Newer
Older
/**
* @file
* Enables the organization of content into categories.
*/
* Implement hook_permission().
function taxonomy_permission() {

Dries Buytaert
committed
$permissions = array(

Angie Byron
committed
'administer taxonomy' => array(
'title' => t('Administer taxonomy'),
'description' => t('Manage taxonomy vocabularies and terms.'),
),
);

Dries Buytaert
committed
foreach (taxonomy_get_vocabularies() as $vocabulary) {
$permissions += array(
'edit terms in ' . $vocabulary->vid => array(
'title' => t('Edit terms in %vocabulary', array('%vocabulary' => $vocabulary->name)),
'description' => t('Edit terms in the %vocabulary vocabulary.', array('%vocabulary' => $vocabulary->name)),
),
);
$permissions += array(
'delete terms in ' . $vocabulary->vid => array(
'title' => t('Delete terms in %vocabulary', array('%vocabulary' => $vocabulary->name)),
'description' => t('Delete terms in the %vocabulary vocabulary.', array('%vocabulary' => $vocabulary->name)),
),
);
}
return $permissions;

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Implement hook_entity_info().

Dries Buytaert
committed
*/

Dries Buytaert
committed
function taxonomy_entity_info() {

Dries Buytaert
committed
$return = array(
'taxonomy_term' => array(
'label' => t('Taxonomy term'),

Dries Buytaert
committed
'controller class' => 'TaxonomyTermController',
'base table' => 'taxonomy_term_data',
'fieldable' => TRUE,
'object keys' => array(
'id' => 'tid',
'bundle' => 'vocabulary_machine_name',
),
'bundle keys' => array(
'bundle' => 'machine_name',
),
'bundles' => array(),

Dries Buytaert
committed
),
);

Dries Buytaert
committed
foreach (taxonomy_vocabulary_get_names() as $machine_name => $vocabulary) {
$return['taxonomy_term']['bundles'][$machine_name] = array(
'label' => $vocabulary->name,
'admin' => array(

Dries Buytaert
committed
'path' => 'admin/structure/taxonomy/%taxonomy_vocabulary',
'real path' => 'admin/structure/taxonomy/' . $vocabulary->vid,
'bundle argument' => 3,
'access arguments' => array('administer taxonomy'),
),
);
}

Dries Buytaert
committed
$return['taxonomy_vocabulary'] = array(
'label' => t('Taxonomy vocabulary'),
'controller class' => 'TaxonomyVocabularyController',
'base table' => 'taxonomy_vocabulary',
'object keys' => array(
'id' => 'vid',
),
'fieldable' => FALSE,
);

Dries Buytaert
committed
return $return;
}

Angie Byron
committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/**
* Return nodes attached to a term across all field instances.
*
* This function requires taxonomy module to be maintaining its own tables,
* and will return an empty array if it is not. If using other field storage
* methods alternatives methods for listing terms will need to be used.
*
* @param $term
* The term object.
* @param $pager
* Boolean to indicate whether a pager should be used.
* @order
* An array of fields and directions.
*
* @return
* An array of nids matching the query.
*/
function taxonomy_select_nodes($term, $pager = TRUE, $order = array('t.sticky' => 'DESC', 't.created' => 'DESC')) {
if (!variable_get('taxonomy_maintain_index_table', TRUE)) {
return array();
}
$query = db_select('taxonomy_index', 't');
$query->addTag('node_access');
if ($pager) {
$count_query = clone $query;
$count_query->addExpression('COUNT(t.nid)');
$query = $query
->extend('PagerDefault')
->limit(variable_get('default_nodes_main', 10));
$query->setCountQuery($count_query);
}
else {
$query->range(0, variable_get('feed_default_items', 10));
}
$query->condition('tid', $term->tid );
$query->addField('t', 'nid');
$query->addField('t', 'tid');
foreach ($order as $field => $direction) {
$query->orderBy($field, $direction);
// ORDER BY fields need to be loaded too, assume they are in the form
// table_alias.name
list($table_alias, $name) = explode('.', $field);
$query->addField($table_alias, $name);
}
return $query->execute()->fetchCol();
}

Dries Buytaert
committed
/**
* Implement hook_field_build_modes();
*
* @TODO: build mode for display as a field (when attached to nodes etc.).
*/
function taxonomy_field_build_modes($obj_type) {
$modes = array();
if ($obj_type == 'term') {
$modes = array(
'full' => t('Taxonomy term page'),
);
}
return $modes;
}

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Implement hook_theme().

Dries Buytaert
committed
*/
function taxonomy_theme() {
return array(
'taxonomy_term_select' => array(
'arguments' => array('element' => NULL),

Gábor Hojtsy
committed
),
'taxonomy_overview_vocabularies' => array(
'arguments' => array('form' => array()),
),
'taxonomy_overview_terms' => array(
'arguments' => array('form' => array()),
),

Angie Byron
committed
'taxonomy_autocomplete' => array(
'arguments' => array('element' => NULL),
),

Dries Buytaert
committed
);
}
/**
* For vocabularies not maintained by taxonomy.module, give the maintaining
* module a chance to provide a path for terms in that vocabulary.
*
* @param $term
* A term object.
* @return
* An internal Drupal path.
*/
function taxonomy_term_path($term) {
$vocabulary = taxonomy_vocabulary_load($term->vid);
if ($vocabulary->module != 'taxonomy' && $path = module_invoke($vocabulary->module, 'term_path', $term)) {
return $path;
}
return 'taxonomy/term/' . $term->tid;

Dries Buytaert
committed
* Implement hook_menu().

Dries Buytaert
committed
function taxonomy_menu() {

Dries Buytaert
committed
$items['admin/structure/taxonomy'] = array(

Gábor Hojtsy
committed
'title' => 'Taxonomy',
'description' => 'Manage tagging, categorization, and classification of your content.',
'page callback' => 'drupal_get_form',
'page arguments' => array('taxonomy_overview_vocabularies'),

Dries Buytaert
committed
'access arguments' => array('administer taxonomy'),
'file' => 'taxonomy.admin.inc',

Dries Buytaert
committed
);

Dries Buytaert
committed
$items['admin/structure/taxonomy/list'] = array(
'title' => 'List',

Dries Buytaert
committed
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);

Dries Buytaert
committed
$items['admin/structure/taxonomy/add'] = array(
'title' => 'Add vocabulary',

Dries Buytaert
committed
'page callback' => 'drupal_get_form',
'page arguments' => array('taxonomy_form_vocabulary'),

Dries Buytaert
committed
'access arguments' => array('administer taxonomy'),

Angie Byron
committed
'type' => MENU_LOCAL_ACTION,
'file' => 'taxonomy.admin.inc',

Dries Buytaert
committed
);

Dries Buytaert
committed
$items['taxonomy/term/%taxonomy_term'] = array(

Dries Buytaert
committed
'title' => 'Taxonomy term',

Dries Buytaert
committed
'title callback' => 'taxonomy_term_title',
'title arguments' => array(2),

Dries Buytaert
committed
'page callback' => 'taxonomy_term_page',
'page arguments' => array(2),
'access arguments' => array('access content'),

Dries Buytaert
committed
'type' => MENU_CALLBACK,
'file' => 'taxonomy.pages.inc',

Dries Buytaert
committed
);

Dries Buytaert
committed
$items['taxonomy/term/%taxonomy_term/view'] = array(

Dries Buytaert
committed
'title' => 'View',
'type' => MENU_DEFAULT_LOCAL_TASK,

Dries Buytaert
committed
);

Dries Buytaert
committed
$items['taxonomy/term/%taxonomy_term/edit'] = array(
'title' => 'Edit term',
'page callback' => 'taxonomy_term_edit',

Gábor Hojtsy
committed
'page arguments' => array(2),

Dries Buytaert
committed
'access callback' => 'taxonomy_term_edit_access',
'access arguments' => array(2),

Dries Buytaert
committed
'type' => MENU_LOCAL_TASK,
'weight' => 10,
'file' => 'taxonomy.pages.inc',

Dries Buytaert
committed
);

Dries Buytaert
committed
$items['taxonomy/term/%taxonomy_term/feed'] = array(
'title' => 'Taxonomy term',
'title callback' => 'taxonomy_term_title',
'title arguments' => array(2),
'page callback' => 'taxonomy_term_feed',
'page arguments' => array(2),
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
'file' => 'taxonomy.feeds.inc',

Dries Buytaert
committed
);

Dries Buytaert
committed
$items['taxonomy/autocomplete'] = array(
'title' => 'Autocomplete taxonomy',

Dries Buytaert
committed
'page callback' => 'taxonomy_autocomplete',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
'file' => 'taxonomy.pages.inc',

Dries Buytaert
committed
);

Dries Buytaert
committed

Dries Buytaert
committed
$items['admin/structure/taxonomy/%taxonomy_vocabulary'] = array(

Dries Buytaert
committed
'title' => 'Vocabulary', // this is replaced by callback
'page callback' => 'drupal_get_form',

Dries Buytaert
committed
'page arguments' => array('taxonomy_form_vocabulary', 3),
'title callback' => 'taxonomy_admin_vocabulary_title_callback',
'title arguments' => array(3),

Dries Buytaert
committed
'access arguments' => array('administer taxonomy'),
'type' => MENU_CALLBACK,
'file' => 'taxonomy.admin.inc',

Dries Buytaert
committed
);

Dries Buytaert
committed
$items['admin/structure/taxonomy/%taxonomy_vocabulary/edit'] = array(

Dries Buytaert
committed
'title' => 'Edit vocabulary',

Dries Buytaert
committed
'type' => MENU_DEFAULT_LOCAL_TASK,

Dries Buytaert
committed
'weight' => -20,
);

Dries Buytaert
committed
$items['admin/structure/taxonomy/%taxonomy_vocabulary/list'] = array(

Dries Buytaert
committed
'title' => 'List terms',
'page callback' => 'drupal_get_form',
'page arguments' => array('taxonomy_overview_terms', 3),
'access arguments' => array('administer taxonomy'),
'type' => MENU_LOCAL_TASK,

Dries Buytaert
committed
'weight' => -10,
'file' => 'taxonomy.admin.inc',

Dries Buytaert
committed
);

Angie Byron
committed
$items['admin/structure/taxonomy/%taxonomy_vocabulary/list/add'] = array(
'title' => 'Add term',

Dries Buytaert
committed
'page callback' => 'drupal_get_form',
'page arguments' => array('taxonomy_form_term', 3),

Dries Buytaert
committed
'access arguments' => array('administer taxonomy'),

Angie Byron
committed
'type' => MENU_LOCAL_ACTION,
'file' => 'taxonomy.admin.inc',

Dries Buytaert
committed
);

Dries Buytaert
committed
/**
* Return edit access for a given term.
*/
function taxonomy_term_edit_access($term) {
return user_access("edit terms in $term->vid") || user_access('administer taxonomy');
}

Dries Buytaert
committed
/**
* Return the vocabulary name given the vocabulary object.
*/
function taxonomy_admin_vocabulary_title_callback($vocabulary) {
return check_plain($vocabulary->name);
}
/**

Dries Buytaert
committed
* Save a vocabulary given a vocabulary object.

Dries Buytaert
committed
*/

Dries Buytaert
committed
function taxonomy_vocabulary_save($vocabulary) {

Dries Buytaert
committed
if (!empty($vocabulary->name)) {
// Prevent leading and trailing spaces in vocabulary names.
$vocabulary->name = trim($vocabulary->name);
}

Dries Buytaert
committed
if (!isset($vocabulary->module)) {
$vocabulary->module = 'taxonomy';

Dries Buytaert
committed
}

Dries Buytaert
committed
if (!empty($vocabulary->vid) && !empty($vocabulary->name)) {

Dries Buytaert
committed
$status = drupal_write_record('taxonomy_vocabulary', $vocabulary, 'vid');

Dries Buytaert
committed
module_invoke_all('taxonomy_vocabulary_update', $vocabulary);

Dries Buytaert
committed
elseif (empty($vocabulary->vid)) {

Dries Buytaert
committed
$status = drupal_write_record('taxonomy_vocabulary', $vocabulary);

Dries Buytaert
committed
field_attach_create_bundle($vocabulary->machine_name);

Angie Byron
committed
taxonomy_vocabulary_create_field($vocabulary);

Dries Buytaert
committed
module_invoke_all('taxonomy_vocabulary_insert', $vocabulary);

Dries Buytaert
committed
entity_get_controller('taxonomy_vocabulary')->resetCache();

Dries Buytaert
committed
return $status;
/**
* Delete a vocabulary.
*
* @param $vid
* A vocabulary ID.
* @return
* Constant indicating items were deleted.
*/

Dries Buytaert
committed
function taxonomy_vocabulary_delete($vid) {
$vocabulary = (array) taxonomy_vocabulary_load($vid);

Dries Buytaert
committed
db_delete('taxonomy_vocabulary')
->condition('vid', $vid)
->execute();
$result = db_query('SELECT tid FROM {taxonomy_term_data} WHERE vid = :vid', array(':vid' => $vid))->fetchCol();
foreach ($result as $tid) {
taxonomy_term_delete($tid);

Dries Buytaert
committed
field_attach_delete_bundle($vocabulary['machine_name']);

Dries Buytaert
committed
entity_get_controller('taxonomy_vocabulary')->resetCache();

Steven Wittens
committed
return SAVED_DELETED;
* Dynamically check and update the hierarchy flag of a vocabulary.
* Checks the current parents of all terms in a vocabulary and updates the
* vocabularies hierarchy setting to the lowest possible level. A hierarchy with
* no parents in any of its terms will be given a hierarchy of 0. If terms
* contain at most a single parent, the vocabulary will be given a hierarchy of
* 1. If any term contain multiple parents, the vocabulary will be given a
* hierarchy of 2.
* @param $vocabulary

Dries Buytaert
committed
* A vocabulary object.
* @param $changed_term
* An array of the term structure that was updated.
*/
function taxonomy_check_vocabulary_hierarchy($vocabulary, $changed_term) {

Dries Buytaert
committed
$tree = taxonomy_get_tree($vocabulary->vid);
$hierarchy = 0;
foreach ($tree as $term) {
// Update the changed term with the new parent value before comparison.
if ($term->tid == $changed_term['tid']) {
$term = (object)$changed_term;
$term->parents = $term->parent;
}
// Check this term's parent count.
if (count($term->parents) > 1) {
$hierarchy = 2;
break;
}
elseif (count($term->parents) == 1 && 0 !== array_shift($term->parents)) {
$hierarchy = 1;
}
}

Dries Buytaert
committed
if ($hierarchy != $vocabulary->hierarchy) {
$vocabulary->hierarchy = $hierarchy;
taxonomy_vocabulary_save($vocabulary);
}
return $hierarchy;
}

Angie Byron
committed
/**
* Create a default field when a vocabulary is created.
*
* @param $vocabulary
* A taxonomy vocabulary object.
*/
function taxonomy_vocabulary_create_field($vocabulary) {
$field = array(
'field_name' => 'taxonomy_' . $vocabulary->machine_name,
'type' => 'taxonomy_term',
// Set cardinality to unlimited so that select
// and autocomplete widgets behave as normal.
'cardinality' => FIELD_CARDINALITY_UNLIMITED,
'settings' => array(
'allowed_values' => array(
array(
'vid' => $vocabulary->vid,
'parent' => 0,
),
),
),
);
field_create_field($field);
}
* Save a term object to the database.
* @param $term
* A term object.
* @return
* Status constant indicating if term was inserted or updated.
*/
function taxonomy_term_save($term) {

Dries Buytaert
committed
if ($term->name) {
// Prevent leading and trailing spaces in term names.
$term->name = trim($term->name);
}

Dries Buytaert
committed
if (!isset($term->vocabulary_machine_name)) {
$vocabulary = taxonomy_vocabulary_load($term->vid);
$term->vocabulary_machine_name = $vocabulary->machine_name;
}
field_attach_presave('taxonomy_term', $term);
if (!empty($term->tid) && $term->name) {

Dries Buytaert
committed
$status = drupal_write_record('taxonomy_term_data', $term, 'tid');

Dries Buytaert
committed
field_attach_update('taxonomy_term', $term);
module_invoke_all('taxonomy_term_update', $term);

Dries Buytaert
committed
$status = drupal_write_record('taxonomy_term_data', $term);

Dries Buytaert
committed
_taxonomy_clean_field_cache($term);

Dries Buytaert
committed
field_attach_insert('taxonomy_term', $term);
module_invoke_all('taxonomy_term_insert', $term);

Dries Buytaert
committed
db_delete('taxonomy_term_hierarchy')
->condition('tid', $term->tid)
->execute();
if (!isset($term->parent) || empty($term->parent)) {
$term->parent = array(0);

Angie Byron
committed
if (!is_array($term->parent)) {
$term->parent = array($term->parent);
}

Dries Buytaert
committed
$query = db_insert('taxonomy_term_hierarchy')
->fields(array('tid', 'parent'));
if (is_array($term->parent)) {
foreach ($term->parent as $parent) {

Dries Buytaert
committed
if (is_array($parent)) {
foreach ($parent as $tid) {

Dries Buytaert
committed
$query->values(array(
'tid' => $term->tid,
'parent' => $tid
));

Dries Buytaert
committed
}
}
else {

Dries Buytaert
committed
$query->values(array(
'tid' => $term->tid,
'parent' => $parent
));

Dries Buytaert
committed
}

Dries Buytaert
committed
$query->execute();

Dries Buytaert
committed
db_delete('taxonomy_term_synonym')
->condition('tid', $term->tid)
->execute();
if (!empty($term->synonyms)) {

Dries Buytaert
committed
$query = db_insert('taxonomy_term_synonym')
->fields(array('tid', 'name'));
foreach (explode ("\n", str_replace("\r", '', $term->synonyms)) as $synonym) {

Dries Buytaert
committed
$query->values(array(
'tid' => $term->tid,
'name' => rtrim($synonym)
));

Dries Buytaert
committed
$query->execute();

Dries Buytaert
committed
taxonomy_terms_static_reset();

Dries Buytaert
committed
return $status;
/**
* Delete a term.
*
* @param $tid
* The term ID.
* @return
* Status constant indicating deletion.
*/
function taxonomy_term_delete($tid) {

Dries Buytaert
committed
$tids = array($tid);
while ($tids) {
$children_tids = $orphans = array();
foreach ($tids as $tid) {
// See if any of the term's children are about to be become orphans:
if ($children = taxonomy_get_children($tid)) {
foreach ($children as $child) {
// If the term has multiple parents, we don't delete it.
$parents = taxonomy_get_parents($child->tid);
if (count($parents) == 1) {
$orphans[] = $child->tid;
}
}
}
$term = taxonomy_term_load($tid);

Dries Buytaert
committed
db_delete('taxonomy_term_data')
->condition('tid', $tid)
->execute();
db_delete('taxonomy_term_hierarchy')
->condition('tid', $tid)
->execute();
db_delete('taxonomy_term_synonym')
->condition('tid', $tid)
->execute();

Dries Buytaert
committed
field_attach_delete('taxonomy_term', $term);

Dries Buytaert
committed
_taxonomy_clean_field_cache($term);
module_invoke_all('taxonomy_term_delete', $term);

Dries Buytaert
committed
}

Dries Buytaert
committed
$tids = $orphans;
}

Dries Buytaert
committed
taxonomy_terms_static_reset();

Gerhard Killesreiter
committed
return SAVED_DELETED;

Dries Buytaert
committed
/**
* Clear all static cache variables for terms..
*/
function taxonomy_terms_static_reset() {
drupal_static_reset('taxonomy_term_count_nodes');
drupal_static_reset('taxonomy_get_tree');
drupal_static_reset('taxonomy_get_synonym_root');

Dries Buytaert
committed
entity_get_controller('taxonomy_term')->resetCache();

Dries Buytaert
committed
}
/**
* Generate a form element for selecting terms from a vocabulary.

Angie Byron
committed
*
* @param $vid
* The vocabulary ID to generate a form element for
* @param $value
* The existing value of the term(s) in this vocabulary to use by default.
* @param $help
* Optional help text to use for the form element. If specified, this value
* MUST be properly sanitized and filtered (e.g. with filter_xss_admin() or
* check_plain() if it is user-supplied) to prevent XSS vulnerabilities. If
* omitted, the help text stored with the vocaulary (if any) will be used.
* @return
* An array describing a form element to select terms for a vocabulary.
*
* @see _taxonomy_term_select()
* @see filter_xss_admin()

Dries Buytaert
committed
function taxonomy_form($vid, $value = 0, $help = NULL) {
$vocabulary = taxonomy_vocabulary_load($vid);

Angie Byron
committed
$help = ($help) ? $help : filter_xss_admin($vocabulary->help);

Dries Buytaert
committed

Angie Byron
committed
$blank = t('- Please choose -');

Angie Byron
committed
return _taxonomy_term_select(check_plain($vocabulary->name), $value, $vid, $help, $blank);

Neil Drumm
committed
/**
* Generate a set of options for selecting a term from all vocabularies.

Neil Drumm
committed
*/

Angie Byron
committed
function taxonomy_form_all() {

Neil Drumm
committed
$vocabularies = taxonomy_get_vocabularies();
$options = array();
foreach ($vocabularies as $vid => $vocabulary) {
$tree = taxonomy_get_tree($vid);

Dries Buytaert
committed
if ($tree && (count($tree) > 0)) {

Neil Drumm
committed
$options[$vocabulary->name] = array();

Neil Drumm
committed
foreach ($tree as $term) {

Dries Buytaert
committed
$options[$vocabulary->name][$term->tid] = str_repeat('-', $term->depth) . $term->name;

Neil Drumm
committed
}
}
}
return $options;
}
/**
* Return an array of all vocabulary objects.
*
* @param $type
* If set, return only those vocabularies associated with this node type.
*/

Angie Byron
committed
function taxonomy_get_vocabularies() {
return taxonomy_vocabulary_load_multiple(FALSE, array());

Dries Buytaert
committed
/**
* Get names for all taxonomy vocabularies.
*
* @return

Dries Buytaert
committed
* An array of vocabulary ids, names, machine names, keyed by machine name.

Dries Buytaert
committed
*/
function taxonomy_vocabulary_get_names() {

Dries Buytaert
committed
$names = db_query('SELECT name, machine_name, vid FROM {taxonomy_vocabulary}')->fetchAllAssoc('machine_name');

Dries Buytaert
committed
return $names;
}
/**
* Find all parents of a given term ID.
*/
function taxonomy_get_parents($tid, $key = 'tid') {

Dries Buytaert
committed
$query = db_select('taxonomy_term_data', 't');
$query->join('taxonomy_term_hierarchy', 'h', 'h.parent = t.tid');
$query->addTag('term_access');
$result = $query
->fields('t')
->condition('h.tid', $tid)
->orderBy('weight')
->orderBy('name')
->execute();

Dries Buytaert
committed
foreach ($result as $parent) {
/**
* Find all ancestors of a given term ID.
*/
function taxonomy_get_parents_all($tid) {

Angie Byron
committed
if ($term = taxonomy_term_load($tid)) {
$parents[] = $term;
$n = 0;
while ($parent = taxonomy_get_parents($parents[$n]->tid)) {
$parents = array_merge($parents, $parent);
$n++;
}
}
return $parents;
}
/**
* Find all children of a term ID.
*/
function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {

Dries Buytaert
committed
$query = db_select('taxonomy_term_data', 't');
$query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
$query->addTag('term_access');
$query
->fields('t')
->condition('parent', $tid)
->orderBy('weight')
->orderBy('name');

Dries Buytaert
committed
$query->condition('t.vid', $vid);

Dries Buytaert
committed
$result = $query->execute();

Dries Buytaert
committed
foreach ($result as $term) {
$children[$term->$key] = $term;
}
return $children;
}
/**
* Create a hierarchical representation of a vocabulary.
*
* @param $vid
* Which vocabulary to generate the tree for.
* @param $parent
* The term ID under which to generate the tree. If 0, generate the tree
* for the entire vocabulary.
* @param $max_depth
* The number of levels of the tree to return. Leave NULL to return all levels.
* @param $depth
* Internal use only.
*
* @return
* An array of all term objects in the tree. Each term object is extended
* to have "depth" and "parents" attributes in addition to its normal ones.
* Results are statically cached.

Dries Buytaert
committed
function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $depth = -1) {
$children = &drupal_static(__FUNCTION__, array());
$parents = &drupal_static(__FUNCTION__ . 'parents', array());
$terms = &drupal_static(__FUNCTION__ . 'terms', array());
// We cache trees, so it's not CPU-intensive to call get_tree() on a term
// and its children, too.
if (!isset($children[$vid])) {
$children[$vid] = array();

Dries Buytaert
committed
$parents[$vid] = array();
$terms[$vid] = array();

Dries Buytaert
committed
$query = db_select('taxonomy_term_data', 't');
$query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
$query->addTag('term_access');
$result = $query
->fields('t')
->fields('h', array('parent'))
->condition('t.vid', $vid)
->orderBy('weight')
->orderBy('name')
->execute();
foreach ($result as $term) {
$children[$vid][$term->parent][] = $term->tid;
$parents[$vid][$term->tid][] = $term->parent;
$terms[$vid][$term->tid] = $term;
$max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;

Dries Buytaert
committed
$tree = array();
if ($max_depth > $depth && !empty($children[$vid][$parent])) {
$term = clone $terms[$vid][$child];
$term->depth = $depth;
// The "parent" attribute is not useful, as it would show one parent only.
unset($term->parent);
$term->parents = $parents[$vid][$child];
$tree[] = $term;
if (!empty($children[$vid][$child])) {
$tree = array_merge($tree, taxonomy_get_tree($vid, $child, $max_depth, $depth));

Dries Buytaert
committed
return $tree;
function taxonomy_get_synonyms($tid) {
if ($tid) {

Dries Buytaert
committed
return db_query('SELECT name FROM {taxonomy_term_synonym} WHERE tid = :tid', array(':tid' => $tid))->fetchCol();
/**
* Return the term object that has the given string as a synonym.
*
* @param $synonym
* The string to compare against.
* @return
* A term object, or FALSE if no matching term is found.

Dries Buytaert
committed
function taxonomy_get_synonym_root($synonym) {
$synonyms = &drupal_static(__FUNCTION__, array());
if (!isset($synonyms[$synonym])) {

Dries Buytaert
committed
$synonyms[$synonym] = db_query("SELECT * FROM {taxonomy_term_synonym} s, {taxonomy_term_data} t WHERE t.tid = s.tid AND s.name = :name", array(':name' => $synonym))->fetch();
}
return $synonyms[$synonym];
* Provides a case-insensitive and trimmed mapping, to maximize the
* likelihood of a successful match.
*
* @param name
* Name of the term to search for.
*
* @return
* An array of matching term objects.
return taxonomy_term_load_multiple(array(), array('name' => trim($name)));

Dries Buytaert
committed
/**
* Controller class for taxonomy terms.
*
* This extends the DrupalDefaultEntityController class. Only alteration is
* that we match the condition on term name case-independently.
*/
class TaxonomyTermController extends DrupalDefaultEntityController {
protected $type;
public function load($ids = array(), $conditions = array()) {
if (isset($conditions['type'])) {
$this->type = $conditions['type'];
unset($conditions['type']);
}

Dries Buytaert
committed
return parent::load($ids, $conditions);
}

Dries Buytaert
committed
protected function buildQuery() {
parent::buildQuery();
// When name is passed as a condition use LIKE.
if (isset($this->conditions['name'])) {
$conditions = &$this->query->conditions();
foreach ($conditions as $key => $condition) {
if ($condition['field'] == 'base.name') {
$conditions[$key]['operator'] = 'LIKE';
}
}
}

Dries Buytaert
committed
// Add the machine name field from the {taxonomy_vocabulary} table.
$this->query->innerJoin('taxonomy_vocabulary', 'v', 'base.vid = v.vid');
$this->query->addField('v', 'machine_name', 'vocabulary_machine_name');
}
protected function cacheGet($ids, $conditions = array()) {
$terms = parent::cacheGet($ids, $conditions);

Dries Buytaert
committed
// Name matching is case insensitive, note that with some collations
// LOWER() and drupal_strtolower() may return different results.
foreach ($terms as $term) {
$term_values = (array) $term;
if (isset($this->conditions['name']) && drupal_strtolower($this->conditions['name'] != drupal_strtolower($term_values['name']))) {
unset($terms[$term->tid]);
}
}

Dries Buytaert
committed
return $terms;
}
}

Dries Buytaert
committed
/**
* Controller class for taxonomy vocabularies.
*
* This extends the DrupalDefaultEntityController class, adding required
* special handling for taxonomy vocabulary objects.
*/
class TaxonomyVocabularyController extends DrupalDefaultEntityController {
protected function buildQuery() {
parent::buildQuery();
$this->query->orderBy('base.weight');
$this->query->orderBy('base.name');
}

Dries Buytaert
committed
protected function attachLoad(&$records) {
foreach ($records as $record) {
// If no node types are associated with a vocabulary, the LEFT JOIN will
// return a NULL value for type.
$queried_vocabularies[$record->vid] = $record;
}

Dries Buytaert
committed
$records = $queried_vocabularies;
parent::attachLoad($records);
/**
* Load multiple taxonomy terms based on certain conditions.
*
* This function should be used whenever you need to load more than one term
* from the database. Terms are loaded into memory and will not require
* database access if loaded again during the same page request.
*

Dries Buytaert
committed
* @see entity_load()
*
* @param $tids
* An array of taxonomy term IDs.
* @param $conditions
* An array of conditions to add to the query.
*
* @return
* An array of term objects, indexed by tid.
*/

Dries Buytaert
committed
function taxonomy_term_load_multiple($tids = array(), $conditions = array()) {

Dries Buytaert
committed
return entity_load('taxonomy_term', $tids, $conditions);
}

Dries Buytaert
committed
/**
* Load multiple taxonomy vocabularies based on certain conditions.
*
* This function should be used whenever you need to load more than one
* vocabulary from the database. Terms are loaded into memory and will not
* require database access if loaded again during the same page request.
*
* @see entity_load()
*
* @param $vids
* An array of taxonomy vocabulary IDs, or FALSE to load all vocabularies.
* @param $conditions
* An array of conditions to add to the query.
*
* @return
* An array of vocabulary objects, indexed by vid.
*/
function taxonomy_vocabulary_load_multiple($vids = array(), $conditions = array()) {
return entity_load('taxonomy_vocabulary', $vids, $conditions);
}

Dries Buytaert
committed
/**
* Return the vocabulary object matching a vocabulary ID.
*
* @param $vid
* The vocabulary's ID.
*
* @return
* The vocabulary object with all of its metadata, if exists, FALSE otherwise.
* Results are statically cached.
*/
function taxonomy_vocabulary_load($vid) {
return reset(taxonomy_vocabulary_load_multiple(array($vid)));
}
*
* @param $tid
* A term's ID
*
* @return
* A term object. Results are statically cached.

Dries Buytaert
committed
function taxonomy_term_load($tid) {

Dries Buytaert
committed
if (!is_numeric($tid)) {
return FALSE;
}

Dries Buytaert
committed
$term = taxonomy_term_load_multiple(array($tid), array());
return $term ? $term[$tid] : FALSE;
}

Angie Byron
committed
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
/**
* Create a select form element for a given taxonomy vocabulary.
*
* NOTE: This function expects input that has already been sanitized and is
* safe for display. Callers must properly sanitize the $title and
* $description arguments to prevent XSS vulnerabilities.
*
* @param $title
* The title of the vocabulary. This MUST be sanitized by the caller.
* @param $value
* The currently selected terms from this vocabulary, if any.
* @param $vocabulary_id
* The vocabulary ID to build the form element for.
* @param $description
* Help text for the form element. This MUST be sanitized by the caller.
* @param $multiple
* Boolean to control if the form should use a single or multiple select.
* @param $blank
* Optional form choice to use when no value has been selected.
* @param $exclude
* Optional array of term ids to exclude in the selector.
* @return
* A FAPI form array to select terms from the given vocabulary.
*
* @see taxonomy_form()
* @see taxonomy_form_term()
*/

Angie Byron
committed
function _taxonomy_term_select($title, $value, $vocabulary_id, $description, $blank, $exclude = array()) {

Dries Buytaert
committed
$options = array();