Drupal - How do I limit the number of nodes posted by a user to an entity referenced node?

I don't think there is a module for that ("yet", may be). However, this can be done easily with a form alter hook and validation.

<?php 
function MYMODULE_form_node_form_alter(&$form, &$form_state) {
  if ($form['#node']->type == 'article') {
    $validate = TRUE;
  }
  // You can also use field existence like following:
  if (isset($form['field_name_that_you_want_to_validate'])) {
    $validate = TRUE;
  }

  if (!empty($validate = TRUE;)) {
    $form['#validate'][] = 'MYMODULE_node_validate_only_one_review';
    form_load_include($form_state, 'inc', 'MYMODULE', 'FILE_THAT_CONTAINS_THE_VALIDATE_FUNCTION');
  }
}
?>

Then, define the validate function:

<?php 
function MYMODULE_node_validate_only_one_review($form, &$form_state) {
  if (!empty($form_state['field_name_that_you_want_to_validate'])) {
    $nids = array();
    foreach ($form_state['field_name_that_you_want_to_validate'] as $language => $items) {
      foreach ($items as $delta => $item) {
        if (!empty($item['target_id'])) {
          $nids[$item['target_id']] = array($language, $delta);
        }
      }
    }
    if (!empty($nids)) {
      $query = new EntityFieldQuery();
      $query->entityCondition('entity_type', 'node')
        ->entityCondition('bundle', 'article')
        ->propertyCondition('uid', $GLOBALS['user']->uid)
        ->fieldCondition('field_name_that_you_want_to_validate', 'target_id', $nids);

      $matches = $query->execute();
      if (isset($matches['node'])) {
        foreach ($nids as $nid => $pack) {
          if (isset($matches['node'][$nid])) {
            list($language, $delta) = $pack;
            form_set_error('field_name_that_you_want_to_validate][' . $language . '][' . $delta, 
              t('You have already submitted a review for this content.');
            );
          }
        }
      }
    }
  }
}
?>

There are 4 assumptions:

  • Node type is article. Change all instances of article with the correct node type machine name.
  • Your field name is field_name_that_you_want_to_validate. Change it accordingly.
  • You are using Entity Reference module for node reference (hence, the target_id key. It would be nid if you use References module)
  • This bounty gave you the hat ;)

There is 1 fact:

  • I submitted this answer for the hat.

There is 1 hope:

  • I will get that hat.

The other answers approach the requirement from a validation standpoint. I think it's better from a user experience standpoint (and I think it makes more sense logically) to tackle it earlier - at presentation. That is, don't present the option to review a book if the user has already reviewed it. Only show books that can be reviewed by the acting user when giving them the list of books to select for reviewed.

Summarized approach:

Upon creation of a Book Review, limit the list of books available for review to those that have not previously been reviewed by the reviewer.

Given this approach, we want to limit the list of books a user can select when creating a review to those that have not previously been reviewed by the reviewer. Entity Reference allows you to use a View to generate the list of reference-able entities. So all you need is a view that displays all Books that haven't been referenced by the current user yet.

More simple (given that we're already excluding entities that aren't books): Show me all books, but exclude books that have been referenced by this user already.

Basic instructions:

  1. Create a new view. It will need a display type of "Entity Reference". But for now, I suggest giving it a Page display so you can test.
  2. Join the referenced and referencing entities: Add a reference to Entity Reference: Referencing entity (note Referencing, not Referenced)
  3. Only return Articles - Under filter criteria, create a filter for Content Type = Article
  4. Filter based on user - Under Contextual Filters, create a Contextual Filter for Content: Author uid:
    1. When the filter value is not in the URL: Provide default value = User ID from logged in user
    2. Negate the expression - Under "More", select "Exclude" (Exclude essentially negates the filter [and might be inappropriately misnamed as such] - we want to return all referenced nodes that weren't created by the current user).
  5. Verify, add view display, and profit - At this point you should be able to visit the URL of the view you created as different users. There you can verify that the only Book nodes that are displayed are those that have not been reviewed by the current user (or those not reviewed at all). Once you've tested and verified it's working, add a display to the view of type "Entity Reference". Then back in your Review content type, set the Entity Reference field's Mode to "Views" and select the view you just created.

Tags:

Nodes

Users