You are here

data_taxonomy.module in Data 6

Hooks and API functions for Data Node module.

File

data_taxonomy/data_taxonomy.module
View source
<?php

/**
 * @file
 * Hooks and API functions for Data Node module.
 */

/**
 * Implementation of hook_views_api().
 */
function data_taxonomy_views_api() {
  return array(
    'api' => '2.0',
    'path' => drupal_get_path('module', 'data_taxonomy') . '/views',
  );
}

/**
 * Implementation of hook_menu().
 */
function data_taxonomy_menu() {
  $items = array();
  $items['data-taxonomy/ajax-save'] = array(
    'page callback' => 'data_taxonomy_ajax_save',
    'page arguments' => array(),
    'access arguments' => array(
      'edit data taxonomy relations',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/build/data/edit/%data_ui_table/taxonomy'] = array(
    'title' => 'Relate to taxonomy',
    'description' => 'Administer data tables.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'data_taxonomy_settings_form',
      4,
    ),
    'file' => 'data_taxonomy.admin.inc',
    'access arguments' => array(
      'administer data tables',
    ),
    'type' => MENU_LOCAL_TASK,
  );
  return $items;
}

/**
 * Implementation of hook_theme().
 */
function data_taxonomy_theme() {
  return array(
    'data_taxonomy_tagging_form' => array(
      'arguments' => array(
        'form' => array(),
      ),
      'path' => drupal_get_path('module', 'data_taxonomy') . '/theme',
      'template' => 'data-taxonomy-tagging-form',
    ),
  );
}

/**
 * Implementation of hook_perm().
 */
function data_taxonomy_perm() {
  return array(
    'edit data taxonomy relations',
  );
}

/**
 * Implementation of hook_feeds_data_processor_targets_alter().
 */
function data_taxonomy_feeds_data_processor_targets_alter(&$fields, $table_name) {
  if ($info = data_taxonomy_get_info($table_name)) {
    foreach ($info['vocabularies'] as $vid) {
      $vocabulary = data_taxonomy_get_vocabulary($vid);
      $fields['data_taxonomy:' . $vid] = array(
        'name' => t('Taxonomy: @vocabulary', array(
          "@vocabulary" => $vocabulary->name,
        )),
        'description' => t('Map to taxonomy terms of @vocabulary vocabulary.', array(
          "@vocabulary" => $vocabulary->name,
        )),
      );
    }
  }
}

/**
 * Implementation of hook_data_insert().
 */
function data_taxonomy_data_insert($record, $table_name) {
  if ($info = data_taxonomy_get_info($table_name)) {
    $id = $record[$info['id']];
    foreach ($info['vocabularies'] as $vid) {
      if (isset($record['data_taxonomy:' . $vid])) {
        _data_taxonomy_save_terms($table_name, $id, $record['data_taxonomy:' . $vid], data_taxonomy_get_vocabulary($vid));
      }
    }
  }
}

/**
 * Implementation of hook_data_update().
 */
function data_taxonomy_data_update($record, $table_name) {
  if ($info = data_taxonomy_get_info($table_name)) {
    $id = $record[$info['id']];
    foreach ($info['vocabularies'] as $vid) {
      if (isset($record['data_taxonomy:' . $vid])) {
        $vocabulary = data_taxonomy_get_vocabulary($vid);
        _data_taxonomy_save_terms($table_name, $id, $record['data_taxonomy:' . $vid], $vocabulary);
      }
    }
  }
}

/**
 * Implementation of hook_taxonomy().
 */
function data_taxonomy_taxonomy($op = NULL, $type = NULL, $term = NULL) {
  if ($type == 'term' && $term['tid'] && $op == 'delete') {
    db_query("DELETE FROM {data_taxonomy} WHERE tid = %d", $term['tid']);
  }
}

/**
 * Helper function, saves a series of taxonomy terms for a record.
 *
 * Creates new taxonomy terms on the fly for vocabularies that are tags.
 *
 * @param $table_name
 *   Table name of the record.
 * @param $id
 *   Record identifier.
 * @param $terms
 *   An array of terms. Can be an array of tids, term names, term arrays or
 *   objects that can be casted into a term array. If the target vocabulary is
 *   a tag vocabulary, non-existing terms will be created on the fly.
 * @param $vocabulary
 *   A vocuabulary object.
 */
function _data_taxonomy_save_terms($table_name, $id, $terms, $vocabulary) {
  if (!is_array($terms)) {
    $terms = array(
      $terms,
    );
  }
  $tids = array();
  foreach ($terms as $term) {
    if (is_string($term)) {
      $term = data_taxonomy_sanitize($term, $vocabulary->vid);
      $term = data_taxonomy_save_term_name($term, $vocabulary->vid, $vocabulary->tags);
    }
    else {
      if (is_object($term)) {
        $term = (array) $term;
      }
      if (is_array($term)) {
        $term['name'] = data_taxonomy_sanitize($term['name'], $vocabulary->vid);
        $term = data_taxonomy_save_term_array($term, $vocabulary->vid, $vocabulary->tags);
      }
    }
    if (is_array($term)) {
      $term = isset($term['tid']) ? $term['tid'] : FALSE;
    }
    if (is_numeric($term) && !isset($tids[$term])) {
      $tids[$term] = $term;
    }
  }
  _data_taxonomy_save_relations($vocabulary->vid, $id, $table_name, $tids);
}

/**
 * Implementation of hook_data_delete_query_alter().
 */
function data_taxonomy_data_delete_query_alter($query, $table_name) {
  if ($info = data_taxonomy_get_info($table_name)) {
    $table_name = db_escape_table($table_name);
    $query
      ->addSubject('data_taxonomy');
    $query
      ->addJoin('data_taxonomy', "{$table_name}.{$info['id']} = data_taxonomy.id AND data_taxonomy.data_table_name = '{$table_name}'", 'LEFT JOIN');
  }
}

/**
 * Get data_taxonomy information for a given data table.
 */
function data_taxonomy_get_info($table_name) {
  static $info = array();
  if (!isset($info[$table_name])) {
    $info[$table_name] = FALSE;
    $meta = data_get_table($table_name)
      ->get('meta');
    if (is_array($meta['data_taxonomy'])) {
      $info[$table_name] = $meta['data_taxonomy'];
    }
  }
  return $info[$table_name];
}

/**
 * Form callback for tagging.
 */
function data_taxonomy_tagging_form(&$form_state, $vid, $id, $table_name, $path, $args) {
  $access = user_access('edit data taxonomy relations');
  $form = array(
    '#theme' => 'data_taxonomy_tagging_form',
  );
  $form['vid'] = array(
    '#type' => 'hidden',
    '#value' => $vid,
    '#access' => $access,
  );
  $form['id'] = array(
    '#type' => 'hidden',
    '#value' => $id,
    '#access' => $access,
  );
  $form['table_name'] = array(
    '#type' => 'hidden',
    '#value' => $table_name,
    '#access' => $access,
  );
  $form['path'] = array(
    '#type' => 'hidden',
    '#value' => $path,
    '#access' => $access,
  );
  $form['args'] = array(
    '#type' => 'hidden',
    '#value' => implode('&', $args),
    '#access' => $access,
  );
  $result = db_query('SELECT td.tid, td.name, td.vid FROM {term_data} td JOIN {data_taxonomy} dt ON td.tid = dt.tid WHERE dt.data_table_name = "%s" AND dt.id = %d AND td.vid = %d', $table_name, $id, $vid);
  $tags = $terms = array();
  while ($term = db_fetch_object($result)) {
    $tags[$term->tid] = $term->name;
    $terms[$term->tid] = $term;
  }
  $form['tags'] = array(
    '#type' => 'textfield',
    '#default_value' => implode(', ', $tags),
    '#autocomplete_path' => 'taxonomy/autocomplete/' . $vid,
    '#id' => "edit-tags-data-taxonomy-{$vid}-{$id}",
    '#access' => $access,
  );

  // Ensure our path gets rewritten. We don't use url() here because we're
  // not interested in rewrites to parts of the request other than $_GET['q'].
  $ajax_path = 'data-taxonomy/ajax-save';
  if (function_exists('custom_url_rewrite_outbound')) {
    $original_path = $ajax_path;
    $options = array();
    custom_url_rewrite_outbound($ajax_path, $options, $original_path);
  }
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
    '#access' => $access,
    // AHAH stack: We need to assign our submit button its own ID as auto
    // assignment will quickly lead to a situation where our AJAX form button
    // has a different ID from the original.
    '#id' => "edit-submit-data-taxonomy-{$vid}-{$id}",
    '#ahah' => array(
      'path' => $ajax_path,
      'wrapper' => "data-taxonomy-tags-{$vid}-{$id}",
      'method' => 'replace',
      'effect' => 'none',
    ),
  );

  // Pass on key elements for theming.
  $form['#terms'] = $terms;
  $form['#path'] = $path;
  $form['#args'] = $args;
  if ($access) {
    $form['#edit'] = l(t('Edit'), $_GET['q'], array(
      'fragment' => 'data-taxonomy-edit',
      'attributes' => array(
        'class' => 'data-taxonomy-edit',
      ),
    ));
  }
  $form['#vocab'] = taxonomy_vocabulary_load($vid);
  return $form;
}

/**
 * Submit handler.
 */
function data_taxonomy_tagging_form_submit($form, &$form_state) {

  // Using clicked_button allows us to use more than one of the same form on
  // a screen.
  $post = $form_state['clicked_button']['#post'];
  $tids = data_taxonomy_save_tags($form_state['values']['tags'], $post['vid']);
  _data_taxonomy_save_relations($post['vid'], $post['id'], $post['table_name'], $tids);
}

/**
 * Save term_data - data table relationships in data_taxonomy table.
 */
function _data_taxonomy_save_relations($vid, $id, $table_name, $tids) {
  db_query("DELETE dt FROM {data_taxonomy} dt JOIN {term_data} td ON dt.tid = td.tid WHERE dt.id = %d AND dt.data_table_name = '%s' AND td.vid = %d", $id, $table_name, $vid);
  foreach ($tids as $tid) {
    db_query('INSERT INTO {data_taxonomy} (id, data_table_name, tid) VALUES (%d, "%s", %d)', $id, $table_name, $tid);
  }
}

/**
 * Save a term, create a new one if it does not exist yet.
 *
 * @param $name
 *   A taxonomy term name to look up and save.
 * @param $vid
 *   A <em>numeric</em> vocabulary id (vid).
 *
 * @return
 *   A taxonomy term array.
 */
function data_taxonomy_save_term_name($name, $vid) {
  if ($term = data_taxonomy_lookup_term($name, $vid)) {
    return $term;
  }
  $term = array(
    'vid' => $vid,
    'name' => $name,
  );
  taxonomy_save_term($term);
  return $term;
}

/**
 * Save a term array, create a new one if it does not exist yet.
 *
 * @param $term
 *   A taxonomy term array to look up and save.
 * @param $vid
 *   A <em>numeric</em> vocabulary id (vid).
 *
 * @return
 *   A taxonomy term array.
 */
function data_taxonomy_save_term_array($term, $vid) {
  if (!isset($term[$vid])) {
    $term['vid'] = $vid;
  }
  if (!isset($term['tid']) || $term['vid'] != $vid) {
    if ($lookup = data_taxonomy_lookup_term($term['name'], $vid)) {
      $term = $term + $lookup;
    }
  }
  taxonomy_save_term($term);
  return $term;
}

/**
 * Sanitize a term name depending on its vocabulary settings.
 */
function data_taxonomy_sanitize($name, $vid) {
  $vocabulary = taxonomy_vocabulary_load($vid);
  if ($vocabulary->tags) {

    // Make sure there aren't any terms with a comma (=tag delimiter) in it.
    return preg_replace('/\\s*,\\s*/', ' ', $name);
  }
  return $name;
}

/**
 * Look up a term by name and vid.
 *
 * @param $name
 *   Term name.
 * @param $vid
 *   A <em>numeric</em> vocabulary id (vid).
 *
 * @return
 *   A taxonomy term array if there is a term for $name/$vid, NULL otherwise.
 */
function data_taxonomy_lookup_term($name, $vid) {
  static $terms;
  if (!isset($terms[$vid][$name])) {
    foreach (data_taxonomy_get_term_by_name_vid($name, $vid) as $term) {
      if ($term->vid == $vid) {
        $terms[$vid][$name] = (array) $term;
      }
    }
  }
  return isset($terms[$vid][$name]) ? $terms[$vid][$name] : NULL;
}

/**
 * Look up a term by name and vocabulary id.
 *
 * @see taxonomy_get_term_by_name().
 */
function data_taxonomy_get_term_by_name_vid($name, $vid) {
  $db_result = db_query(db_rewrite_sql("SELECT t.tid, t.* FROM {term_data} t WHERE t.vid = %d AND LOWER(t.name) = LOWER('%s')", 't', 'tid'), $vid, trim($name));
  $result = array();
  while ($term = db_fetch_object($db_result)) {
    $result[] = $term;
  }
  return $result;
}

/**
 * Explode terms from typed input, create new terms.
 *
 * @param $typed_input
 *   A comma separated list of terms.
 * @param $vid
 *   A <em>numeric</em> vocabulary id (vid).
 *
 * @todo: This should actually live in taxonomy module.
 *
 * @return
 *   Array of tids corresponding to the terms in typed_input.
 */
function data_taxonomy_save_tags($typed_input, $vid) {
  $tids = array();
  foreach (drupal_explode_tags($typed_input) as $typed_term) {
    $term = data_taxonomy_save_term_name($typed_term, $vid);

    // Cast the edit as an object as though it were retrieved from the DB.
    $tids[$term['tid']] = (object) $term;
  }
  return $tids;
}

/**
 * AHAH callback for saving terms.
 *
 * @todo: Verify form token.
 */
function data_taxonomy_ajax_save() {
  $cached_form_state = array();
  $files = array();
  $cached_form = form_get_cache($_POST['form_build_id'], $cached_form_state);
  if ($cached_form['form_token']['#default_value'] == $_POST['form_token']) {

    // Rebuild $form_state['values'].
    $form_state = array(
      'values' => $_POST,
    );
    foreach (element_children($cached_form) as $elem) {
      if ($cached_form[$elem]['#type'] === 'value' && isset($cached_form[$elem]['#value'])) {
        $form_state['values'][$elem] = $cached_form[$elem]['#value'];
      }
    }

    // Process and save terms & relations.
    $values = $form_state['values'];
    $terms = data_taxonomy_save_tags($values['tags'], $values['vid']);
    _data_taxonomy_save_relations($values['vid'], $values['id'], $values['table_name'], array_keys($terms));
    drupal_json(array(
      'status' => 1,
      'data' => theme('links', data_taxonomy_tag_links($terms, $_POST['path'], explode('&', $_POST['args'])), array(
        'class' => 'links data-taxonomy-tags',
      )),
    ));
    exit;
  }
  drupal_json(array(
    'status' => 1,
    'data' => 'Error submitting form',
  ));
  exit;
}

/**
 * Generate a links array suitable for use with theme('links') from an array of
 * taxonomy terms.
 *
 * @param $terms
 *   An array of terms.
 * @param $path
 *   The path template to use (e. g. path/%/!tid/%)
 * @param $args
 *   The arguments to use in the path template, used to replace %'s in $path.
 */
function data_taxonomy_tag_links($terms, $path, $args) {
  $tags = array();
  $path = _data_taxonomy_replace_tokens($path, $args);
  foreach ($terms as $tid => $term) {
    $tags[] = array(
      'title' => $term->name,
      'href' => str_replace('!term', $term->name, str_replace('!tid', $term->tid, $path)),
    );
  }
  return $tags;
}

/**
 * Replaces % in $path with arguments.
 *
 * @todo: Replace missing % not with 'all' but with value depending on argument
 * setting.
 *
 * @param $path
 *   A path template like path/%/!tid/%
 * @param $args
 *   An array of arguments used to replace % characters in path.
 * @return
 *   A path with replaced tokens like path/arg1/!tid/arg2
 */
function _data_taxonomy_replace_tokens($path, $args) {
  if (is_array($args)) {
    $args = array_filter($args);
    $pos = strpos($path, '%');
    while ($pos !== FALSE && count($args)) {
      $path = substr_replace($path, array_shift($args), $pos, 1);
      $pos = strpos($path, '%');
    }
  }
  $path = str_replace('%', 'all', $path);
  return $path;
}

/**
 * Preprocessor for theme('data_taxonomy_tagging_form').
 */
function template_preprocess_data_taxonomy_tagging_form(&$vars) {
  drupal_add_js(drupal_get_path('module', 'data_taxonomy') . '/theme/data_taxonomy.js');
  drupal_add_css(drupal_get_path('module', 'data_taxonomy') . '/theme/data_taxonomy.css');
  $vars['label'] = $vars['form']['#vocab']->name;
  if ($vars['form']['#edit']) {
    $vars['edit'] = $vars['form']['#edit'];
  }
  $vars['tags'] = theme('links', data_taxonomy_tag_links($vars['form']['#terms'], $vars['form']['#path'], $vars['form']['#args']), array(
    'class' => 'links data-taxonomy-tags',
  ));
}

/**
 * Get a vocabulary by vid or module name.
 *
 * @param $id
 *   A module name or a numeric vocabulary id.
 *
 * @return
 *   An object of type stdClass that represents a vocabulary.
 */
function data_taxonomy_get_vocabulary($id) {
  static $vocabularies;
  if (!isset($vocabularies[$id])) {
    foreach (taxonomy_get_vocabularies() as $vocabulary) {
      if ($vocabulary->vid == $id) {
        $vocabularies[$id] = $vocabulary;
        break;
      }
      elseif ($vocabulary->module == $id) {
        $vocabularies[$id] = $vocabulary;
        break;
      }
    }
  }
  return $vocabularies[$id];
}

/**
 * Return the vocabulary identifier, the vocabulary's vid or module.
 *
 * @return
 *   Vocabulary's module name if it is a features vocabulary (= exportable),
 *   vocabulary's vid otherwise.
 */
function data_taxonomy_vocabulary_id($vocabulary) {
  if (strpos($vocabulary->module, 'features_') === 0) {
    return $vocabulary->module;
  }
  return $vocabulary->vid;
}

Functions

Namesort descending Description
data_taxonomy_ajax_save AHAH callback for saving terms.
data_taxonomy_data_delete_query_alter Implementation of hook_data_delete_query_alter().
data_taxonomy_data_insert Implementation of hook_data_insert().
data_taxonomy_data_update Implementation of hook_data_update().
data_taxonomy_feeds_data_processor_targets_alter Implementation of hook_feeds_data_processor_targets_alter().
data_taxonomy_get_info Get data_taxonomy information for a given data table.
data_taxonomy_get_term_by_name_vid Look up a term by name and vocabulary id.
data_taxonomy_get_vocabulary Get a vocabulary by vid or module name.
data_taxonomy_lookup_term Look up a term by name and vid.
data_taxonomy_menu Implementation of hook_menu().
data_taxonomy_perm Implementation of hook_perm().
data_taxonomy_sanitize Sanitize a term name depending on its vocabulary settings.
data_taxonomy_save_tags Explode terms from typed input, create new terms.
data_taxonomy_save_term_array Save a term array, create a new one if it does not exist yet.
data_taxonomy_save_term_name Save a term, create a new one if it does not exist yet.
data_taxonomy_tagging_form Form callback for tagging.
data_taxonomy_tagging_form_submit Submit handler.
data_taxonomy_tag_links Generate a links array suitable for use with theme('links') from an array of taxonomy terms.
data_taxonomy_taxonomy Implementation of hook_taxonomy().
data_taxonomy_theme Implementation of hook_theme().
data_taxonomy_views_api Implementation of hook_views_api().
data_taxonomy_vocabulary_id Return the vocabulary identifier, the vocabulary's vid or module.
template_preprocess_data_taxonomy_tagging_form Preprocessor for theme('data_taxonomy_tagging_form').
_data_taxonomy_replace_tokens Replaces % in $path with arguments.
_data_taxonomy_save_relations Save term_data - data table relationships in data_taxonomy table.
_data_taxonomy_save_terms Helper function, saves a series of taxonomy terms for a record.