You are here

function unique_field_node_validate in Unique field 7

Implements hook_node_validate().

File

./unique_field.module, line 77
Provides content validation requirement that a node's author, language, taxonomy terms, or other fields are unique.

Code

function unique_field_node_validate($node, $form) {

  // skip validation if deleting a node or if override value is set
  if (!empty($node->op) && !empty($node->delete) && $node->op === $node->delete || is_array($form) && isset($form['unique_field_override']) && is_array($form['unique_field_override']) && $form['unique_field_override']['#value'] && user_access('unique_field_perm_bypass')) {
    return;
  }

  // get list of unique fields for node type
  $fields = variable_get('unique_field_fields_' . $node->type, array());

  // check if there are unique fields for this node type
  if (count($fields)) {

    // get unique field settings for this node type
    $scope = variable_get('unique_field_scope_' . $node->type, UNIQUE_FIELD_SCOPE_TYPE);
    $comp = variable_get('unique_field_comp_' . $node->type, UNIQUE_FIELD_COMP_EACH);
    $var_show_matches = variable_get('unique_field_show_matches_' . $node->type, array());
    $show_matches = is_array($var_show_matches) && in_array(UNIQUE_FIELD_SHOW_MATCHES, $var_show_matches);

    // initialization
    $errmsg = NULL;
    $errfld = array();
    $matches = array();
    $allmatch = NULL;

    // check fields for node scope
    if ($scope === UNIQUE_FIELD_SCOPE_NODE) {
      $values = array();
      foreach ($fields as $field) {
        $new_values = array();
        if ($field === UNIQUE_FIELD_FIELDS_TITLE) {
          $new_values[] = $node->title;
        }
        else {

          // Ensure that the field content exists. For example, if field
          // permissions are enabled, the field may be missing for some users.
          // Make sure to use the field API function, e.g. to respect language.
          $fvalues = field_get_items('node', $node, $field);
          if (empty($fvalues)) {
            continue;
          }
          $field_info = field_info_field($field);
          $field_keys = array_keys($field_info['columns']);
          foreach ($fvalues as $index => $value) {
            if (is_numeric($index)) {
              $field_combined = array();
              foreach ($field_keys as $key) {
                if (isset($fvalues[$index][$key]) && !empty($fvalues[$index][$key])) {
                  $field_combined[$key] = $fvalues[$index][$key];
                }
              }
              if (!empty($field_combined)) {
                $new_values[] = serialize($field_combined);
              }
            }
          }
        }
        $new_values = array_merge($values, $new_values);
        $values = array_unique($new_values);
        if (serialize($values) !== serialize($new_values)) {
          $errfld[] = $field;
        }
      }
      if (count($errfld) > 0) {
        $errmsg = t('The @labels fields must have unique values. The @label field has a value that is already used.');
      }
    }
    else {
      foreach ($fields as $field) {
        $values = '';
        if ($field === UNIQUE_FIELD_FIELDS_TITLE) {
          $values = $node->title;
        }
        elseif ($field === UNIQUE_FIELD_FIELDS_AUTHOR) {
          $values = $node->uid;
        }
        elseif ($field === UNIQUE_FIELD_FIELDS_LANGUAGE) {
          $values = $node->language;
        }
        else {

          // Ensure that the field content exists. For example, if field
          // permissions are enabled, the field may be missing for some users.
          // Make sure to use the field API function, e.g. to respect language.
          $fvalues = field_get_items('node', $node, $field);
          if (empty($fvalues)) {
            continue;
          }
          foreach ($fvalues as $index => $value) {
            if (!is_numeric($index) || !is_array($value)) {
              unset($fvalues[$index]);
            }
          }
          $field_info = field_info_field($field);
          $values = _field_filter_items($field_info, $fvalues);
        }
        if (empty($values)) {
          continue;
        }
        $match = unique_field_match_value($field, $values, $scope, $node->type, $node->language);

        // remove matches of this node
        if ($node->nid && is_array($match) && in_array($node->nid, $match)) {
          $key = array_search($node->nid, $match);
          unset($match[$key]);
        }
        if ($comp === UNIQUE_FIELD_COMP_EACH && is_array($match) && count($match)) {
          $errfld[] = $field;
          $errmsg = t('The @label field requires a unique value, and the specified value is already used.');
        }
        $matches[$field] = $match;
        $allmatch = is_array($allmatch) ? array_intersect($allmatch, $match) : $match;
      }

      // check for fields in combination
      if ($comp === UNIQUE_FIELD_COMP_ALL && is_array($allmatch) && count($allmatch)) {
        foreach ($fields as $field) {
          $errfld[] = $field;
          $matches[$field] = $allmatch;
        }
        $errmsg = t('This form requires that the fields @labels are a unique combination. The specified values are already used.');
      }
    }

    // common error messages
    if ($errmsg && !empty($errmsg) && is_array($errfld) && count($errfld) > 0) {
      $labels = array();
      foreach ($errfld as $field) {
        if ($field === UNIQUE_FIELD_FIELDS_TITLE) {
          $nodetype = node_type_get_type($node->type);
          $labels[$field] = $nodetype->title_label;
        }
        elseif ($field === UNIQUE_FIELD_FIELDS_AUTHOR) {
          $labels[$field] = t('Author');
        }
        elseif ($field === UNIQUE_FIELD_FIELDS_LANGUAGE) {
          $labels[$field] = t('Language');
        }
        else {
          $fld = field_info_instance('node', $field, $node->type);
          $labels[$field] = $fld['label'];
        }
      }
      foreach ($errfld as $field) {
        $msg = strtr($errmsg, array(
          '@label' => check_plain($labels[$field]),
          '@labels' => check_plain(join(', ', $labels)),
        ));
        if ($show_matches && isset($matches[$field]) && is_array($matches[$field]) && count($matches[$field])) {
          $list_items = array();
          foreach ($matches[$field] as $nid) {
            $match_node = node_load($nid);
            if (node_access('view', $match_node)) {
              $list_items[] = l($match_node->title, 'node/' . $nid);
            }
          }
          $list_html = theme('item_list', array(
            'items' => $list_items,
          ));
          $msg .= ' ' . t('Matches are found in the following content: !list-html', array(
            '!list-html' => $list_html,
          ));
        }
        if (user_access('unique_field_perm_bypass')) {
          $form_id = str_replace('_', '-', $form['#id']);
          $msg .= '<p>' . t('Click !here to bypass this check and resubmit.', array(
            '!here' => "<a href=\"#\" onclick=\"jQuery('form#" . $form_id . " input[name=\\'unique_field_override\\']').val(1);jQuery('form#" . $form_id . "').submit();return false;\">" . t('here') . '</a>',
          )) . '</p>';
        }
        form_set_error($field, $msg);

        // if checking the fields in combination, then one error message
        // is enough for all of the fields
        if ($comp === UNIQUE_FIELD_COMP_ALL) {
          break;
        }
      }
    }
  }
}