taxonomy.module 27.8 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
Dries's avatar
   
Dries committed
2
3
4
5
6
7
8
9
10
11

  function taxonomy_feed() {
    global $id, $or, $and, $type;

    if ($type == "voc") {
      //TODO - vocabulary feed. How to represent an outline in XML?
    }
    else {
      if ($or) {
        foreach ((explode(",", $or)) as $t) {
Kjartan's avatar
Kjartan committed
12
          $terms[] = "'". check_query($t) ."'";
Dries's avatar
   
Dries committed
13
        }
Kjartan's avatar
Kjartan committed
14
        $result = db_query("SELECT DISTINCT(n.nid), type FROM node n LEFT JOIN term_node r ON n.nid = r.nid WHERE tid IN (". implode(",", $terms) .") AND status = '1' ORDER BY static DESC, created DESC LIMIT 15");
Dries's avatar
   
Dries committed
15
16
17
18
        $term = taxonomy_get_term($or);
      }
      else if ($and) {
        foreach ((explode(",", $and)) as $t) {
Kjartan's avatar
Kjartan committed
19
          $terms[] = "'". check_query($t) ."'";
Dries's avatar
   
Dries committed
20
        }
Kjartan's avatar
Kjartan committed
21
        $result = db_query("SELECT n.nid, type, count(*) AS c FROM node n LEFT JOIN term_node r ON n.nid = r.nid WHERE tid IN (". implode(",", $terms) .")  AND status = '1' GROUP BY n.nid HAVING c = ". count($terms) ." ORDER BY static DESC, created DESC LIMIT 15");
Dries's avatar
   
Dries committed
22
23
24
25
26
27
        $term = taxonomy_get_term($and);
      }
      else {
        return node_feed();
      }

Kjartan's avatar
Kjartan committed
28
29
      $channel["title"] = variable_get("site_name", "drupal") ." - ". $term->name;
      $channel["link"] = path_uri() ."index.php?or=$or";
Dries's avatar
   
Dries committed
30
31
32
33
34
35
      $channel["description"] = $term->description;

      node_feed($result, $channel);
    }
  }

Dries's avatar
 
Dries committed
36
37
38
39
40
41
  function taxonomy_perm() {
    return array("administer taxonomy");
  }

  function taxonomy_link($type) {
    if ($type == "admin" && user_access("administer taxonomy")) {
Dries's avatar
   
Dries committed
42
      $links[] = la(t("taxonomy"), array("mod" => "taxonomy"));
Dries's avatar
 
Dries committed
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    }

    return $links ? $links : array();
  }

/*
** admin pages (form, save, overview)
*/

  function taxonomy_form_vocabulary($edit = array()) {
    foreach (module_list() as $name) {
      if (module_hook($name, "node")) {
        $nodetypes[$name] = $name;
      }
    }

Kjartan's avatar
Kjartan committed
59
60
61
62
63
64
65
    $form .= form_textfield("Vocabulary name", "name", $edit["name"], 50, 64, "Required.  The name for this vocabulary.  Example: 'Topic'.");
    $form .= form_textarea("Description", "description", $edit["description"], 60, 5, "Optional.  Description of the vocabulary, can be used by modules.");
    $form .= form_select("Types", "types", explode(",", $edit["types"]), $nodetypes, "Required.  A list of node types you want to associate this vocabulary with.", "", 1);
    $form .= form_checkbox("Related terms", "relations", 1, $edit["relations"], "Optional. Allows ". la("related terms", array("mod" => "taxonomy", "op" => "help#relatedterms")) ." in this vocabulary.");
    $form .= form_select("Hierarchy", "hierarchy", $edit["hierarchy"], array("Disabled", "Single", "Multiple"), "Optional. Allows ". la("a tree-like hierarchy", array("mod" => "taxonomy", "op" => "help#hierarchy")) ." between terms of this vocabulary.", "", 0);
    $form .= form_checkbox("Multiple select", "multiple", 1, $edit["multiple"], "Optional. Allows nodes to have more than one term in this vocabulary.");
    $form .= form_checkbox("Required", "required", 1, $edit["required"], "If enabled every node <b>must</b> have at least one term in this vocabulary");
Dries's avatar
 
Dries committed
66
67
68
    $form .= form_textfield("Weight", "weight", $edit["weight"], 3, 3, "Optional. In listings, the heavier vocabularies will sink and the lighter vocabularies will be positioned nearer the top.");
    $form .= form_submit("Submit");

Kjartan's avatar
Kjartan committed
69
    if ($edit["vid"]) {
Dries's avatar
 
Dries committed
70
      $form .= form_submit("Delete");
Kjartan's avatar
Kjartan committed
71
      $form .= form_hidden("vid", $edit["vid"]);
Dries's avatar
 
Dries committed
72
73
74
75
76
77
    }

    return form($form);
  }

  function taxonomy_save_vocabulary($edit) {
Kjartan's avatar
Kjartan committed
78
79
    $data = array("name" => $edit["name"], "types" => implode(",", $edit["types"]), "description" => $edit["description"], "multiple" => $edit["multiple"], "required" => $edit["required"], "hierarchy" => $edit["hierarchy"], "relations" => $edit["relations"], "weight" => $edit["weight"]);

Dries's avatar
 
Dries committed
80
    if ($edit["vid"] && $edit["name"]) {
Kjartan's avatar
Kjartan committed
81
      db_query("UPDATE vocabulary SET ". _prepare_update($data) ." WHERE vid = '". check_input($edit["vid"]) ."'");
Dries's avatar
 
Dries committed
82
83
84
85
86
    }
    else if ($edit["vid"]) {
      taxonomy_del_vocabulary($edit["vid"]);
    }
    else {
Kjartan's avatar
Kjartan committed
87
      db_query("INSERT INTO vocabulary ". _prepare_insert($data, 1) ." VALUES ". _prepare_insert($data, 2));
Dries's avatar
 
Dries committed
88
89
90
91
    }
  }

  function taxonomy_del_vocabulary($vid) {
Dries's avatar
   
Dries committed
92
93
    db_query("DELETE FROM vocabulary WHERE vid = '%s'", $vid);
    $result = db_query("SELECT tid FROM term_data WHERE vid = '%s'", $vid);
Dries's avatar
 
Dries committed
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
    while ($term = db_fetch_object($result)) {
      taxonomy_del_term($term->tid);
    }
  }

  function taxonomy_form_term($edit = array()) {
    global $vocabulary_id;
    if (!$vocabulary_id) {
      $vocabulary_id = $edit["vid"];
    }
    $vocabulary = taxonomy_get_vocabulary($vocabulary_id);
    $form .= form_textfield("Term name", "name", $edit["name"], 50, 64, "Required.  The name for this term.  Example: 'Linux'.");
    $form .= form_textarea("Description", "description", $edit["description"], 60, 5, "Optional.  Description of the term, can be used by modules.");

    if ($vocabulary->relations) {
Dries's avatar
   
Dries committed
109
      $form .= _taxonomy_term_select("Related terms", "relations", array_keys(taxonomy_get_related($edit["tid"])), $vocabulary_id, "Optional.", 1, "<none>", array($edit["tid"]));
Dries's avatar
 
Dries committed
110
111
112
113
114
115
    }


    if ($vocabulary->hierarchy) {
      $parent = array_keys(taxonomy_get_parents($edit["tid"]));
      taxonomy_get_tree($vocabulary_id, $children, $edit["tid"]);
Dries's avatar
   
Dries committed
116
      // you can't be son of yourself or your children
Dries's avatar
 
Dries committed
117
118
119
      $exclude = array_keys($children);
      $exclude[] = $edit["tid"];
      if ($vocabulary->hierarchy == 1) {
Kjartan's avatar
Kjartan committed
120
121
122
123
        $form .= _taxonomy_term_select("Parent", "parent", $parent, $vocabulary_id, "Required. ". la("Parent term", array("mod" => "taxonomy", "op" => "help#parent")) .".", 0, "<root>", $exclude);
      }
      elseif ($vocabulary->hierarchy == 2) {
        $form .= _taxonomy_term_select("Parents", "parent", $parent, $vocabulary_id, "Required. ". la("Parent terms", array("mod" => "taxonomy", "op" => "help#parent")) .".", 1, "<root>", $exclude);
Dries's avatar
 
Dries committed
124
125
126
      }
    }

Kjartan's avatar
Kjartan committed
127
    $form .= form_textarea("Synonyms", "synonyms", implode("\n", taxonomy_get_synonyms($edit["tid"])), 30, 5, "Optional. ". la("Synonyms", array("mod" => "taxonomy", "op" => "help#synonyms")) ." of this term, one synonym per line.");
Dries's avatar
 
Dries committed
128
129
130
131
132
133
134
135
136
137
138
139
140
141
    $form .= form_textfield("Weight", "weight", $edit["weight"], 3, 3, "Optional. In listings, the heavier terms will sink and the lighter terms will be positioned nearer the top.");
    $form .= form_hidden("vid", $vocabulary->vid);
    $form .= form_submit("Submit");

    if ($edit["tid"]) {
      $form .= form_submit("Delete");
      $form .= form_hidden("tid", $edit["tid"]);
    }

    return form($form);
  }

  function taxonomy_save_term($edit) {
   if ($edit["tid"] && $edit["name"]) {
Kjartan's avatar
Kjartan committed
142
      $data = array("name" => $edit["name"], "description" => $edit["description"], "weight" => $edit["weight"]);
Dries's avatar
 
Dries committed
143

Kjartan's avatar
Kjartan committed
144
      db_query("UPDATE term_data SET ". _prepare_update($data) ." WHERE tid = '%s'", $edit["tid"]);
Dries's avatar
 
Dries committed
145
146
147
148
149
150
151
152
153
154
    }
    else if ($edit["tid"]) {
      taxonomy_del_term($edit["tid"]);
    }
    else {
      $edit["tid"] = db_result(db_query("SELECT MAX(tid) + 1 FROM term_data"));
      if (!$edit["tid"]) {
        // first term
        $edit["tid"] = 1;
      }
Kjartan's avatar
Kjartan committed
155
156
      $data = array("tid" => $edit["tid"], "name" => $edit["name"], "description" => $edit["description"], "vid" => $edit["vid"], "weight" => $edit["weight"]);
      db_query("INSERT INTO term_data ". _prepare_insert($data, 1) ." VALUES ". _prepare_insert($data, 2));
Dries's avatar
 
Dries committed
157
158
159
    }

    // relations (seem very powerful, but I have to understand it completely)
Dries's avatar
   
Dries committed
160
    db_query("DELETE FROM term_relation WHERE tid1 = '%s' OR tid2 = '%s'", $edit["tid"], $edit["tid"]);
Dries's avatar
 
Dries committed
161
162
163
    if ($edit["relations"]) {
      foreach ($edit["relations"] as $related_id) {
        if ($related_id != 0) {
Dries's avatar
   
Dries committed
164
          $rel_q[] = "('". check_query($edit["tid"]) ."', '". check_query($related_id) ."')";
Dries's avatar
 
Dries committed
165
166
167
168
169
170
171
172
173
        }
      }
      if ($rel_q) {
        $related_query = implode(", ", $rel_q);
        db_query("INSERT INTO term_relation (tid1, tid2) VALUES $related_query");
      }
    }

    // hierarchy
Dries's avatar
   
Dries committed
174
    db_query("DELETE FROM term_hierarchy WHERE tid = '%s'", $edit["tid"]);
Dries's avatar
 
Dries committed
175
176
177
178
179
    if (!isset($edit["parent"])) {
      $edit["parent"] = 0;
    }
    if (is_array($edit["parent"])) {
      foreach ($edit["parent"] as $parent) {
Dries's avatar
   
Dries committed
180
        $sql[] = "('". check_query($edit["tid"]) ."', '". check_query($parent) ."')";
Dries's avatar
 
Dries committed
181
      }
Kjartan's avatar
Kjartan committed
182
183
184
      db_query("INSERT INTO term_hierarchy (tid, parent) VALUES ". implode(", ", $sql));
    }
    else {
Dries's avatar
   
Dries committed
185
      db_query("INSERT INTO term_hierarchy (tid, parent) VALUES ('%s', '%s')", $edit["tid"], $edit["parent"][0]);
Dries's avatar
 
Dries committed
186
187
188
    }

    // synonyms (very cool idea indeed)
Dries's avatar
   
Dries committed
189
    db_query("DELETE FROM term_synonym WHERE tid = '%s'", $edit["tid"]);
Dries's avatar
 
Dries committed
190
191
    if ($edit["synonyms"]) {
      foreach (explode ("\n", $edit["synonyms"]) as $synonym) {
Dries's avatar
   
Dries committed
192
        $syn_q[] = "('". check_query($edit["tid"]) ."', '". check_query(chop($synonym)) ."')";
Dries's avatar
 
Dries committed
193
194
195
196
197
198
199
      }
      $synonyms_query = implode(", ", $syn_q);
      db_query("INSERT INTO term_synonym (tid, name) VALUES $synonyms_query");
    }
  }

  function taxonomy_del_term($tid) {
Dries's avatar
   
Dries committed
200
201
202
203
204
    db_query("DELETE FROM term_data WHERE tid = '%s'", $tid);
    db_query("DELETE FROM term_hierarchy WHERE tid = '%s'", $tid);
    db_query("DELETE FROM term_relation WHERE tid1 = '%s' OR tid2 = '%s'", $tid, $tid);
    db_query("DELETE FROM term_synonym WHERE tid = '%s'", $tid);
    db_query("DELETE FROM term_node WHERE tid = '%s'", $tid);
Dries's avatar
 
Dries committed
205
206
207
208
209
210
211
212
213
214
215
  }

  function taxonomy_overview() {
    global $tree;

    $output .= "<h3>vocabularies overview</h3>";
    $output .= "<table border=\"1\" cellpadding=\"2\" cellspacing=\"2\">\n";
    $output .= " <tr><th>name</th><th>node types</th><th>operations</th></tr>\n";

    $vocabularies = taxonomy_get_vocabularies();
    foreach ($vocabularies as $vocabulary) {
Dries's avatar
   
Dries committed
216
217
218
219
      $links[] = la(t("edit vocabulary"), array("mod" => "taxonomy", "type" => "vocabulary", "op" => "edit", "id" => $vocabulary->vid));
      $links[] = la(t("add term"), array("mod" => "taxonomy", "op" => "add", "type" => "leaf", "vocabulary_id" => $vocabulary->vid));
      $links[] = la(t("preview form"), array("mod" => "taxonomy", "type" => "vocabulary", "op" => "preview", "id" => $vocabulary->vid));

Kjartan's avatar
Kjartan committed
220
      $output .= " <tr><td>". check_output($vocabulary->name) ."</td><td>". check_output($vocabulary->types) ."</td><td>". implode(" | ", $links) ."</td></tr>\n";
Dries's avatar
 
Dries committed
221
222
223
224
225
226

      unset($tree);
      taxonomy_get_tree($vocabulary->vid, $tree);
      if ($tree) {
        $output .= "<tr><td colspan=\"3\"><table><tr><td>";
        foreach ($tree as $term) {
Kjartan's avatar
Kjartan committed
227
          $output .= "<tr><td>". la(_taxonomy_depth($term->depth).check_output($term->name), array("mod" => "taxonomy", "op" => "edit", "type" => "term", "id" => check_output($term->tid))) ."</td></tr>";
Dries's avatar
 
Dries committed
228
229
230
231
232
233
234
235
236
237
238
239
240
241
        }
        $output .= "</td></tr></table></td></tr>\n";
      }
    }
    $output .= "</table>\n";

    return $output;
  }

  function taxonomy_form($vocabulary_id, $value = 0) {
    $vocabulary = taxonomy_get_vocabulary($vocabulary_id);
    if ($vocabulary->required) {
      $verb = "must";
      $blank = 0;
Kjartan's avatar
Kjartan committed
242
243
    }
    else {
Dries's avatar
 
Dries committed
244
245
246
247
248
249
      $verb = "can";
      $blank = "<none>";
    }
    if ($vocabulary->multiple) {
      $description = "You $verb choose one or more terms for this node";
      $multiple = 1;
Kjartan's avatar
Kjartan committed
250
251
    }
    else {
Dries's avatar
 
Dries committed
252
253
254
255
256
257
258
259
260
261
262
263
264
      $description = "You $verb choose one term for this node";
      $multiple = 0;
    }
    return _taxonomy_term_select($vocabulary->name, "taxonomy", $value, $vocabulary_id, $description, $multiple, $blank);
  }

/*
** API functions
*/

  // return array of vocabularies, as objects
  function taxonomy_get_vocabularies($type = '', $key = "vid") {
    if ($type) {
Dries's avatar
   
Dries committed
265
      $result = db_query("SELECT * FROM vocabulary WHERE types LIKE '%%%s%%' ORDER BY weight, name", $type);
Kjartan's avatar
Kjartan committed
266
267
    }
    else {
Dries's avatar
 
Dries committed
268
269
270
271
272
273
274
275
276
277
278
279
280
281
      $result = db_query("SELECT * FROM vocabulary ORDER BY weight, name");
    }
    $vocabularies = array();
    while ($voc = db_fetch_object($result)) {
      $vocabularies[$voc->$key] = $voc;
    }
    return $vocabularies;
  }

  // return form with current term
  function taxonomy_node_form($type, $node = '') {
    if (!$node->taxonomy) {
      if ($node->nid) {
        $terms = array_keys(taxonomy_node_get_terms($node->nid));
Kjartan's avatar
Kjartan committed
282
283
      }
      else {
Dries's avatar
 
Dries committed
284
285
        $terms = 0;
      }
Kjartan's avatar
Kjartan committed
286
287
    }
    else {
Dries's avatar
 
Dries committed
288
289
290
      $terms = $node->taxonomy;
    }

Dries's avatar
   
Dries committed
291
    $c = db_query("SELECT * FROM vocabulary WHERE types LIKE '%%%s%%' ORDER BY weight, name", $type);
Dries's avatar
 
Dries committed
292
293
294
    while ($vocabulary = db_fetch_object($c)) {
      $result[] .= taxonomy_form($vocabulary->vid, $terms);
    }
295
    return $result ? $result : array();
Dries's avatar
 
Dries committed
296
297
298
299
  }

  // return 1 if node identified by $nid contains a taxonomy term identified by $tid in his body or title
  function taxonomy_node_has_term($nid, $tid) {
Dries's avatar
   
Dries committed
300
    $term_name = db_result(db_query("SELECT name FROM term_data WHERE tid = '%s'", $tid));
Dries's avatar
 
Dries committed
301

Dries's avatar
   
Dries committed
302
    return db_result(db_query("SELECT COUNT(n.nid) FROM node n WHERE n.nid = '%s' AND ((n.body LIKE '%%%s%%') OR (n.body LIKE '%%%s%%'))", $nid, $term_name, $term_name));
Dries's avatar
 
Dries committed
303
304
305
306
  }

  // return array of terms of a node beloging to a particular vocabulary identified by $vid
  function taxonomy_node_get_terms_by_vocabulary($nid, $vid, $key = "tid") {
Dries's avatar
   
Dries committed
307
    $result = db_query("SELECT t.* FROM term_data t, term_node r WHERE t.tid = r.tid AND t.vid = '%s' AND r.nid = '%s' ORDER BY weight", $vid, $nid);
Dries's avatar
 
Dries committed
308
309
310
311
312
313
314
315
316
317
318
319
    $terms = array();
    while ($term = db_fetch_object($result)) {
      $terms[$term->$key] = $term;
    }
    return $terms;
  }

  // return array of terms of a node
  function taxonomy_node_get_terms($nid, $key = "tid") {
    static $terms;

    if (!$terms[$nid]) {
Dries's avatar
   
Dries committed
320
      $result = db_query("SELECT t.* FROM term_data t, term_node r WHERE r.tid = t.tid AND r.nid = '%s' ORDER BY weight", $nid);
Dries's avatar
 
Dries committed
321
322
323
324
325
326
327
328
329
330
331
332
333
334
      $terms[$nid] = array();
      while ($term = db_fetch_object($result)) {
        $terms[$nid][$term->$key] = $term;
      }
    }
    return $terms[$nid];
  }

  // save terms of a node
  function taxonomy_node_save($nid, $terms) {
    taxonomy_node_delete($nid);

    if ($terms) {
      foreach ($terms as $t) {
Kjartan's avatar
Kjartan committed
335
        $query[] = "('". check_query($nid) ."', '". check_query($t) ."')";
Dries's avatar
 
Dries committed
336
      }
Kjartan's avatar
Kjartan committed
337
      db_query("INSERT INTO term_node (nid, tid) VALUES ". implode(", ", $query));
Dries's avatar
 
Dries committed
338
339
340
341
342
    }
  }

  // clean up terms
  function taxonomy_node_delete($nid) {
Dries's avatar
   
Dries committed
343
    db_query("DELETE FROM term_node WHERE nid = '%s'", $nid);
Dries's avatar
 
Dries committed
344
345
346
347
348
  }

  // relations: return array of related terms
  function taxonomy_get_related($tid, $key = "tid") {
    if ($tid) {
Dries's avatar
   
Dries committed
349
      $result = db_query("SELECT t.*, tid1, tid2 FROM term_relation, term_data t WHERE (t.tid = tid1 OR t.tid = tid2) AND (tid1 = '%s' OR tid2 = '%s') ORDER BY weight", $tid, $tid);
Dries's avatar
 
Dries committed
350
351
352
353
354
355
356
357
      $related = array();
      while ($term = db_fetch_object($result)) {
        $related[$term->$key] = $term;
      }
      return $related;
    }
  }

Dries's avatar
   
Dries committed
358
  // hierarchy: get parent terms
Dries's avatar
 
Dries committed
359
360
  function taxonomy_get_parents($tid, $key = "tid") {
    if ($tid) {
Dries's avatar
   
Dries committed
361
      $result = db_query("SELECT t.* FROM term_hierarchy h, term_data t WHERE h.parent = t.tid AND h.tid = '%s' ORDER BY weight, name", $tid);
Dries's avatar
 
Dries committed
362
363
364
365
366
      $parents = array();
      while ($parent = db_fetch_object($result)) {
        $parents[$parent->$key] = $parent;
      }
      return $parents;
Kjartan's avatar
Kjartan committed
367
368
    }
    else {
Dries's avatar
 
Dries committed
369
370
371
372
373
374
375
      return array();
    }
  }

  // hierarchy: get children
  function taxonomy_get_children($tid, $vid = 0, $key = "tid") {
    if ($vid) {
Dries's avatar
   
Dries committed
376
      $result = db_query("SELECT t.* FROM term_hierarchy h, term_data t WHERE t.vid = '%s' AND h.tid = t.tid AND h.parent = '%s' ORDER BY weight, name", $vid, $tid);
Kjartan's avatar
Kjartan committed
377
378
    }
    else {
Dries's avatar
   
Dries committed
379
      $result = db_query("SELECT t.* FROM term_hierarchy h, term_data t WHERE h.tid = t.tid AND parent = '%s' ORDER BY weight", $tid);
Dries's avatar
 
Dries committed
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
    }
    $children = array();
    while ($term = db_fetch_object($result)) {
      $children[$term->$key] = $term;
    }
    return $children;
  }

  // hierarchy: get whole family, with tid, parent and depth; useful to show
  function taxonomy_get_tree($vocabulary_id, &$tree, $parent = 0, $depth = -1, $key = "tid") {
    static $children, $terms;
    if ($depth == -1) {
      $children = array();
      $tree = array();
      // $terms = array();   // we should be able to safely do this
    }
    $depth++;
    if ($vocabulary_id) {
      if (!$children) {
Dries's avatar
   
Dries committed
399
        $result = db_query("SELECT t.*, parent FROM term_data t, term_hierarchy h WHERE t.tid = h.tid AND t.vid = '%s' ORDER BY weight, name", $vocabulary_id);
Dries's avatar
 
Dries committed
400
401
402
403
404
405
406
407
        while ($term = db_fetch_object($result)) {
          $children[$term->parent][] = $term->tid;
          $terms[$term->tid] = $term;
        }
      }
      if ($children[$parent]) {
        foreach ($children[$parent] as $child) {
          $terms[$child]->depth = $depth;
Dries's avatar
   
Dries committed
408
          $tree[] = $terms[$child];
Dries's avatar
 
Dries committed
409
410
411
          taxonomy_get_tree($vocabulary_id, $tree, $child, $depth, $key);
        }
      }
Kjartan's avatar
Kjartan committed
412
413
    }
    else {
Dries's avatar
 
Dries committed
414
415
416
417
418
419
420
      return 0;
    }
  }

  // synonyms: return array of synonyms
  function taxonomy_get_synonyms($tid) {
    if ($tid) {
Dries's avatar
   
Dries committed
421
      $result = db_query("SELECT name FROM term_synonym WHERE tid = '%s'", $tid);
Dries's avatar
 
Dries committed
422
423
424
      while ($synonym = db_fetch_array($result)) {
        $synonyms[] = $synonym["name"];
      }
Dries's avatar
   
Dries committed
425
      return $synonyms ? $synonyms : array();
Kjartan's avatar
Kjartan committed
426
427
    }
    else {
Dries's avatar
   
Dries committed
428
      return array();
Dries's avatar
 
Dries committed
429
430
431
432
433
    }
  }

  // synonyms: return original term
  function taxonomy_get_synonym_root($term) {
Dries's avatar
   
Dries committed
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
    return db_fetch_object(db_query("SELECT * FROM term_synonym s, term_data t WHERE t.tid = s.tid AND s.name = '%s'", $term));
  }

  // given a term id, count number of nodes in it
  function taxonomy_term_count_nodes($tid) {
    static $count;

    if (!$count) {
      $result = db_query("SELECT tid, COUNT(*) AS c FROM term_node GROUP BY tid");
      while ($term = db_fetch_object($result)) {
        $count[$term->tid] = $term->c;
      }
    }

    foreach (_taxonomy_term_children($tid) as $c) {
      $children_count += taxonomy_term_count_nodes($c);
    }
    return $count[$tid] + $children_count;
  }

  // helper for above function
  function _taxonomy_term_children($tid) {
    static $children;

    if (!$children) {
      $result = db_query("SELECT tid, parent FROM term_hierarchy");
      while ($term = db_fetch_object($result)) {
        $children[$term->parent][] = $term->tid;
      }
    }
    return $children[$tid] ? $children[$tid] : array();
Dries's avatar
 
Dries committed
465
466
467
468
  }

  function taxonomy_get_vocabulary($vid) {
    // simple cache using a static var?
Dries's avatar
   
Dries committed
469
    return db_fetch_object(db_query("SELECT * FROM vocabulary WHERE vid = '%s'", $vid));
Dries's avatar
 
Dries committed
470
471
472
473
  }

  function taxonomy_get_term($tid) {
    // simple cache using a static var?
Dries's avatar
   
Dries committed
474
    return db_fetch_object(db_query("SELECT * FROM term_data WHERE tid = '%s'", $tid));
Dries's avatar
 
Dries committed
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
  }

/*
** service functions
*/

  function _taxonomy_term_select($title, $name, $value, $vocabulary_id, $description, $multiple, $blank, $exclude = array()) {
    taxonomy_get_tree($vocabulary_id, $tree);

    if ($blank) {
      $options[0] = $blank;
    }

    if ($tree) {
      foreach ($tree as $term) {
        if (!in_array($term->tid, $exclude)) {
          $options[$term->tid] = _taxonomy_depth($term->depth, '-').$term->name;
        }
      }
      if (!$blank && !$value) {
        // required but without a predefined value, so set first as predefined
        $value = $tree[0]->tid;
      }
    }

    if (count($options) > 0) {
      foreach ($options as $key=>$choice) {
        $select .= "<option value=\"$key\"". (is_array($value) ? (in_array($key, $value) ? " selected=\"selected\"" : "") : ($key == $value ? " selected=\"selected\"" : "")) .">". check_form($choice) ."</option>";
      }

      // min 8, possibly options/3 (set max too?)
      $size = max(8, round(count($options)) / 3);

Kjartan's avatar
Kjartan committed
508
      return form_item($title, "<select name=\"edit[$name][]\"". ($multiple ? " multiple size=\"$size\"" : "") . ($extra ? " $extra" : "") .">$select</select>", $description);
Dries's avatar
 
Dries committed
509
510
511
512
    }
  }

  function _taxonomy_depth($depth, $graphic = '--') {
Kjartan's avatar
Kjartan committed
513
    for ($n = 0; $n < $depth; $n++) {
Dries's avatar
 
Dries committed
514
515
516
517
518
519
520
      $result .= $graphic;
    }
    return $result;
  }

  function _prepare_update($data) {
    foreach ($data as $key => $value) {
Dries's avatar
   
Dries committed
521
      $q[] = "$key = '". check_query($value) ."'";
Dries's avatar
 
Dries committed
522
523
524
525
526
527
528
529
    }
    $result = implode(", ", $q);
    return $result;
  }

  function _prepare_insert($data, $stage) {
    if ($stage == 1) {
      $result = implode(", ", array_keys($data));
Kjartan's avatar
Kjartan committed
530
531
    }
    else {
Dries's avatar
 
Dries committed
532
      foreach (array_values($data) as $value) {
Dries's avatar
   
Dries committed
533
        $q[] = "'". check_query($value) ."'";
Dries's avatar
 
Dries committed
534
535
536
537
538
      }
      $result = implode(", ", $q);
    }
    return "($result)";
  }
Dries's avatar
   
Dries committed
539
540
541
542
543
544
545
546
547
548
549
550
551
552

  function taxonomy_page() {
    global $op;

    switch ($op) {
      case "feed":
        taxonomy_feed();
        break;
      default:
         // TODO: pretty display of all vocabularies
    }
  }

 /*
Dries's avatar
 
Dries committed
553
554
555
556
557
558
559
** admin
*/

  function taxonomy_admin() {
    global $edit, $type, $op, $id, $tree;

    if (user_access("administer taxonomy")) {
Dries's avatar
   
Dries committed
560
561
562
      $links[] = la(t("add new vocabulary"), array("mod" => "taxonomy", "op" => "add", "type" => "vocabulary"));
      $links[] = la(t("overview"), array("mod" => "taxonomy"));
      $links[] = la(t("help"), array("mod" => "taxonomy", "op" => "help"));
Dries's avatar
 
Dries committed
563

Kjartan's avatar
Kjartan committed
564
      print "<small>". implode(" | ", $links) ."</small><hr>\n";
Dries's avatar
 
Dries committed
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585

      switch ($op) {
        case "add":
          if ($type == "vocabulary")
            print taxonomy_form_vocabulary();
          else
            print taxonomy_form_term();
          break;
        case "edit":
          if ($type == "vocabulary")
            print taxonomy_form_vocabulary(object2array(taxonomy_get_vocabulary($id)));
          else
            print taxonomy_form_term(object2array(taxonomy_get_term($id)));
          break;
        case "preview":
            print taxonomy_form($id);
          break;
        case "help":
          print taxonomy_help();
          break;
        case "Delete":
Kjartan's avatar
Kjartan committed
586
          $edit["name"] = 0;
Dries's avatar
 
Dries committed
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
          // fall through:
        case "Submit":
          if ($type == "vocabulary")
            print status(taxonomy_save_vocabulary($edit));
          else
            print status(taxonomy_save_term($edit));
          // fall through:
        default:
          print taxonomy_overview();
      }
    }
    else {
      print message_access();
    }
  }

Dries's avatar
   
Dries committed
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  function taxonomy_help() {
    ?>
  <h3>Background</h3>
    Classifying nodes allows for the organization of content into categories and
    subcategories of description. These categories can be used to organize and retrieve
    similarly described content. Drupal's <i>taxonomy.module</i> is an extremely flexible
    classification system that allows for multiple lists of categories for classification
    (controlled vocabularies) and offers the possibility of creating thesauri (controlled
    vocabularies that indicate the relationship of terms) and taxonomies (controlled
    vocabularies where relationships are indicated hierarchically). For details about
  <a href="http://www.eleganthack.com/archives/002165.html#002165">classification
  types</a> and insight into the development of <i>taxonomy.module</i>, see this
  <a href="http://www.drupal.org/node.php?id=55">drupal.org discussion</a>.<br />
  <h3>An Example Taxonomy - Foods</h3>
Kjartan's avatar
Kjartan committed
617
618
619
620
621
622
623
624
625
626
627
  <p>Dairy <br />
    --Milk <br />
    Drink <br />
    --Alchohol <br />
    --Pop <br />
    --Milk<br />
    Meat <br />
    --Beef <br />
    --Chicken <br />
    --Lamb <br />
    Spices <br />
Dries's avatar
   
Dries committed
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
    --Sugar</p>
  <p><b>Notes</b></p>
  <ul>
    <li>The term <i>Milk</i> appears within both <i>Dairy</i> and <i>Drink</i>.
      This is an example of <i>Multiple Parents</i> for a term.</li>
    <li>The order of siblings (e.g. <i>Beef</i>, <i>Chicken</i>, <i>Lamb</i>) in
      the taxonomy may be controlled with the <i>Weight</i> parameter. </li>
  </ul>
  <h4></h4>
    <h3>Vocabularies</h3>
    When you create a controlled vocabulary you are creating a set of terms to use
    for describing content (known as descriptors in indexing lingo). Drupal allows
    you to describe each node of content (blog, story, etc.)
    using one or many of these terms. For simple implementations, you might
    create a set of categories without subcategories, similar to <a href="http://www.slashdot.com">Slashdot's</a> "Sections".
    For more complex implementations, you might create a hierarchical list of categories
    such as the example <i>Food</i> taxonomy above.

    <h4>Setting up a vocabulary</h4>
    <p>When you set up a controlled vocabulary, you will be asked to enter some descriptive
  data and define the attributes of this vocabulary. For example, if you select
  the <i>Hierarchy </i>option, you will be defining a taxonomy or a thesaurus. If
  you select <i>Related Terms</i> option, you are allowing the definition of related
  terms as in a thesaurus. Selecting <i>Multiple Select</i> will allow you to describe
  a node using more than one term. That node will then appear in each term's page,
  thus increasing the chance that a user will find it.</p>
    <i>Vocabulary name</i><br />
    Required. The name for this vocabulary. Example: <i>Dairy</i>.<br />
    <br />
    <i>Description</i><br />
    Optional. Description of the vocabulary, can be used by modules and feeds.<br />
    <br />
    <i>Types</i><br />
    Required. The list of node types you want to associate this vocabulary
    with. Some available types are: blog, book, forum, page, story.<br />
    <br />
    <i><a name="relatedterms"></a>Related Terms</i><br />
    Allows relationships between terms within this vocabulary. Think of these as
    <i>See also</i> references.<br />
    <br />
    <i><a name="hierarchy"></a>Hierarchy</i><br />
    Allows a tree-like taxonomy, as in our <i>Foods</i> example above<br />
    <br />
    <i>Multiple Select</i><br />
  Allows nodes to be described using more than one term. Nodes may then appear on
  multiple taxonomy pages.<br />
    <h4>Adding terms to a vocabulary</h4>
  The options you see when adding a term to a vocabulary will depend on what you
  selected for <i>Related Terms</i>, <i>Hierarchy </i>and <i>Multiple Select</i>
  when you created the corrosponding vocabulary.<br />
    <br />
  <i>Term name</i><br />
    Required. The name for this term. Example: <i>Milk</i><br />
    <br />
  <i>Description</i><br />
  Optional. Description of the term that may be used by modules and RSS feeds.
  This is synonymous with a 'Scope note'.<br />
    <br />
  <i><a name="parent"></a>Parent</i><br />
    Required. Select the term under which this term is a subset -- the branch of the hierarchy
    that this term belongs under. This is also known as the "Broader term" indicator
    used in thesauri.<br />
    <br />
  <i><a name="synonyms"></a>Synonyms</i><br />
    Optional. Enter synonyms for this term, one synonym per line. Synonyms can be used for
    variant spellings, acronyms, and other terms that have the same meaning as the
    added term, but which are not explicitly listed in this thesaurus (i.e. <i>unauthorized
    terms</i>).<br />

  <h3>Displaying Nodes Organized by Term(s)</h3>
  <p>In order to view the nodes associated with a term or a collection of terms, you
    should browse to a properly formed URL. For example, see
    <a href="<?php print path_uri().drupal_url(array("mod" => "node", "or" => "1,2"), "module"); ?>"><?php print path_uri().drupal_url(array("mod" => "node", "or" => "1,2"), "module"); ?></a>.
    Taxonomy URLs always contain  a termID or list of termIDs at the end of the URL (aka <i>querystring</i>).
     You may learn the termID for a given term by hovering over that term in the <? echo la("Taxonomy Overview", array("mod" => "taxonomy")) ?> page in the Admin and noting the number after the querystring parameter called <i>tid</i>.
     If you wish to see nodes from a collection of termIDs, separate each termID with a comma.
     Also, the name of the querystring parameter may be <i>or</i> or <i>and</i>.
     <i>or</i> shows nodes which appear in <b>any</b> of the termIDs while <i>and</i> shows nodes in <b>all</b> the specified termIDs.
      Thus, <i>or</i> is less specific than <i>and</i>.
  </p>

  <h3>RSS Feeds</h3>
  <p>Every term, or collection of terms, provides an <a href="http://backend.userland.com/stories/rss091">RSS</a> feed to which interested
    users may subscribe. The URL format for an sample RSS feed is
      <a href="<?php print path_uri().drupal_url(array("mod" => "node", "op" => "feed", "or" => "1,2"), "module"); ?>"><?php print path_uri().drupal_url(array("mod" => "node", "op" => "feed", "or" => "1,2"), "module"); ?></a>.</p>
      <?php
  }
Dries's avatar
 
Dries committed
715
?>