taxonomy.module 53.2 KB
Newer Older
Dries Buytaert's avatar
 
Dries Buytaert committed
1
<?php
Kjartan Mannes's avatar
Kjartan Mannes committed
2
// $Id$
Dries Buytaert's avatar
   
Dries Buytaert committed
3

Dries Buytaert's avatar
   
Dries Buytaert committed
4
5
6
7
8
/**
 * @file
 * Enables the organization of content into categories.
 */

Dries Buytaert's avatar
   
Dries Buytaert committed
9
10
11
/**
 * Implementation of hook_perm().
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
12
function taxonomy_perm() {
Dries Buytaert's avatar
   
Dries Buytaert committed
13
  return array('administer taxonomy');
Kjartan Mannes's avatar
Kjartan Mannes committed
14
}
Dries Buytaert's avatar
 
Dries Buytaert committed
15

Dries Buytaert's avatar
   
Dries Buytaert committed
16
17
18
19
20
21
22
23
24
25
26
/**
 * Implementation of hook_link().
 *
 * This hook is extended with $type = 'taxonomy terms' to allow themes to
 * print lists of terms associated with a node. Themes can print taxonomy
 * links with:
 *
 * if (module_exist('taxonomy')) {
 *   $this->links(taxonomy_link('taxonomy terms', $node));
 * }
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
27
function taxonomy_link($type, $node = NULL) {
Dries Buytaert's avatar
   
Dries Buytaert committed
28
  if ($type == 'taxonomy terms' && $node != NULL) {
Kjartan Mannes's avatar
   
Kjartan Mannes committed
29
    $links = array();
Dries Buytaert's avatar
   
Dries Buytaert committed
30
    if (array_key_exists('taxonomy', $node)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
31
32
      foreach ($node->taxonomy as $tid) {
        $term = taxonomy_get_term($tid);
Dries Buytaert's avatar
   
Dries Buytaert committed
33
        $links[] = l($term->name, 'taxonomy/term/'. $term->tid);
Dries Buytaert's avatar
   
Dries Buytaert committed
34
35
36
37
      }
    }
    else {
      foreach (taxonomy_node_get_terms($node->nid) as $term) {
Dries Buytaert's avatar
   
Dries Buytaert committed
38
        $links[] = l($term->name, 'taxonomy/term/'. $term->tid);
Dries Buytaert's avatar
   
Dries Buytaert committed
39
      }
Dries Buytaert's avatar
   
Dries Buytaert committed
40
41
42
    }
    return $links;
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
43
44
}

Dries Buytaert's avatar
   
Dries Buytaert committed
45
46
47
/**
 * Implementation of hook_menu().
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
48
function taxonomy_menu($may_cache) {
Dries Buytaert's avatar
   
Dries Buytaert committed
49
  $items = array();
Dries Buytaert's avatar
   
Dries Buytaert committed
50

Dries Buytaert's avatar
   
Dries Buytaert committed
51
52
53
54
  if ($may_cache) {
    $items[] = array('path' => 'admin/taxonomy', 'title' => t('categories'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'));
55

Dries Buytaert's avatar
   
Dries Buytaert committed
56
57
    $items[] = array('path' => 'admin/taxonomy/list', 'title' => t('list'),
      'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
58

Dries Buytaert's avatar
   
Dries Buytaert committed
59
60
61
62
63
    $items[] = array('path' => 'admin/taxonomy/add/vocabulary', 'title' => t('add vocabulary'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_LOCAL_TASK);

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    $items[] = array('path' => 'admin/taxonomy/edit/vocabulary', 'title' => t('edit vocabulary'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK);

    $items[] = array('path' => 'admin/taxonomy/add/term', 'title' => t('add term'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK);

    $items[] = array('path' => 'admin/taxonomy/edit/term', 'title' => t('edit term'),
      'callback' => 'taxonomy_admin',
      'access' => user_access('administer taxonomy'),
      'type' => MENU_CALLBACK);

Dries Buytaert's avatar
   
Dries Buytaert committed
79
80
81
82
    $items[] = array('path' => 'taxonomy/term', 'title' => t('taxonomy term'),
      'callback' => 'taxonomy_term_page',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK);
Steven Wittens's avatar
Steven Wittens committed
83
84
85
86
87

    $items[] = array('path' => 'taxonomy/autocomplete', 'title' => t('autocomplete taxonomy'),
      'callback' => 'taxonomy_autocomplete',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK);
Dries Buytaert's avatar
   
Dries Buytaert committed
88
  }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  else {
    if (is_numeric(arg(2))) {
      $items[] = array('path' => 'admin/taxonomy/' . arg(2), 'title' => t('add term'),
        'callback' => 'taxonomy_admin',
        'access' => user_access('administer taxonomy'),
        'type' => MENU_CALLBACK);

      $items[] = array('path' => 'admin/taxonomy/' . arg(2) . '/list', 'title' => t('list'),
        'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);

      $items[] = array('path' => 'admin/taxonomy/' . arg(2) . '/add/term', 'title' => t('add term'),
        'callback' => 'taxonomy_admin',
        'access' => user_access('administer taxonomy'),
        'type' => MENU_LOCAL_TASK);
    }
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
105

Dries Buytaert's avatar
   
Dries Buytaert committed
106
107
  return $items;
}
Dries Buytaert's avatar
 
Dries Buytaert committed
108

Kjartan Mannes's avatar
Kjartan Mannes committed
109
function taxonomy_form_vocabulary($edit = array()) {
110
111
112
113
114
115
116
117
118
119
120
  $form['name'] = array(type => 'textfield', title => t('Vocabulary name'), default_value => $edit['name'], size => 60, maxlength => 64, description => t('The name for this vocabulary.  Example: "Topic".'), required => TRUE);

  $form['description'] = array(type => 'textarea', title => t('Description'), default_value => $edit['description'], cols => 60, rows => 5, description => t('Description of the vocabulary; can be used by modules.'));
  $form['help'] = array(type => 'textfield', title => t('Help text'), default_value => $edit['help'], size => 60, maxlength => 255, description => t('Instructions to present to the user when choosing a term.'));
  $form['nodes'] = array(type => 'checkboxes', title => t('Types'), default_value => $edit['nodes'], options => node_get_types(), description => t('A list of node types you want to associate with this vocabulary.'), required => TRUE);
  $form['hierarchy'] = array(type => 'radios', title => t('Hierarchy'), default_value => $edit['hierarchy'], options => array(t('Disabled'), t('Single'), t('Multiple')), description => t('Allows <a href="%help-url">a tree-like hierarchy</a> between terms of this vocabulary.', array('%help-url' => url('admin/help/taxonomy', NULL, NULL, 'hierarchy'))));
  $form['relations'] = array(type => 'checkbox', title => t('Related terms'), default_value => $edit['relations'], return_value => 1, description => t('Allows <a href="%help-url">related terms</a> in this vocabulary.', array('%help-url' => url('admin/help/taxonomy', NULL, NULL, 'related-terms'))));
  $form['tags'] = array(type => 'checkbox', title => t('Free tagging'), default_value => $edit['tags'], return_value => 1, description => t('Content is categorized by typing terms instead of choosing from a list.'));
  $form['multiple'] = array(type => 'checkbox', title => t('Multiple select'), default_value => $edit['multiple'], return_value => 1, description => t('Allows nodes to have more than one term from this vocabulary (always true for free tagging).'));
  $form['required'] = array(type => 'checkbox', title => t('Required'), default_value => $edit['required'], return_value => 1, description => t('If enabled, every node <strong>must</strong> have at least one term in this vocabulary.'));
  $form['weight'] = array(type => 'weight', title => t('Weight'), default_value => $edit['weight'], delta => 10, description => t('In listings, the heavier vocabularies will sink and the lighter vocabularies will be positioned nearer the top.'));
121

122
123
124
125
126
127
128
129
  // Add extra vocabulary form elements.
  $extra = module_invoke_all('taxonomy', 'form', 'vocabulary');
  if (is_array($extra)) {
    foreach ($extra as $key => $element) {
      $extra[$key][weight] = isset($extra[$key][weight]) ? $nodeapi[$key][weight] : -18;
    }
    $form = array_merge($form, $extra);
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
130

131
  $form['submit'] = array(type => 'submit', value => t('Submit'));
Dries Buytaert's avatar
   
Dries Buytaert committed
132
  if ($edit['vid']) {
133
134
    $form['delete'] = array(type => 'submit', value => t('Delete'));
    $form['vid'] = array(type => 'hidden', value => $edit['vid']);
Dries Buytaert's avatar
 
Dries Buytaert committed
135
  }
136
  return drupal_get_form('taxonomy_form_vocabulary', $form);
Kjartan Mannes's avatar
Kjartan Mannes committed
137
}
Kjartan Mannes's avatar
Kjartan Mannes committed
138

139
function taxonomy_save_vocabulary(&$edit) {
140
141
  $edit['nodes'] = ($edit['nodes']) ? $edit['nodes'] : array();
  $edit['weight'] = ($edit['weight']) ? $edit['weight'] : 0;
142
  $edit['tags'] = ($edit['tags']) ? $edit['tags'] : 0;
Dries Buytaert's avatar
   
Dries Buytaert committed
143

144
  $data = array('name' => $edit['name'], 'description' => $edit['description'], 'help' => $edit['help'], 'multiple' => $edit['multiple'], 'required' => $edit['required'], 'hierarchy' => $edit['hierarchy'], 'relations' => $edit['relations'], 'tags' => $edit['tags'], 'weight' => $edit['weight'],  'module' => isset($edit['module']) ? $edit['module'] : 'taxonomy');
Dries Buytaert's avatar
   
Dries Buytaert committed
145
  if ($edit['vid'] && $edit['name']) {
Dries Buytaert's avatar
   
Dries Buytaert committed
146
    db_query('UPDATE {vocabulary} SET '. _taxonomy_prepare_update($data) .' WHERE vid = %d', $edit['vid']);
Dries Buytaert's avatar
   
Dries Buytaert committed
147
    db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d", $edit['vid']);
148
    foreach ($edit['nodes'] as $type => $selected) {
Dries Buytaert's avatar
   
Dries Buytaert committed
149
150
      db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
151
    module_invoke_all('taxonomy', 'update', 'vocabulary', $edit);
152
    $status = SAVED_UPDATED;
Dries Buytaert's avatar
 
Dries Buytaert committed
153
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
154
  else if ($edit['vid']) {
155
    $status = taxonomy_del_vocabulary($edit['vid']);
Kjartan Mannes's avatar
Kjartan Mannes committed
156
157
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
158
    $data['vid'] = $edit['vid'] = db_next_id('{vocabulary}_vid');
Dries Buytaert's avatar
   
Dries Buytaert committed
159
    db_query('INSERT INTO {vocabulary} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
160
    foreach ($edit['nodes'] as $type => $selected) {
Dries Buytaert's avatar
   
Dries Buytaert committed
161
162
      db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $edit['vid'], $type);
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
163
    module_invoke_all('taxonomy', 'insert', 'vocabulary', $edit);
164
    $status = SAVED_NEW;
Kjartan Mannes's avatar
Kjartan Mannes committed
165
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
166
167

  cache_clear_all();
Dries Buytaert's avatar
   
Dries Buytaert committed
168

169
  return $status;
Kjartan Mannes's avatar
Kjartan Mannes committed
170
}
Dries Buytaert's avatar
 
Dries Buytaert committed
171

Kjartan Mannes's avatar
Kjartan Mannes committed
172
function taxonomy_del_vocabulary($vid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
173
174
  $vocabulary = taxonomy_get_vocabulary($vid);

Dries Buytaert's avatar
   
Dries Buytaert committed
175
  db_query('DELETE FROM {vocabulary} WHERE vid = %d', $vid);
Dries Buytaert's avatar
   
Dries Buytaert committed
176
  db_query('DELETE FROM {vocabulary_node_types} WHERE vid = %d', $vid);
Dries Buytaert's avatar
   
Dries Buytaert committed
177
  $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid);
Kjartan Mannes's avatar
Kjartan Mannes committed
178
179
  while ($term = db_fetch_object($result)) {
    taxonomy_del_term($term->tid);
Dries Buytaert's avatar
 
Dries Buytaert committed
180
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
181

Dries Buytaert's avatar
   
Dries Buytaert committed
182
  module_invoke_all('taxonomy', 'delete', 'vocabulary', $vocabulary);
Dries Buytaert's avatar
   
Dries Buytaert committed
183

Dries Buytaert's avatar
   
Dries Buytaert committed
184
185
  cache_clear_all();

186
  return SAVED_DELETED;
Dries Buytaert's avatar
   
Dries Buytaert committed
187
188
189
190
191
}

function _taxonomy_confirm_del_vocabulary($vid) {
  $vocabulary = taxonomy_get_vocabulary($vid);

192
193
194
195
196
197
198
  $form['type'] = array(type => 'hidden', value => 'vocabulary');
  $form['vid'] = array(type => 'hidden', value => $vid);
  $form['name'] = array(type => 'hidden', value => $vocabulary->name);
  return confirm_form('vocabulary_confirm_delete', $form,
                  t('Are you sure you want to delete the vocabulary %title?',
                  array('%title' => theme('placeholder', $vocabulary->name))),
                  'admin/taxonomy', t('Deleting a vocabulary will delete all the terms in it. This action cannot be undone.'),
199
                  t('Delete'),
200
                  t('Cancel'));
Kjartan Mannes's avatar
Kjartan Mannes committed
201
}
Dries Buytaert's avatar
 
Dries Buytaert committed
202

Kjartan Mannes's avatar
Kjartan Mannes committed
203
function taxonomy_form_term($edit = array()) {
Dries Buytaert's avatar
   
Dries Buytaert committed
204
  $vocabulary_id = isset($edit['vid']) ? $edit['vid'] : arg(4);
Kjartan Mannes's avatar
Kjartan Mannes committed
205
  $vocabulary = taxonomy_get_vocabulary($vocabulary_id);
Dries Buytaert's avatar
   
Dries Buytaert committed
206

207
208
209
  $form['name'] = array(type => 'textfield', title => t('Term name'), default_value => $edit['name'], size => 60, maxlength => 64, description => t('The name for this term.  Example: "Linux".'), required => TRUE);

  $form['description'] = array(type => 'textarea', title => t('Description'), default_value => $edit['description'], cols => 60, rows => 5, description => t('A description of the term.'));
Dries Buytaert's avatar
 
Dries Buytaert committed
210

Kjartan Mannes's avatar
Kjartan Mannes committed
211
  if ($vocabulary->hierarchy) {
Dries Buytaert's avatar
   
Dries Buytaert committed
212
213
    $parent = array_keys(taxonomy_get_parents($edit['tid']));
    $children = taxonomy_get_tree($vocabulary_id, $edit['tid']);
Dries Buytaert's avatar
   
Dries Buytaert committed
214

Dries Buytaert's avatar
   
Dries Buytaert committed
215
    // A term can't be the child of itself, nor of its children.
Dries Buytaert's avatar
   
Dries Buytaert committed
216
217
218
    foreach ($children as $child) {
      $exclude[] = $child->tid;
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
219
    $exclude[] = $edit['tid'];
Dries Buytaert's avatar
   
Dries Buytaert committed
220

Kjartan Mannes's avatar
Kjartan Mannes committed
221
    if ($vocabulary->hierarchy == 1) {
222
      $form['parent'] = _taxonomy_term_select(t('Parent'), 'parent', $parent, $vocabulary_id, l(t('Parent term'), 'admin/help/taxonomy', NULL, NULL, 'parent') .'.', 0, '<'. t('root') .'>', $exclude);
Dries Buytaert's avatar
 
Dries Buytaert committed
223
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
224
    elseif ($vocabulary->hierarchy == 2) {
225
      $form['parent'] = _taxonomy_term_select(t('Parents'), 'parent', $parent, $vocabulary_id, l(t('Parent terms'), 'admin/help/taxonomy', NULL, NULL, 'parent') .'.', 1, '<'. t('root') .'>', $exclude);
Dries Buytaert's avatar
 
Dries Buytaert committed
226
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
227
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
228

229
  if ($vocabulary->relations) {
230
    $form['relations'] = _taxonomy_term_select(t('Related terms'), 'relations', array_keys(taxonomy_get_related($edit['tid'])), $vocabulary_id, NULL, 1, '<'. t('none') .'>', array($edit['tid']));
231
232
  }

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  $form['synonyms'] = array(type => 'textarea', title => t('Synonyms'), default_value => implode("\n", taxonomy_get_synonyms($edit['tid'])), cols => 60, rows => 5, description => t('<a href="%help-url">Synonyms</a> of this term, one synonym per line.', array('%help-url' => url('admin/help/taxonomy', NULL, NULL, 'synonyms'))));
  $form['weight'] = array(type => 'weight', title => t('Weight'), default_value => $edit['weight'], delta => 10, description => t('In listings, the heavier terms will sink and the lighter terms will be positioned nearer the top.'));

  // Add extra term form elements.
  $extra = module_invoke_all('taxonomy', 'term', 'vocabulary');
  if (is_array($extra)) {
    foreach ($extra as $key => $element) {
      $extra[$key][weight] = isset($extra[$key][weight]) ? $nodeapi[$key][weight] : -18;
    }
    $form = array_merge($form, $extra);
  }


  $form['vid'] = array(type => 'hidden', value => $vocabulary->vid);
  $form['submit'] = array(type => 'submit', value => t('Submit'));
Kjartan Mannes's avatar
Kjartan Mannes committed
248

Dries Buytaert's avatar
   
Dries Buytaert committed
249
  if ($edit['tid']) {
250
251
    $form['delete'] = array(type => 'submit', value => t('Delete'));
    $form['tid'] = array(type => 'hidden', value => $edit['tid']);
Dries Buytaert's avatar
 
Dries Buytaert committed
252
  }
253
  else {
254
    $form['destination'] = array(type => 'hidden', value => $_GET['q']);
255
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
256

257
  return drupal_get_form('taxonomy_form_term', $form);
Kjartan Mannes's avatar
Kjartan Mannes committed
258
}
Dries Buytaert's avatar
 
Dries Buytaert committed
259

260
function taxonomy_save_term(&$edit) {
Dries Buytaert's avatar
   
Dries Buytaert committed
261
262
  if ($edit['tid'] && $edit['name']) {
    $data = array('name' => $edit['name'], 'description' => $edit['description'], 'weight' => $edit['weight']);
Dries Buytaert's avatar
 
Dries Buytaert committed
263

Dries Buytaert's avatar
   
Dries Buytaert committed
264
    db_query('UPDATE {term_data} SET '. _taxonomy_prepare_update($data) .' WHERE tid = %d', $edit['tid']);
Dries Buytaert's avatar
   
Dries Buytaert committed
265
    module_invoke_all('taxonomy', 'update', 'term', $edit);
266
    $status = SAVED_UPDATED;
Kjartan Mannes's avatar
Kjartan Mannes committed
267
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
268
269
  else if ($edit['tid']) {
    return taxonomy_del_term($edit['tid']);
Kjartan Mannes's avatar
Kjartan Mannes committed
270
271
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
272
273
    $edit['tid'] = db_next_id('{term_data}_tid');
    $data = array('tid' => $edit['tid'], 'name' => $edit['name'], 'description' => $edit['description'], 'vid' => $edit['vid'], 'weight' => $edit['weight']);
Dries Buytaert's avatar
   
Dries Buytaert committed
274
    db_query('INSERT INTO {term_data} '. _taxonomy_prepare_insert($data, 1) .' VALUES '. _taxonomy_prepare_insert($data, 2));
Dries Buytaert's avatar
   
Dries Buytaert committed
275
    module_invoke_all('taxonomy', 'insert', 'term', $edit);
276
    $status = SAVED_NEW;
Kjartan Mannes's avatar
Kjartan Mannes committed
277
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
278

Dries Buytaert's avatar
   
Dries Buytaert committed
279
280
281
  db_query('DELETE FROM {term_relation} WHERE tid1 = %d OR tid2 = %d', $edit['tid'], $edit['tid']);
  if ($edit['relations']) {
    foreach ($edit['relations'] as $related_id) {
Kjartan Mannes's avatar
Kjartan Mannes committed
282
      if ($related_id != 0) {
Dries Buytaert's avatar
   
Dries Buytaert committed
283
        db_query('INSERT INTO {term_relation} (tid1, tid2) VALUES (%d, %d)', $edit['tid'], $related_id);
Dries Buytaert's avatar
 
Dries Buytaert committed
284
      }
Kjartan Mannes's avatar
Kjartan Mannes committed
285
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
286
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
287

Dries Buytaert's avatar
   
Dries Buytaert committed
288
289
  db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $edit['tid']);
  if (!isset($edit['parent'])) {
290
    $edit['parent'] = array(0);
Kjartan Mannes's avatar
Kjartan Mannes committed
291
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
292
293
  if (is_array($edit['parent'])) {
    foreach ($edit['parent'] as $parent) {
294
295
296
297
298
299
300
301
      if (is_array($parent)) {
        foreach ($parent as $tid) {
          db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $tid);
        }
      }
      else {
        db_query('INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)', $edit['tid'], $parent);
      }
Dries Buytaert's avatar
 
Dries Buytaert committed
302
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
303
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
304

Dries Buytaert's avatar
   
Dries Buytaert committed
305
306
307
  db_query('DELETE FROM {term_synonym} WHERE tid = %d', $edit['tid']);
  if ($edit['synonyms']) {
    foreach (explode ("\n", str_replace("\r", '', $edit['synonyms'])) as $synonym) {
Dries Buytaert's avatar
   
Dries Buytaert committed
308
      if ($synonym) {
Dries Buytaert's avatar
   
Dries Buytaert committed
309
        db_query("INSERT INTO {term_synonym} (tid, name) VALUES (%d, '%s')", $edit['tid'], chop($synonym));
Dries Buytaert's avatar
   
Dries Buytaert committed
310
      }
Kjartan Mannes's avatar
Kjartan Mannes committed
311
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
312
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
313

Dries Buytaert's avatar
   
Dries Buytaert committed
314
315
  cache_clear_all();

316
  return $status;
Kjartan Mannes's avatar
Kjartan Mannes committed
317
}
Dries Buytaert's avatar
 
Dries Buytaert committed
318

Kjartan Mannes's avatar
Kjartan Mannes committed
319
function taxonomy_del_term($tid) {
320
321
322
323
324
325
326
327
328
329
330
331
332
333
  $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;
          }
        }
      }
Dries Buytaert's avatar
   
Dries Buytaert committed
334

335
      $term = taxonomy_get_term($tid);
Dries Buytaert's avatar
   
Dries Buytaert committed
336

337
338
339
340
341
      db_query('DELETE FROM {term_data} WHERE tid = %d', $tid);
      db_query('DELETE FROM {term_hierarchy} WHERE tid = %d', $tid);
      db_query('DELETE FROM {term_relation} WHERE tid1 = %d OR tid2 = %d', $tid, $tid);
      db_query('DELETE FROM {term_synonym} WHERE tid = %d', $tid);
      db_query('DELETE FROM {term_node} WHERE tid = %d', $tid);
Dries Buytaert's avatar
   
Dries Buytaert committed
342

343
      module_invoke_all('taxonomy', 'delete', 'term', $term);
344
      drupal_set_message(t('Deleted term %name.', array('%name' => theme('placeholder', $term->name))));
345
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
346

347
348
    $tids = $orphans;
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
349

Dries Buytaert's avatar
   
Dries Buytaert committed
350
  cache_clear_all();
Dries Buytaert's avatar
   
Dries Buytaert committed
351
352
353
354
355
}

function _taxonomy_confirm_del_term($tid) {
  $term = taxonomy_get_term($tid);

356
357
358
359
360
  $form['type'] = array(type => 'hidden', value => 'term');
  $form['tid'] = array(type => 'hidden', value => $tid);
  return confirm_form('term_confirm_delete', $form,
                  t('Are you sure you want to delete the term %title?',
                  array('%title' => theme('placeholder', $term->name))),
361
362
363
                  'admin/taxonomy',
                  t('Deleting a term will delete all its children if there are any. This action cannot be undone.'),
                  t('Delete'),
364
                  t('Cancel'));
Kjartan Mannes's avatar
Kjartan Mannes committed
365
}
Dries Buytaert's avatar
 
Dries Buytaert committed
366

Dries Buytaert's avatar
   
Dries Buytaert committed
367
368
369
/**
 * Generate a tabular listing of administrative functions for vocabularies.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
370
function taxonomy_overview() {
371
372
  $vid = arg(2);

373
  // Show all vocabularies, and a "view terms" link to the pagers.
374
  if (!$vid) {
375
    $header = array(t('Name'), t('Type'), array('data' => t('Operations'), 'colspan' => '2'));
376
377
    $vocabularies = taxonomy_get_vocabularies();
    foreach ($vocabularies as $vocabulary) {
378
379
      $types = array();
      foreach ($vocabulary->nodes as $type) {
380
        $node_type = node_get_name($type);
381
382
        $types[] = $node_type ? $node_type : $type;
      }
Dries Buytaert's avatar
Dries Buytaert committed
383
      $rows[] = array(check_plain($vocabulary->name), implode(', ', $types), l(t('edit vocabulary'), "admin/taxonomy/edit/vocabulary/$vocabulary->vid"), l(t('edit terms'), "admin/taxonomy/$vocabulary->vid"));
384
385
386
    }

    if (!$rows) {
387
      $rows[] = array(array('data' => t('No categories available.'), 'colspan' => '4', 'class' => 'message'));
388
389
    }
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
390

391
  // Show the vocabulary's terms with a pager.
392
  else {
393
394
395
    $destination = drupal_get_destination();

    $header = array(t('Name'), t('Operations'));
396
    $vocabulary = taxonomy_get_vocabulary($vid);
397

Dries Buytaert's avatar
Dries Buytaert committed
398
399
400
401
402
403
404
405
406
407
    drupal_set_title(check_plain($vocabulary->name));
    $start_from      = $_GET['page'] ? $_GET['page'] : 0;
    $total_entries   = 0;  // total count for pager
    $page_increment  = 25; // number of tids per page
    $displayed_count = 0;  // number of tids shown

    $tree = taxonomy_get_tree($vocabulary->vid);
    foreach ($tree as $term) {
      $total_entries++; // we're counting all-totals, not displayed
      if (($start_from && ($start_from * $page_increment) >= $total_entries) || ($displayed_count == $page_increment)) { continue; }
408
      $rows[] = array(_taxonomy_depth($term->depth) . ' ' . l(check_plain($term->name), "taxonomy/term/$term->tid"), l(t('edit'), "admin/taxonomy/edit/term/$term->tid", array(), $destination));
Dries Buytaert's avatar
Dries Buytaert committed
409
410
411
412
413
414
      $displayed_count++; // we're counting tids displayed
    }

    if (!$rows) {
      $rows[] = array(array('data' => t('No terms available.'), 'colspan' => '2'));
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
415

Dries Buytaert's avatar
Dries Buytaert committed
416
417
    $GLOBALS['pager_page_array'][] = $start_from;  // FIXME
    $GLOBALS['pager_total'][] = intval($total_entries / $page_increment) + 1; // FIXME
418

Dries Buytaert's avatar
Dries Buytaert committed
419
420
    if ($total_entries >= $page_increment) {
      $rows[] = array(array('data' => theme('pager', NULL, $page_increment), 'colspan' => '2'));
421
    }
Dries Buytaert's avatar
   
Dries Buytaert committed
422
423
  }

424
  return theme('table', $header, $rows, array('id' => 'taxonomy'));
Kjartan Mannes's avatar
Kjartan Mannes committed
425
426
}

Dries Buytaert's avatar
   
Dries Buytaert committed
427
428
429
/**
 * Generate a form element for selecting terms from a vocabulary.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
430
function taxonomy_form($vid, $value = 0, $help = NULL, $name = 'taxonomy') {
Dries Buytaert's avatar
   
Dries Buytaert committed
431
  $vocabulary = taxonomy_get_vocabulary($vid);
432
  $help = ($help) ? $help : $vocabulary->help;
Kjartan Mannes's avatar
Kjartan Mannes committed
433
434
435
436
  if ($vocabulary->required) {
    $blank = 0;
  }
  else {
Dries Buytaert's avatar
   
Dries Buytaert committed
437
    $blank = '<'. t('none') .'>';
Kjartan Mannes's avatar
Kjartan Mannes committed
438
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
439

440
  return _taxonomy_term_select(check_plain($vocabulary->name), $name, $value, $vid, $help, intval($vocabulary->multiple), $blank);
Kjartan Mannes's avatar
Kjartan Mannes committed
441
}
Dries Buytaert's avatar
 
Dries Buytaert committed
442

443
/**
444
445
446
 * Generate a set of options for selecting a term from all vocabularies. Can be
 * passed to form_select.
 */
447
function taxonomy_form_all($free_tags = 0) {
448
449
450
  $vocabularies = taxonomy_get_vocabularies();
  $options = array();
  foreach ($vocabularies as $vid => $vocabulary) {
451
    if ($vocabulary->tags && !$free_tags) { continue; }
452
453
454
455
456
457
458
459
460
461
462
    $tree = taxonomy_get_tree($vid);
    $options[$vocabulary->name] = array();
    if ($tree) {
      foreach ($tree as $term) {
        $options[$vocabulary->name][$term->tid] = _taxonomy_depth($term->depth, '-') . $term->name;
      }
    }
  }
  return $options;
}

Dries Buytaert's avatar
   
Dries Buytaert committed
463
464
465
466
467
468
/**
 * Return an array of all vocabulary objects.
 *
 * @param $type
 *   If set, return only those vocabularies associated with this node type.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
469
function taxonomy_get_vocabularies($type = NULL) {
Kjartan Mannes's avatar
Kjartan Mannes committed
470
  if ($type) {
471
    $result = db_query(db_rewrite_sql("SELECT v.vid, v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", 'v', 'vid'), $type);
Kjartan Mannes's avatar
Kjartan Mannes committed
472
473
  }
  else {
474
    $result = db_query(db_rewrite_sql('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid ORDER BY v.weight, v.name', 'v', 'vid'));
Kjartan Mannes's avatar
Kjartan Mannes committed
475
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
476

Kjartan Mannes's avatar
Kjartan Mannes committed
477
  $vocabularies = array();
Dries Buytaert's avatar
   
Dries Buytaert committed
478
  $node_types = array();
Kjartan Mannes's avatar
Kjartan Mannes committed
479
  while ($voc = db_fetch_object($result)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
480
481
482
483
    $node_types[$voc->vid][] = $voc->type;
    unset($voc->type);
    $voc->nodes = $node_types[$voc->vid];
    $vocabularies[$voc->vid] = $voc;
Dries Buytaert's avatar
 
Dries Buytaert committed
484
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
485

Kjartan Mannes's avatar
Kjartan Mannes committed
486
487
  return $vocabularies;
}
Dries Buytaert's avatar
 
Dries Buytaert committed
488

Dries Buytaert's avatar
   
Dries Buytaert committed
489
490
491
/**
 * Generate a form for selecting terms to associate with a node.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
492
function taxonomy_node_form($type, $node = '', $help = NULL, $name = 'taxonomy') {
493
  if (!array_key_exists('taxonomy', $node)) {
Kjartan Mannes's avatar
Kjartan Mannes committed
494
    if ($node->nid) {
495
      $terms = taxonomy_node_get_terms($node->nid);
Kjartan Mannes's avatar
Kjartan Mannes committed
496
497
    }
    else {
498
      $terms = array();
Dries Buytaert's avatar
 
Dries Buytaert committed
499
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
500
501
502
503
  }
  else {
    $terms = $node->taxonomy;
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
504

505
  $c = db_query(db_rewrite_sql("SELECT v.*, n.type FROM {vocabulary} v INNER JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", 'v', 'vid'), $type);
Kjartan Mannes's avatar
Kjartan Mannes committed
506
  while ($vocabulary = db_fetch_object($c)) {
507
508
509
510
511
512
513
514
515
516
517
518
519
520
    if ($vocabulary->tags) {
      $typed_terms = array();
      foreach ($terms as $term) {
        if ($term->vid == $vocabulary->vid) {

          // Commas and quotes in terms are special cases, so encode 'em.
          if (preg_match('/,/', $term->name) || preg_match('/"/', $term->name)) {
            $term->name = '"'.preg_replace('/"/', '""', $term->name).'"';
          }

          $typed_terms[] = $term->name;
        }
      }
      $typed_string = implode(', ', $typed_terms) . (array_key_exists('tags', $terms) ? $terms['tags'][$vocabulary->vid] : NULL);
521

522

523
      $form[$name]['tags'][$vocabulary->vid] = array(type => textfield, default_value => $typed_string, size => 60, maxlength => 100, autocomplete_path => 'taxonomy/autocomplete/'. $vocabulary->vid, required => $vocabulary->required, title => $vocabulary->name, description => t('A comma-separated list of terms describing this content (Example: funny, bungie jumping, "Company, Inc.").'));
524
525
526
    }
    else {
      $ntterms = array_key_exists('taxonomy', $node) ? $terms : array_keys($terms);
527
      $form[$name][$vocabulary->vid] = taxonomy_form($vocabulary->vid, $ntterms, $help, $name);
528
529
530
531
532
533
      if ($vocabulary->multiple) {
        $form[$name][$vocabulary->vid][parents] = array($name);
      }
      else {
        $form[$name][$vocabulary->vid][tree] = TRUE;
      }
534
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
535
  }
536
  return $form ? $form : array();
Kjartan Mannes's avatar
Kjartan Mannes committed
537
}
Dries Buytaert's avatar
 
Dries Buytaert committed
538

Dries Buytaert's avatar
   
Dries Buytaert committed
539
540
541
542
/**
 * Find all terms associated to the given node, within one vocabulary.
 */
function taxonomy_node_get_terms_by_vocabulary($nid, $vid, $key = 'tid') {
543
  $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_data} t, {term_node} r WHERE t.tid = r.tid AND t.vid = %d AND r.nid = %d ORDER BY weight', 't', 'tid'), $vid, $nid);
Kjartan Mannes's avatar
Kjartan Mannes committed
544
545
546
  $terms = array();
  while ($term = db_fetch_object($result)) {
    $terms[$term->$key] = $term;
Dries Buytaert's avatar
 
Dries Buytaert committed
547
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
548
549
550
  return $terms;
}

Dries Buytaert's avatar
   
Dries Buytaert committed
551
/**
552
 * Find all terms associated to the given node, ordered by vocabulary and term weight.
Dries Buytaert's avatar
   
Dries Buytaert committed
553
554
 */
function taxonomy_node_get_terms($nid, $key = 'tid') {
Kjartan Mannes's avatar
Kjartan Mannes committed
555
  static $terms;
Dries Buytaert's avatar
 
Dries Buytaert committed
556

Dries Buytaert's avatar
   
Dries Buytaert committed
557
  if (!isset($terms[$nid])) {
558
    $result = db_query('SELECT t.* FROM {term_node} r INNER JOIN {term_data} t ON r.tid = t.tid INNER JOIN {vocabulary} v ON t.vid = v.vid WHERE r.nid = %d ORDER BY v.weight, t.weight, t.name', $nid);
Kjartan Mannes's avatar
Kjartan Mannes committed
559
    $terms[$nid] = array();
Dries Buytaert's avatar
 
Dries Buytaert committed
560
    while ($term = db_fetch_object($result)) {
Kjartan Mannes's avatar
Kjartan Mannes committed
561
      $terms[$nid][$term->$key] = $term;
Dries Buytaert's avatar
 
Dries Buytaert committed
562
563
    }
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
564
565
  return $terms[$nid];
}
Dries Buytaert's avatar
 
Dries Buytaert committed
566

567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
/**
 * Make sure incoming vids are free tagging enabled.
 */
function taxonomy_node_validate(&$node) {
  if ($node->taxonomy) {
    $terms = $node->taxonomy;
    if ($terms['tags']) {
      foreach ($terms['tags'] as $vid => $vid_value) {
        $vocabulary = taxonomy_get_vocabulary($vid);
        if (!$vocabulary->tags) {
          form_set_error("taxonomy[tags][$vid", t('The %name vocabulary can not be modified in this way.', array('%name' => theme('placeholder', $vocabulary->name))));
        }
      }
    }
  }
}

Dries Buytaert's avatar
   
Dries Buytaert committed
584
585
586
/**
 * Save term associations for a given node.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
587
function taxonomy_node_save($nid, $terms) {
588
  taxonomy_node_delete($nid);
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621

  // Free tagging vocabularies do not send their tids in the form,
  // so we'll detect them here and process them independently.
  if ($terms['tags']) {
    $typed_input = $terms['tags'];
    unset($terms['tags']);

    foreach ($typed_input as $vid => $vid_value) {
      // This regexp allows the following types of user input:
      // this, "somecmpany, llc", "and ""this"" w,o.rks", foo bar
      $regexp = '%(?:^|,\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^",]*))%x';
      preg_match_all($regexp, $vid_value, $matches);
      $typed_terms = $matches[1];

      foreach ($typed_terms as $typed_term) {
        // If a user has escaped a term (to demonstrate that it is a group,
        // or includes a comma or quote character), we remove the escape
        // formatting so to save the term into the DB as the user intends.
        $typed_term = str_replace('""', '"', preg_replace('/^"(.*)"$/', '\1', $typed_term));
        $typed_term = trim($typed_term);
        if ($typed_term == "") { continue; }

        // See if the term exists in the chosen vocabulary
        // and return the tid, otherwise, add a new record.
        $possibilities = taxonomy_get_term_by_name($typed_term);
        $typed_term_tid = NULL; // tid match if any.
        foreach ($possibilities as $possibility) {
          if ($possibility->vid == $vid) {
            $typed_term_tid = $possibility->tid;
          }
        }

        if (!$typed_term_tid) {
622
623
624
          $edit = array('vid' => $vid, 'name' => $typed_term);
          $status = taxonomy_save_term($edit);
          $typed_term_tid = $edit['tid'];
625
626
627
628
629
630
        }

        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $typed_term_tid);
      }
    }
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
631

632
  if (is_array($terms)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
633
    foreach ($terms as $term) {
634
635
636
637
638
639
640
      if (is_array($term)) {
        foreach ($term as $tid) {
          if ($tid) {
            db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $tid);
          }
        }
      }
641
      else if ($term) {
Dries Buytaert's avatar
   
Dries Buytaert committed
642
        db_query('INSERT INTO {term_node} (nid, tid) VALUES (%d, %d)', $nid, $term);
643
      }
Dries Buytaert's avatar
 
Dries Buytaert committed
644
645
    }
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
646
}
Dries Buytaert's avatar
 
Dries Buytaert committed
647

Dries Buytaert's avatar
   
Dries Buytaert committed
648
649
650
/**
 * Remove associations of a node to its terms.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
651
function taxonomy_node_delete($nid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
652
  db_query('DELETE FROM {term_node} WHERE nid = %d', $nid);
Kjartan Mannes's avatar
Kjartan Mannes committed
653
}
Dries Buytaert's avatar
 
Dries Buytaert committed
654

Dries Buytaert's avatar
   
Dries Buytaert committed
655
656
657
658
/**
 * Find all term objects related to a given term ID.
 */
function taxonomy_get_related($tid, $key = 'tid') {
Kjartan Mannes's avatar
Kjartan Mannes committed
659
  if ($tid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
660
    $result = db_query('SELECT t.*, tid1, tid2 FROM {term_relation}, {term_data} t WHERE (t.tid = tid1 OR t.tid = tid2) AND (tid1 = %d OR tid2 = %d) AND t.tid != %d ORDER BY weight, name', $tid, $tid, $tid);
Kjartan Mannes's avatar
Kjartan Mannes committed
661
662
663
    $related = array();
    while ($term = db_fetch_object($result)) {
      $related[$term->$key] = $term;
Dries Buytaert's avatar
 
Dries Buytaert committed
664
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
665
    return $related;
Dries Buytaert's avatar
 
Dries Buytaert committed
666
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
667
668
  else {
    return array();
Dries Buytaert's avatar
 
Dries Buytaert committed
669
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
670
}
Dries Buytaert's avatar
 
Dries Buytaert committed
671

Dries Buytaert's avatar
   
Dries Buytaert committed
672
673
674
675
/**
 * Find all parents of a given term ID.
 */
function taxonomy_get_parents($tid, $key = 'tid') {
Kjartan Mannes's avatar
Kjartan Mannes committed
676
  if ($tid) {
677
    $result = db_query(db_rewrite_sql('SELECT t.tid, t.* FROM {term_hierarchy} h, {term_data} t WHERE h.parent = t.tid AND h.tid = %d ORDER BY weight, name', 't', 'tid'), $tid);
Kjartan Mannes's avatar
Kjartan Mannes committed
678
679
680
    $parents = array();
    while ($parent = db_fetch_object($result)) {
      $parents[$parent->$key] = $parent;
Dries Buytaert's avatar
   
Dries Buytaert committed
681
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
682
    return $parents;
Dries Buytaert's avatar
 
Dries Buytaert committed
683
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
684
685
686
687
  else {
    return array();
  }
}
Dries Buytaert's avatar
 
Dries Buytaert committed
688

Dries Buytaert's avatar
   
Dries Buytaert committed
689
690
691
692
/**
 * Find all ancestors of a given term ID.
 */
function taxonomy_get_parents_all($tid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
693
694
695
696
697
698
699
700
701
702
703
704
  $parents = array();
  if ($tid) {
    $parents[] = taxonomy_get_term($tid);
    $n = 0;
    while ($parent = taxonomy_get_parents($parents[$n]->tid)) {
      $parents = array_merge($parents, $parent);
      $n++;
    }
  }
  return $parents;
}

Dries Buytaert's avatar
   
Dries Buytaert committed
705
706
707
708
/**
 * Find all children of a term ID.
 */
function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
Kjartan Mannes's avatar
Kjartan Mannes committed
709
  if ($vid) {
710
    $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_hierarchy} h, {term_data} t WHERE t.vid = %d AND h.tid = t.tid AND h.parent = %d ORDER BY weight, name', 't', 'tid'), $vid, $tid);
Dries Buytaert's avatar
 
Dries Buytaert committed
711
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
712
  else {
713
    $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_hierarchy} h, {term_data} t WHERE h.tid = t.tid AND parent = %d ORDER BY weight, name', 't', 'tid'), $tid);
Kjartan Mannes's avatar
Kjartan Mannes committed
714
715
716
717
718
719
720
  }
  $children = array();
  while ($term = db_fetch_object($result)) {
    $children[$term->$key] = $term;
  }
  return $children;
}
Dries Buytaert's avatar
 
Dries Buytaert committed
721

Dries Buytaert's avatar
   
Dries Buytaert committed
722
723
724
725
726
727
728
729
730
731
732
733
734
/**
 * 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 $depth
 *   Internal use only.
 *
Dries Buytaert's avatar
   
Dries Buytaert committed
735
736
737
 * @param $max_depth
 *   The number of levels of the tree to return. Leave NULL to return all levels.
 *
Dries Buytaert's avatar
   
Dries Buytaert committed
738
739
740
741
742
 * @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.
 */
function taxonomy_get_tree($vid, $parent = 0, $depth = -1, $max_depth = NULL) {
Dries Buytaert's avatar
   
Dries Buytaert committed
743
  static $children, $parents, $terms;
Dries Buytaert's avatar
   
Dries Buytaert committed
744

Kjartan Mannes's avatar
Kjartan Mannes committed
745
  $depth++;
Dries Buytaert's avatar
   
Dries Buytaert committed
746

Dries Buytaert's avatar
   
Dries Buytaert committed
747
748
749
750
  // 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's avatar
   
Dries Buytaert committed
751

752
    $result = db_query(db_rewrite_sql('SELECT t.tid, t.*, parent FROM {term_data} t, {term_hierarchy} h WHERE t.tid = h.tid AND t.vid = %d ORDER BY weight, name', 't', 'tid'), $vid);
Dries Buytaert's avatar
   
Dries Buytaert committed
753
    while ($term = db_fetch_object($result)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
754
755
756
      $children[$vid][$term->parent][] = $term->tid;
      $parents[$vid][$term->tid][] = $term->parent;
      $terms[$vid][$term->tid] = $term;
Dries Buytaert's avatar
 
Dries Buytaert committed
757
758
    }
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
759

Dries Buytaert's avatar
   
Dries Buytaert committed
760
  $max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;
Dries Buytaert's avatar
Dries Buytaert committed
761
762
763
764
765
766
767
768
769
770
771
772
  if ($children[$vid][$parent]) {
    foreach ($children[$vid][$parent] as $child) {
      if ($max_depth > $depth) {
        $terms[$vid][$child]->depth = $depth;
        // The "parent" attribute is not useful, as it would show one parent only.
        unset($terms[$vid][$child]->parent);
        $terms[$vid][$child]->parents = $parents[$vid][$child];
        $tree[] = $terms[$vid][$child];

        if ($children[$vid][$child]) {
          $tree = array_merge($tree, taxonomy_get_tree($vid, $child, $depth, $max_depth));
        }
Dries Buytaert's avatar
   
Dries Buytaert committed
773
      }
Dries Buytaert's avatar
   
Dries Buytaert committed
774
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
775
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
776

Dries Buytaert's avatar
   
Dries Buytaert committed
777
  return $tree ? $tree : array();
Kjartan Mannes's avatar
Kjartan Mannes committed
778
}
Dries Buytaert's avatar
 
Dries Buytaert committed
779

Dries Buytaert's avatar
   
Dries Buytaert committed
780
781
782
/**
 * Return an array of synonyms of the given term ID.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
783
784
function taxonomy_get_synonyms($tid) {
  if ($tid) {
Dries Buytaert's avatar
   
Dries Buytaert committed
785
    $result = db_query('SELECT name FROM {term_synonym} WHERE tid = %d', $tid);
Kjartan Mannes's avatar
Kjartan Mannes committed
786
    while ($synonym = db_fetch_array($result)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
787
      $synonyms[] = $synonym['name'];
Dries Buytaert's avatar
 
Dries Buytaert committed
788
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
789
    return $synonyms ? $synonyms : array();
Dries Buytaert's avatar
 
Dries Buytaert committed
790
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
791
792
  else {
    return array();
Dries Buytaert's avatar
   
Dries Buytaert committed
793
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
794
}
Dries Buytaert's avatar
   
Dries Buytaert committed
795

Dries Buytaert's avatar
   
Dries Buytaert committed
796
797
798
799
800
/**
 * Return the term object that has the given string as a synonym.
 */
function taxonomy_get_synonym_root($synonym) {
  return db_fetch_object(db_query("SELECT * FROM {term_synonym} s, {term_data} t WHERE t.tid = s.tid AND s.name = '%s'", $synonym));
Kjartan Mannes's avatar
Kjartan Mannes committed
801
}
Dries Buytaert's avatar
   
Dries Buytaert committed
802

Dries Buytaert's avatar
   
Dries Buytaert committed
803
804
805
/**
 * Given a term id, count the number of published nodes in it.
 */
Dries Buytaert's avatar
   
Dries Buytaert committed
806
function taxonomy_term_count_nodes($tid, $type = 0) {
Kjartan Mannes's avatar
Kjartan Mannes committed
807
  static $count;
Dries Buytaert's avatar
   
Dries Buytaert committed
808

Dries Buytaert's avatar
   
Dries Buytaert committed
809
810
811
  if (!isset($count[$type])) {
    // $type == 0 always evaluates true is $type is a string
    if (is_numeric($type)) {
812
      $result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t INNER JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 GROUP BY t.tid'));
Dries Buytaert's avatar
   
Dries Buytaert committed
813
814
    }
    else {
815
      $result = db_query(db_rewrite_sql("SELECT t.tid, COUNT(n.nid) AS c FROM {term_node} t, {node} n WHERE t.nid = n.nid AND n.status = 1 AND n.type = '%s' GROUP BY t.tid"), $type);
Dries Buytaert's avatar
   
Dries Buytaert committed
816
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
817
    while ($term = db_fetch_object($result)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
818
      $count[$type][$term->tid] = $term->c;
Dries Buytaert's avatar
   
Dries Buytaert committed
819
820
821
    }
  }

Kjartan Mannes's avatar
Kjartan Mannes committed
822
  foreach (_taxonomy_term_children($tid) as $c) {
Dries Buytaert's avatar
   
Dries Buytaert committed
823
    $children_count += taxonomy_term_count_nodes($c, $type);
Kjartan Mannes's avatar
Kjartan Mannes committed
824
  }
Dries Buytaert's avatar
   
Dries Buytaert committed
825
  return $count[$type][$tid] + $children_count;
Kjartan Mannes's avatar
Kjartan Mannes committed
826
827
}

Dries Buytaert's avatar
   
Dries Buytaert committed
828
829
830
/**
 * Helper for taxonomy_term_count_nodes().
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
831
832
function _taxonomy_term_children($tid) {
  static $children;
Dries Buytaert's avatar
   
Dries Buytaert committed
833

Dries Buytaert's avatar
   
Dries Buytaert committed
834
  if (!isset($children)) {
Dries Buytaert's avatar
   
Dries Buytaert committed
835
    $result = db_query('SELECT tid, parent FROM {term_hierarchy}');
Kjartan Mannes's avatar
Kjartan Mannes committed
836
837
    while ($term = db_fetch_object($result)) {
      $children[$term->parent][] = $term->tid;
Dries Buytaert's avatar
   
Dries Buytaert committed
838
    }
Dries Buytaert's avatar
 
Dries Buytaert committed
839
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
840
841
  return $children[$tid] ? $children[$tid] : array();
}
Dries Buytaert's avatar
 
Dries Buytaert committed
842

Dries Buytaert's avatar
   
Dries Buytaert committed
843
/**
Dries Buytaert's avatar
   
Dries Buytaert committed
844
 * Try to map a string to an existing term, as for glossary use.
Dries Buytaert's avatar
   
Dries Buytaert committed
845
 *
Dries Buytaert's avatar
   
Dries Buytaert committed
846
847
848
849
850
851
852
853
 * 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.
Dries Buytaert's avatar
   
Dries Buytaert committed
854
855
 */
function taxonomy_get_term_by_name($name) {
856
  $db_result = db_query(db_rewrite_sql("SELECT t.tid, t.* FROM {term_data} t WHERE LOWER('%s') LIKE LOWER(name)", 't', 'tid'), trim($name));
Dries Buytaert's avatar
   
Dries Buytaert committed
857
858
859
860
861
862
863
864
  $result = array();
  while ($term = db_fetch_object($db_result)) {
    $result[] = $term;
  }

  return $result;
}

Dries Buytaert's avatar
   
Dries Buytaert committed
865
866
867
/**
 * Return the vocabulary object matching a vocabulary ID.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
868
function taxonomy_get_vocabulary($vid) {
869
  $result = db_query('SELECT v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE v.vid = %d ORDER BY v.weight, v.name', $vid);
Dries Buytaert's avatar
   
Dries Buytaert committed
870
871
872
873
874
875
876
877
878
  $node_types = array();
  while ($voc = db_fetch_object($result)) {
    $node_types[] = $voc->type;
    unset($voc->type);
    $voc->nodes = $node_types;
    $vocabulary = $voc;
  }

  return $vocabulary;
Kjartan Mannes's avatar
Kjartan Mannes committed
879
}
Dries Buytaert's avatar
 
Dries Buytaert committed
880

Dries Buytaert's avatar
   
Dries Buytaert committed
881
882
883
/**
 * Return the term object matching a term ID.
 */
Kjartan Mannes's avatar
Kjartan Mannes committed
884
885
function taxonomy_get_term($tid) {
  // simple cache using a static var?
Dries Buytaert's avatar
   
Dries Buytaert committed
886
  return db_fetch_object(db_query('SELECT * FROM {term_data} WHERE tid = %d', $tid));
Kjartan Mannes's avatar
Kjartan Mannes committed
887
}
Dries Buytaert's avatar
 
Dries Buytaert committed
888

Kjartan Mannes's avatar
Kjartan Mannes committed
889
function _taxonomy_term_select($title, $name, $value, $vocabulary_id, $description, $multiple, $blank, $exclude = array()) {
Dries Buytaert's avatar
   
Dries Buytaert committed
890
  $tree = taxonomy_get_tree($vocabulary_id);
891
892
  $options = array();

Dries Buytaert's avatar
Dries Buytaert committed
893
  if ($blank) {
894
    $options[0] = $blank;
Dries Buytaert's avatar
Dries Buytaert committed
895
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
896
897
898
  if ($tree) {
    foreach ($tree as $term) {
      if (!in_array($term->tid, $exclude)) {
899
        $options[$term->tid] = _taxonomy_depth($term->depth, '-') . $term->name;
Dries Buytaert's avatar
 
Dries Buytaert committed
900
901
      }
    }
Kjartan Mannes's avatar
Kjartan Mannes committed
902
903
904
905
906
    if (!$blank && !$value) {
      // required but without a predefined value, so set first as predefined
      $value = $tree[0]->tid;
    }
  }
907
  return array(type => 'select', title => $title, default_value => $value, options => $options, description => $description, multiple => $multiple, size => $multiple ? 'size="'. min(12, count($options)) .'"' : 0, weight => -15);
Kjartan Mannes's avatar
Kjartan Mannes committed
908
}
Dries Buytaert's avatar
 
Dries Buytaert committed
909

Kjartan Mannes's avatar
Kjartan Mannes committed
910
911
912
function _taxonomy_depth($depth, $graphic = '--') {
  for ($n = 0; $n < $depth; $n++) {
    $result .= $graphic;
Dries Buytaert's avatar
 
Dries Buytaert committed
913
  }
Kjartan Mannes's avatar
Kjartan Mannes committed
914
915
  return $result;
}
Dries Buytaert's avatar
 
Dries Buytaert committed
916

Dries Buytaert's avatar