You are here

function unique_field_nodeapi in Unique field 6

Same name and namespace in other branches
  1. 5 unique_field.module \unique_field_nodeapi()

Implementation of hook_nodeapi().

File

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

Code

function unique_field_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {

  // check fields for unique requirements on node 'validate' operation
  if ($op === 'validate') {

    // 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($a3) && isset($a3['unique_field_override']) && is_array($a3['unique_field_override']) && $a3['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 {

            // if content_permissions is enabled and the current user is
            // not permitted to access a field, then the field data is cleared
            if (!is_array($node->{$field})) {
              continue;
            }
            $f = $node->{$field};
            $field_info = content_fields($field, $node->type);
            $field_keys = array_keys($field_info['columns']);
            foreach ($f as $index => $value) {
              if (is_numeric($index)) {
                $field_combined = array();
                foreach ($field_keys as $key) {
                  if (!empty($f[$index][$key])) {
                    $field_combined[$key] = $f[$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;
          }
          elseif (strpos($field, UNIQUE_FIELD_FIELDS_TAXONOMY) === 0) {
            $vid = intval(substr($field, strlen(UNIQUE_FIELD_FIELDS_TAXONOMY)));
            if (!$vid || !module_exists('taxonomy') || !is_array($node->taxonomy)) {
              continue;
            }
            $values = array();
            if (is_array($node->taxonomy['tags']) && isset($node->taxonomy['tags'][$vid])) {
              $tags = drupal_explode_tags($node->taxonomy['tags'][$vid]);
              foreach ($tags as $tag) {
                $tid = db_result(db_query("SELECT tid FROM {term_data} WHERE vid = %d AND LOWER(name) = LOWER('%s')", $vid, trim($tag)));
                if (intval($tid)) {
                  $values[] = intval($tid);
                }
              }
            }
            elseif (is_array($node->taxonomy[$vid])) {
              foreach ($node->taxonomy[$vid] as $tid) {
                if (intval($tid)) {
                  $values[] = intval($tid);
                }
              }
            }
            elseif (intval($node->taxonomy[$vid])) {
              $values[] = intval($node->taxonomy[$vid]);
            }
          }
          else {

            // if content_permissions is enabled and the current user is
            // not permitted to access a field, then the field data is cleared
            if (!is_array($node->{$field})) {
              continue;
            }
            $f = $node->{$field};
            $values = array();
            foreach ($f as $index => $value) {
              if (is_numeric($index) && is_array($value)) {
                $values[] = $value;
              }
            }
          }
          $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();
        $formnames = array();
        foreach ($errfld as $key => $field) {
          if ($field === UNIQUE_FIELD_FIELDS_TITLE) {
            $nodetype = node_get_types('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');
          }
          elseif (strpos($field, UNIQUE_FIELD_FIELDS_TAXONOMY) === 0) {
            $vid = intval(substr($field, strlen(UNIQUE_FIELD_FIELDS_TAXONOMY)));
            if ($vid && function_exists('taxonomy_get_vocabularies')) {
              $vocabs = taxonomy_get_vocabularies($node->type);
              if (is_array($vocabs) && $vocabs[$vid]) {
                $formnames[$field] = is_array($node->taxonomy['tags']) && isset($node->taxonomy['tags'][$vid]) ? 'taxonomy][tags][' . $vid : 'taxonomy][' . $vid;
                $labels[$field] = $vocabs[$vid]->name;
              }
            }
          }
          else {
            $fld = content_fields($field, $node->type);
            $labels[$field] = $fld['widget']['label'];
          }
        }
        foreach ($errfld as $field) {
          $msg = strtr($errmsg, array(
            '@label' => check_plain($labels[$field]),
            '@labels' => check_plain(join(', ', $labels)),
          ));
          if ($show_matches && 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', $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)) {
            $msg .= '<p>' . t('Click !here to bypass this check and resubmit.', array(
              '!here' => "<a href=\"#\" onclick=\"\$('form#node-form input#edit-unique-field-override').val(1);\$('form#node-form').submit();return false;\">" . t('here') . "</a>",
            )) . '</p>';
          }
          $formname = isset($formnames[$field]) ? $formnames[$field] : $field;
          form_set_error($formname, $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;
          }
        }
      }
    }
  }
}