You are here

function term_merge_duplicates_form in Term Merge 7

Generate 'term_merge_duplicates_form'.

Allow merging terms with the same or similar names.

Parameters

object $vocabulary: Fully loaded taxonomy vocabulary object inside of which term merging occurs, if this argument is omitted, then $parent_term is required and will be used to obtain information about Taxonomy vocabulary

object $parent_term: Fully loaded taxonomy term object using which the function will pull up the vocabulary inside of which term merging occurs. Duplicate terms will be sought only among children of this term

1 string reference to 'term_merge_duplicates_form'
term_merge_menu in ./term_merge.module
Implements hook_menu().

File

./term_merge.pages.inc, line 303
Menu page callbacks for Term Merge module.

Code

function term_merge_duplicates_form($form, &$form_state, $vocabulary = NULL, $parent_term = NULL) {
  $form['#attached']['js'][drupal_get_path('module', 'term_merge') . '/js/duplicate.form.js'] = array();

  // Checking if we were not given vocabulary object, we will use term object to
  // obtain the former.
  if (!is_null($parent_term) && is_null($vocabulary)) {
    $vocabulary = taxonomy_vocabulary_load($parent_term->vid);
  }
  $tree = taxonomy_get_tree($vocabulary->vid, is_null($parent_term) ? 0 : $parent_term->tid);

  // Helpful and self explaining text that should help people understand what's
  // up.
  $form['help'] = array(
    '#markup' => '<p>' . t('Here you can merge terms with the same names. It is a useful tool against term-duplicates. If this tool is invoked on a term (not on the entire vocabulary), duplicate terms will be sought only among children of that term. The terms are grouped by names. Term into which the merging will occur is selected manually by user, however you must know that it is impossible to merge a parent term into any of its children.') . '</p>',
  );
  $form['settings'] = array(
    '#type' => 'fieldset',
    '#title' => t('Advanced settings'),
    '#description' => t('Fine tune the duplicate search tool. You can adjust these settings if your vocabulary is very large. Also, you can control within these settings how the potential duplicates are presented below.'),
    '#tree' => TRUE,
    '#collapsible' => TRUE,
  );
  $form['settings']['help'] = array(
    '#markup' => '<p>' . format_plural(count($tree), 'Vocabulary %vocabulary has only 1 term. It is very unlikely you will merge anything here.', 'Vocabulary %vocabulary has @count terms. If this tool works slow, you may instruct the duplicate finder tool to terminate its work after it has found a specific number of possible duplicates.', array(
      '%vocabulary' => $vocabulary->name,
    )) . '</p>',
  );
  $form['settings']['max_duplicates'] = array(
    '#type' => 'textfield',
    '#title' => t('Show N duplicates'),
    '#description' => t('Input an integer here - this many duplicates will be shown on the form. Once this amount of possible duplicates is found, the search process terminates.'),
    '#required' => TRUE,
    '#default_value' => isset($form_state['values']['settings']['max_duplicates']) ? $form_state['values']['settings']['max_duplicates'] : 300,
    '#element_validate' => array(
      'element_validate_integer_positive',
    ),
  );
  $options = array();
  foreach (term_merge_duplicate_suggestion() as $plugin) {
    $options[$plugin['name']] = $plugin['title'];
  }
  $form['settings']['duplicate_suggestion'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Mark terms as duplicate if all the checked conditions stand true'),
    '#options' => $options,
    '#default_value' => isset($form_state['values']['settings']['duplicate_suggestion']) ? $form_state['values']['settings']['duplicate_suggestion'] : array(
      'name',
    ),
  );
  $options = array();
  $bundle = field_extract_bundle('taxonomy_term', $vocabulary);
  foreach (field_info_instances('taxonomy_term', $bundle) as $instance) {
    $options[$instance['field_name']] = $instance['label'];
  }
  if (!empty($options)) {
    $form['settings']['fields'] = array(
      '#type' => 'checkboxes',
      '#title' => t('Display fields'),
      '#description' => t('Check which fields you wish to display in the results below for each possible duplicate term.'),
      '#options' => $options,
      '#default_value' => isset($form_state['values']['settings']['fields']) ? array_values(array_filter($form_state['values']['settings']['fields'])) : array(),
    );
  }
  $form['settings']['update'] = array(
    '#type' => 'button',
    '#value' => t('Re-run duplicate search'),
    '#ajax' => array(
      'callback' => 'term_merge_duplicates_form_settings',
      'wrapper' => 'term-merge-duplicate-wrapper',
      'method' => 'replace',
      'effect' => 'fade',
    ),
  );

  // Amount of found duplicates.
  $count = 0;

  // Array of groups of terms with the same name. Each group is an array of
  // duplicates. Trunk term of each group will be chosen by user.
  $groups = array();
  foreach ($tree as $term) {
    if ($count >= $form['settings']['max_duplicates']['#default_value']) {

      // We have reached the limit of possible duplicates to be found.
      break;
    }
    $hash = '';
    foreach ($form['settings']['duplicate_suggestion']['#default_value'] as $duplicate_suggestion) {
      $duplicate_suggestion = term_merge_duplicate_suggestion($duplicate_suggestion);
      $function = ctools_plugin_get_function($duplicate_suggestion, 'hash callback');
      if ($function) {
        $hash .= $function($term);
      }
    }
    if (!isset($groups[$hash])) {
      $groups[$hash] = array();
    }
    else {

      // We increment count by one for the just encountered duplicate. Plus, if
      // it is the second duplicate in this group, we also increment it by one
      // for the 1st duplicate in the group.
      $count++;
      if (count($groups[$hash]) == 1) {
        $count++;
      }
    }
    $groups[$hash][$term->tid] = $term;
  }
  $form['wrapper'] = array(
    '#prefix' => '<div id="term-merge-duplicate-wrapper">',
    '#suffix' => '</div>',
  );
  if ($count > 0) {
    $form['wrapper']['global_switch'] = array(
      '#type' => 'checkbox',
      '#title' => t('Select All Terms'),
      '#description' => t('Checking here will select for merging all the encountered duplicate terms.'),
      '#attributes' => array(
        'class' => array(
          'term-merge-duplicate-general-switch',
        ),
      ),
    );
  }
  $form['wrapper']['group'] = array(
    '#tree' => TRUE,
  );
  $groups = array_filter($groups, 'term_merge_duplicates_form_filter');
  $tids = array();
  foreach ($groups as $group) {
    $tids = array_merge($tids, array_keys($group));
  }

  // This array will be keyed by term tid and values will be counts of how many
  // other entities reference to this term through values of fields attached to
  // them.
  $terms_count = array_fill_keys($tids, 0);
  if (!empty($tids)) {
    foreach (term_merge_fields_with_foreign_key('taxonomy_term_data', 'tid') as $referencing_field) {
      if ($referencing_field['storage']['type'] == 'field_sql_storage') {
        $table = array_keys($referencing_field['storage']['details']['sql'][FIELD_LOAD_CURRENT]);
        $table = reset($table);
        $column = $referencing_field['storage']['details']['sql'][FIELD_LOAD_CURRENT][$table][$referencing_field['term_merge_field_column']];
        $select = db_select($table, 'reference')
          ->condition($column, $tids);
        $select
          ->addField('reference', $column, 'tid');
        $select
          ->addExpression('COUNT(1)', 'count');
        $select
          ->groupBy($column);
        $select = $select
          ->execute();
        foreach ($select as $row) {
          $terms_count[$row->tid] += $row->count;
        }
      }
    }
  }
  if (!empty($form['settings']['fields']['#default_value'])) {

    // We need to load full term entities, because we are requested to show
    // fields.
    $terms = taxonomy_term_load_multiple($tids);
    foreach ($groups as $i => $group) {
      $groups[$i] = array_intersect_key($terms, $group);
    }
  }
  foreach ($groups as $i => $group) {

    // Sorting terms by tid for better usage experience.
    ksort($group);
    $first_term = reset($group);
    $options = array();
    foreach ($group as $term) {
      $parents = array();

      // Adding Root to the hierarchy.
      $parents[] = t('Vocabulary Root');
      foreach (taxonomy_get_parents_all($term->tid) as $parent) {

        // We do not include the current term in the hierarchy.
        if ($parent->tid != $term->tid) {
          $parents[] = $parent->name;
        }
      }
      $language = isset($term->language) ? $term->language : LANGUAGE_NONE;
      if ($language == LANGUAGE_NONE) {
        $language = t('Not Specified');
      }
      $options[$term->tid] = array(
        'id' => $term->tid,
        'title' => l($term->name, 'taxonomy/term/' . $term->tid),
        'language' => $language,
        'description' => check_markup($term->description, $term->format),
        'parents' => implode(' &raquo; ', $parents),
        'count' => format_plural($terms_count[$term->tid], '@count time', '@count times'),
      );
      if (isset($form['settings']['fields'])) {
        foreach ($form['settings']['fields']['#default_value'] as $instance) {
          $field = field_info_field($instance);
          $items = field_get_items('taxonomy_term', $term, $field['field_name']);
          $options[$term->tid][$field['field_name']] = '';
          if (is_array($items)) {
            $options[$term->tid][$field['field_name']] = array(
              '#theme' => 'item_list',
              '#items' => array(),
            );
            foreach ($items as $item) {
              switch ($field['type']) {
                case 'image':
                  $display = array();
                  $image_style = image_style_load('thumbnail');
                  if ($image_style) {
                    $cache = _field_info_field_cache();
                    $display = $cache
                      ->prepareInstanceDisplay($display, $field['type']);
                    $display['settings']['image_style'] = $image_style['name'];
                  }
                  $rendered_item = drupal_render(field_view_value('taxonomy_term', $term, $field['field_name'], $item, $display));
                  break;
                default:
                  $rendered_item = drupal_render(field_view_value('taxonomy_term', $term, $field['field_name'], $item));
                  break;
              }
              $options[$term->tid][$field['field_name']]['#items'][] = $rendered_item;
            }
            if (count($options[$term->tid][$field['field_name']]['#items']) > 1) {
              $options[$term->tid][$field['field_name']] = drupal_render($options[$term->tid][$field['field_name']]);
            }
            else {
              $options[$term->tid][$field['field_name']] = $options[$term->tid][$field['field_name']]['#items'][0];
            }
          }
        }
      }
    }
    $form['wrapper']['group'][$i] = array(
      '#type' => 'fieldset',
      '#title' => check_plain($first_term->name),
      '#collapsible' => TRUE,
      '#pre_render' => array(
        'term_merge_duplicates_fieldset_preprocess',
      ),
      '#element_validate' => array(
        'term_merge_duplicates_fieldset_validate',
      ),
    );
    $header = array(
      'id' => t('ID'),
      'title' => t('Title'),
      'description' => t('Description'),
      'language' => t('Language'),
      'parents' => t('Parents'),
      'count' => t('Referenced'),
    );
    if (isset($form['settings']['fields'])) {
      $header += array_map('check_plain', array_intersect_key($form['settings']['fields']['#options'], drupal_map_assoc($form['settings']['fields']['#default_value'])));
    }
    $form['wrapper']['group'][$i]['duplicates'] = array(
      '#type' => 'tableselect',
      '#title' => 'Duplicates',
      '#header' => $header,
      '#options' => $options,
    );
    $options = array();
    foreach ($group as $term) {
      $options[$term->tid] = $term->name;
    }
    $form['wrapper']['group'][$i]['trunk_tid'] = array(
      '#type' => 'radios',
      '#title' => t('Merge Into'),
      '#options' => $options,
      '#attributes' => array(
        'class' => array(
          'term-merge-duplicate-trunk',
        ),
      ),
    );
  }
  if ($count > 0) {

    // Adding necessary options of merging.
    $form += term_merge_merge_options_elements($vocabulary);
    $form['actions'] = array(
      '#type' => 'actions',
    );
    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Submit'),
    );
  }
  else {
    if (is_null($parent_term)) {
      $no_match_text = t('Sorry, seems like we were not able to find any possible duplicate terms in %vocabulary vocabulary.', array(
        '%vocabulary' => $vocabulary->name,
      ));
    }
    else {
      $no_match_text = t('Sorry, seems like we were not able to find any possible duplicate terms among children of %term term. You may want to search for duplicates through the entire <a href="!url">vocabulary</a>.', array(
        '%term' => $parent_term->name,
        '!url' => url('admin/structure/taxonomy/' . $vocabulary->machine_name . '/merge/duplicates'),
      ));
    }
    $form['nothing_found'] = array(
      '#markup' => '<p><b>' . $no_match_text . '</b></p>',
    );
  }
  return $form;
}