/[drupal]/contributions/modules/comment_alter_taxonomy/comment_alter_taxonomy.module
ViewVC logotype

Contents of /contributions/modules/comment_alter_taxonomy/comment_alter_taxonomy.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.17 - (show annotations) (download) (as text)
Tue Mar 24 00:39:32 2009 UTC (8 months ago) by dww
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +51 -10 lines
File MIME type: text/x-php
#389096 by dww: Instead of providing separate issue views by tag,
reuse the new taxonomy exposed filters on issue advanced search:
- Changed links for project_issue tags to point to the new URLs.
- Added code to redirect from legacy paths to the new URLs (there's an
  admin setting to enable this behavior).
- Removed the default issue tag listing views.
1 <?php
2 // $Id: comment_alter_taxonomy.module,v 1.16 2009/02/19 23:58:53 damz Exp $
3
4 /**
5 * @file
6 * Allows users with proper permissions to alter the taxonomy of a
7 * parent node from inside of a comment.
8 */
9
10 /**
11 * Implementation of hook_perm().
12 */
13 function comment_alter_taxonomy_perm() {
14 $perms = array();
15 $types = node_get_types();
16 foreach ($types as $type) {
17 $name = check_plain($type->type);
18 $perms[] = "alter taxonomy on $name content";
19 }
20 return $perms;
21 }
22
23 /**
24 * Implementation of hook_menu().
25 */
26 function comment_alter_taxonomy_menu($may_cache = TRUE) {
27 $items['admin/settings/comment_alter_taxonomy'] = array(
28 'title' => 'Comment alter taxonomy',
29 'description' => 'Enable/disable vocabularies that users may alter from their comments.',
30 'page callback' => 'drupal_get_form',
31 'page arguments' => array('comment_alter_taxonomy_admin_settings'),
32 'access arguments' => array('administer site configuration'),
33 );
34 $legacy = variable_get('comment_alter_taxonomy_legacy_issue_paths', FALSE);
35 if (module_exists('project_issue') && !empty($legacy)) {
36 $items['project/issues/%/term/%'] = array(
37 'title' => 'Issues for a project with a given term',
38 'page callback' => 'comment_alter_taxonomy_legacy_project_issue_redirect',
39 'page arguments' => array(4, 2),
40 'access arguments' => array('access content'),
41 'file' => 'comment_alter_taxonomy_legacy_pages.inc',
42 );
43 $items['project/issues-term/%'] = array(
44 'title' => 'Issues with a given term',
45 'page callback' => 'comment_alter_taxonomy_legacy_project_issue_redirect',
46 'page arguments' => array(2),
47 'access arguments' => array('access content'),
48 'file' => 'comment_alter_taxonomy_legacy_pages.inc',
49 );
50 }
51 return $items;
52 }
53
54 /**
55 * Administration settings form.
56 */
57 function comment_alter_taxonomy_admin_settings() {
58 $options = array();
59
60 // Get a list of all vocabularies in the system.
61 $vocabularies = taxonomy_get_vocabularies();
62 foreach ($vocabularies as $vid => $vocabulary) {
63 $options[$vid] = check_plain($vocabulary->name);
64 }
65
66 $form['comment_alter_taxonomy_vocabularies'] = array(
67 '#type' => 'checkboxes',
68 '#title' => t('Vocabularies that may be altered'),
69 '#options' => $options,
70 '#default_value' => array_filter(variable_get('comment_alter_taxonomy_vocabularies', array())),
71 );
72
73 if (module_exists('project_issue')) {
74 $form['project_issue'] = array(
75 '#type' => 'fieldset',
76 '#title' => t('Project issue support'),
77 '#collapsible' => TRUE,
78 '#collapsed' => TRUE,
79 );
80 $form['project_issue']['comment_alter_taxonomy_legacy_issue_paths'] = array(
81 '#type' => 'checkbox',
82 '#title' => t('Provide support for legacy project issue taxonomy listing paths'),
83 '#default_value' => variable_get('comment_alter_taxonomy_legacy_issue_paths', FALSE),
84 );
85 $form['#submit'][] = 'comment_alter_taxonomy_settings_submit';
86 }
87
88 return system_settings_form($form);
89 }
90
91 function comment_alter_taxonomy_settings_submit($form, $form_state) {
92 $current_value = variable_get('comment_alter_taxonomy_legacy_issue_paths', 'FALSE');
93 $form_value = $form_state['values']['comment_alter_taxonomy_legacy_issue_paths'];
94 if ($current_value != $form_value) {
95 // If the setting changed, record that and force a menu rebuild to ensure
96 // we have the right menu items defined based on the setting.
97 variable_set('comment_alter_taxonomy_legacy_issue_paths', $form_value);
98 menu_rebuild();
99 }
100 }
101
102 /**
103 * Implementation of hook_form_alter().
104 */
105 function comment_alter_taxonomy_form_alter(&$form, $form_state, $form_id) {
106 if ($form_id == 'comment_admin_overview') {
107 // {comment_alter_taxonomy} may need to be updated if any comments are edited/deleted.
108 $form['#submit'][] = 'comment_alter_taxonomy_comment_mass_update';
109 }
110 elseif (isset($form['type']['#value']) && $form['type']['#value'] .'_node_form' == $form_id && isset($form['nid']['#value'])) {
111 // Prevent user from changing the terms for any vocabulary that can be altered from a comment with this
112 // module.
113 if (isset($form['taxonomy'])) {
114 $alterable_vids = array_keys(comment_alter_taxonomy_get_alterable_vocabularies($form['type']['#value']));
115 foreach ($alterable_vids as $vid) {
116 if (isset($form['taxonomy'][$vid])) {
117 unset($form['taxonomy'][$vid]);
118 }
119 elseif (isset($form['taxonomy']['tags'][$vid])) {
120 unset($form['taxonomy']['tags'][$vid]);
121 }
122 }
123 }
124 }
125 elseif ($form_id == 'comment_form' && empty($form['cid']['#value'])) {
126 comment_alter_taxonomy_comment_form($form);
127 }
128 }
129
130 function comment_alter_taxonomy_comment_form(&$form) {
131 // Prepare some variables for later checking.
132 $node = node_load($form['nid']['#value']);
133 $access = user_access("alter taxonomy on ". check_plain($node->type) ." content");
134
135 $vocabularies = taxonomy_get_vocabularies($node->type);
136 $allowed = $access ? comment_alter_taxonomy_get_alterable_vocabularies($node->type) : array();
137
138 // We need to store the current taxonomy terms assigned to the node so that later,
139 // after form submission, we can add those terms that are currently assigned to the node but
140 // which the user is not given permission to alter in the comment back to the node.
141 // This is necessary because taxonomy_node_save() first deletes all terms on a node
142 // and then adds back those terms from the edit of the node.
143 foreach ($vocabularies as $vid => $vocabulary) {
144 _comment_alter_taxonomy_vocabulary_form($vocabulary, $node, $form, !isset($allowed[$vid]));
145 }
146
147 // Add fieldset only if form has more than 1 element.
148 if (count($allowed) > 1) {
149 $form['taxonomy'] += array(
150 '#type' => 'fieldset',
151 '#title' => t('Categories'),
152 '#collapsible' => TRUE,
153 '#collapsed' => FALSE,
154 );
155 }
156 $form['taxonomy']['#weight'] = -3;
157 $form['taxonomy']['#tree'] = TRUE;
158 }
159
160 /**
161 * Generate taxonomy form for a given vocabulary.
162 *
163 * This is kind of nasty; mostly a copy/paste of taxonomy_form_alter, which is
164 * a big glop of stuff.
165 *
166 * @param $vocabulary
167 * A vocabulary object.
168 * @param $node
169 * A node object.
170 * @param $form
171 * The form array onto which the vocabulary widget should be placed.
172 * @param $disabled
173 * Whether or not this widget should be disabled, for example if the user
174 * does not have the permission to alter terms for this vocabulary.
175 */
176 function _comment_alter_taxonomy_vocabulary_form($vocabulary, $node, &$form, $disabled = FALSE) {
177 // Determine existing term assignments, if any.
178 if (!isset($node->taxonomy)) {
179 if ($node->nid) {
180 $terms = taxonomy_node_get_terms($node);
181 }
182 else {
183 $terms = array();
184 }
185 }
186 else {
187 $terms = $node->taxonomy;
188 }
189
190 if ($vocabulary->tags) {
191 // Handle free-tagging vocabularies.
192 $typed_terms = array();
193 foreach ($terms as $term) {
194 // Extract terms belonging to the vocabulary in question.
195 if ($term->vid == $vocabulary->vid) {
196
197 // Commas and quotes in terms are special cases, so encode 'em.
198 if (strpos($term->name, ',') !== FALSE || strpos($term->name, '"') !== FALSE) {
199 $term->name = '"'. str_replace('"', '""', $term->name) .'"';
200 }
201
202 $typed_terms[] = $term->name;
203 }
204 }
205 $typed_string = implode(', ', $typed_terms) . (array_key_exists('tags', $terms) ? $terms['tags'][$vocabulary->vid] : NULL);
206
207 if ($vocabulary->help) {
208 $help = $vocabulary->help;
209 }
210 else {
211 $help = t('A comma-separated list of terms describing this content. Example: funny, bungee jumping, "Company, Inc.".');
212 }
213
214 $form['taxonomy']['tags'][$vocabulary->vid] = array(
215 '#type' => 'textfield',
216 '#title' => $vocabulary->name,
217 '#description' => $help,
218 '#required' => $vocabulary->required,
219 '#default_value' => $typed_string,
220 '#autocomplete_path' => 'taxonomy/autocomplete/'. $vocabulary->vid,
221 '#weight' => $vocabulary->weight,
222 '#maxlength' => 255,
223 '#tree' => TRUE,
224 );
225 if ($disabled) {
226 _comment_alter_taxonomy_disable_element($form['taxonomy']['tags'][$vocabulary->vid]);
227 }
228 }
229 else {
230 // Extract terms belonging to the vocabulary in question.
231 $default_terms = array();
232 foreach ($terms as $term) {
233 if ($term->vid == $vocabulary->vid) {
234 $default_terms[$term->tid] = $term;
235 }
236 }
237 $form['taxonomy'][$vocabulary->vid] = taxonomy_form($vocabulary->vid, array_keys($default_terms), $vocabulary->help);
238 if ($disabled) {
239 _comment_alter_taxonomy_disable_element($form['taxonomy'][$vocabulary->vid]);
240 }
241 $form['taxonomy'][$vocabulary->vid]['#weight'] = $vocabulary->weight;
242 $form['taxonomy'][$vocabulary->vid]['#required'] = $vocabulary->required;
243 $form['taxonomy'][$vocabulary->vid]['#tree'] = TRUE;
244 }
245 }
246
247 /**
248 * Recursively disable a form tree, transforming input element in value callbacks.
249 */
250 function _comment_alter_taxonomy_disable_element(&$element) {
251 if (isset($element['#type'])) {
252 if (isset($element['#default_value'])) {
253 $element['#type'] = 'value';
254 $element['#value'] = $element['#default_value'];
255 }
256 else {
257 unset($element['#type']);
258 }
259 unset($element['#theme']);
260 }
261 foreach (element_children($element) as $child) {
262 _comment_alter_taxonomy_disable_element($element[$child]);
263 }
264 }
265
266 /**
267 * Implementation of hook_comment().
268 */
269 function comment_alter_taxonomy_comment($arg, $op) {
270 // $arg can be a comment object, or a form or form_values.
271 switch ($op) {
272 case 'insert':
273 if (isset($arg['taxonomy'])) {
274 // Fetch the cid of the previous comment and store the tids of the current node if necessary.
275 $previous_cid = (int) db_result(db_query_range('SELECT cid FROM {comments} WHERE nid = %d AND cid < %d ORDER BY cid DESC', $arg['nid'], $arg['cid'], 0, 1));
276 $node = node_load($arg['nid']);
277 _comment_alter_taxonomy_save_tids($node, $previous_cid);
278
279 // Save the terms to the node itself.
280 taxonomy_node_save($node, $arg['taxonomy']);
281
282 // Load the node again so we can reset the internal node_load cache.
283 $node = node_load($arg['nid'], NULL, TRUE);
284
285 // Store the tids assigned to the node at this point to the {comment_alter_taxonomy} table.
286 _comment_alter_taxonomy_save_tids($node, $arg['cid']);
287 }
288 break;
289
290 case 'delete':
291 db_query("DELETE FROM {comment_alter_taxonomy} WHERE cid = %d", $arg->cid);
292 break;
293 }
294 }
295
296 /**
297 * Saves a record of the terms assigned to a given node and comment to the
298 * {comment_alter_taxonomy} database table. This function does
299 * not actually cause terms to be saved to the node itself, but
300 * saves a record of the terms assigned to a node at the time of a certain
301 * comment.
302 *
303 * @param $node
304 * The node for which to save the term.
305 * @param $cid
306 * The cid of the comment. Set this to 0 if this is the original
307 * node and not an actual comment.
308 */
309 function _comment_alter_taxonomy_save_tids($node, $cid) {
310 global $db_type;
311 if (!db_result(db_query_range("SELECT cid FROM {comment_alter_taxonomy} WHERE nid = %d AND cid = %d", $node->nid, $cid, 0, 1))) {
312 // Ignore is only supported on MySQL.
313 $ignore = $db_type == 'mysql' || $db_type == 'mysqli' ? 'IGNORE' : '';
314
315 // Insert a dummy tid = 0 to ensure the table contain at least one row for this comment.
316 // Insert is first, do reduce possible concurrency issue. That query can
317 // fail in case of concurrent insert in some cases, suppress error display.
318 @db_query("INSERT $ignore INTO {comment_alter_taxonomy} (nid, cid, tid) VALUES (%d, %d, %d)", $node->nid, $cid, 0);
319
320 // Insert the real terms.
321 @db_query("INSERT $ignore INTO {comment_alter_taxonomy} (nid, cid, tid) SELECT nid, %d, tid FROM {term_node} WHERE vid = %d", $cid, $node->vid);
322
323 // If the previous query actually inserted terms, remove the dummy tid = 0.
324 if (db_result(db_query_range("SELECT cid FROM {comment_alter_taxonomy} WHERE nid = %d AND cid = %d AND tid <> 0", $node->nid, $cid, 0, 1))) {
325 db_query("DELETE FROM {comment_alter_taxonomy} WHERE nid = %d AND cid = %d and tid = 0", $node->nid, $cid);
326 }
327 }
328 }
329
330 /**
331 * Find all terms associated with the given node, ordered by vocabulary and term weight.
332 *
333 * This is almost a direct copy from the taxonomy_node_get_terms() function except
334 * that it's possible to reset the static $terms variable so that changes to
335 * a node's taxonomy made in this module can be read back by other modules
336 * during the page load.
337 *
338 * @param $node
339 * The node.
340 * @param $key
341 * Key in the array to look for.
342 * @param $reset
343 * If set to true, terms for the specified $nid stored in the static cache will
344 * be ignored and the terms will be re-retrieved from the database.
345 * @return
346 * An array of terms associated with the given node, ordered by vocabulary
347 * and term weight.
348 */
349 function _comment_alter_taxonomy_taxonomy_node_get_terms($node, $key = 'tid', $reset = FALSE) {
350 static $terms;
351
352 if (!isset($terms[$node->vid][$key]) || $reset) {
353 $result = db_query(db_rewrite_sql('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.vid = %d ORDER BY v.weight, t.weight, t.name', 't', 'tid'), $node->vid);
354 $terms[$node->vid][$key] = array();
355 while ($term = db_fetch_object($result)) {
356 $terms[$node->vid][$key][$term->$key] = $term;
357 }
358 }
359 return $terms[$node->vid][$key];
360 }
361
362 /**
363 * Implementation of hook_project_issue_metadata().
364 *
365 * Adds taxonomy terms to the data that will be used to create the
366 * project issue metadata tables and which is used when creating
367 * issue notification e-mail messages.
368 *
369 * @param $op
370 * Specifies the type of table that is being created. 'current' is passed when generating the metadata table
371 * at the top of issue nodes and 'diff' is passed when creating tables used in comments and when creating
372 * issue notification e-mail messages.
373 * @param $node
374 * The node object of the project issue.
375 * @param $metadata
376 * An array of metadata to use in the final table.
377 * @param $old_data
378 * A node or comment object containing the 'old' data when $op == 'diff'.
379 * @param $new_data
380 * A node or comment object containing the 'new' data when $op == 'diff'.
381 */
382 function comment_alter_taxonomy_project_issue_metadata($op, $node, &$metadata = array(), $old_data = NULL, $new_data = NULL) {
383 switch ($op) {
384 case 'current':
385 if (!isset($node->taxonomy)) {
386 return;
387 }
388
389 // Get an array containing all vocabulary objects that are associated
390 // with project_issue nodes and which are alterable by comment_alter_taxonomy.
391 $allowed = comment_alter_taxonomy_get_alterable_vocabularies('project_issue');
392 if (empty($allowed)) {
393 return;
394 }
395
396 // Group the terms assigned to the node by vocabulary and create an additional
397 // row in the table for each vocabulary. Exclude any terms in vocabularies
398 // which are not alterable by the comment_alter_taxonomy module.
399 $terms = $node->taxonomy;
400 if (!empty($terms)) {
401 $grouped_terms = array();
402 foreach ($terms as $tid => $term) {
403 $vid = $term->vid;
404 if (isset($allowed[$vid])) {
405 if (!isset($metadata["taxonomy_vid_$vid"])) {
406 $vocabulary = $allowed[$vid];
407 $metadata["taxonomy_vid_$vid"] = array('label' => check_plain(t("$vocabulary->name")));
408 }
409 $grouped_terms[$vid][] = theme('comment_alter_taxonomy_project_issue_metadata_term', $node, $term);
410 }
411 }
412 foreach ($grouped_terms as $vid => $terms) {
413 $metadata["taxonomy_vid_$vid"]['current'] = implode(', ', $terms);
414 }
415 break;
416 }
417
418 case 'diff':
419 // Get an array containing all vocabulary objects that are associated
420 // with project_issue nodes and which are alterable by comment_alter_taxonomy.
421 $allowed = comment_alter_taxonomy_get_alterable_vocabularies('project_issue');
422 if (empty($allowed)) {
423 return;
424 }
425
426 // For each vocabulary in $allowed, create an element of $metadata to store term
427 // changes for that vocabulary. Doing this now makes sure that the final
428 // $metadata array will have the vocabularies ordered by weight and makes sure
429 // that the vocabularies are displayed in the same order every time.
430 // Before this function returns these values in $metadata will be checked and any
431 // that do not reflect term changes will be unset.
432 foreach ($allowed as $vid => $vocabulary) {
433 // For multiple select vocabularies, each term will be stored in $metadata
434 // as an element of an array for both 'old' and 'new'. For single
435 // select vocabularies, all terms for the vocabulary are placed
436 // in a single string.
437 $metadata["taxonomy_vid_$vid"] = array(
438 'label' => t($vocabulary->name),
439 'old' => $vocabulary->multiple || $vocabulary->tags ? array() : '',
440 'new' => $vocabulary->multiple || $vocabulary->tags ? array() : '',
441 );
442 }
443
444 $old_terms = _comment_alter_taxonomy_build_term_list($node, $old_data);
445 $new_terms = _comment_alter_taxonomy_build_term_list($node, $new_data);
446
447 if ($old_terms !== FALSE && $new_terms !== FALSE && (!empty($old_terms) || !empty($new_terms))) {
448 // Merge all terms together.
449 $all_terms = $old_terms + $new_terms;
450
451 foreach ($all_terms as $tid => $term) {
452 // If a term is in both $old_terms and $new_terms, than it didn't change and we can ignore
453 // it since we're only interested in terms that were changed between $old_data and $new_data.
454 if (!empty($old_terms) && !empty($new_terms) && isset($old_terms[$tid]) && isset($new_terms[$tid])) {
455 continue;
456 }
457
458 $vid = $term->vid;
459 // Skip this term if its not associated with a vocabulary that's alterable
460 // by comment_alter_taxonomy.
461 if (!isset($metadata["taxonomy_vid_$vid"])) {
462 continue;
463 }
464
465 // Determine if this term goes in the 'old' or 'new' element of
466 // the $metadata array.
467 if (isset($old_terms[$tid])) {
468 $old_new = 'old';
469 }
470 else {
471 $old_new = 'new';
472 }
473
474 // Add this term change to the $metadata array.
475 $themed_term = theme('comment_alter_taxonomy_project_issue_metadata_term', $node, $term);
476 if (is_array($metadata["taxonomy_vid_$vid"][$old_new])) {
477 // Multiple select vocabulary.
478 $metadata["taxonomy_vid_$vid"][$old_new][$tid] = $themed_term;
479 }
480 elseif (!empty($metadata["taxonomy_vid_$vid"][$old_new])) {
481 $metadata["taxonomy_vid_$vid"][$old_new] .= ', '. $themed_term;
482 }
483 else {
484 $metadata["taxonomy_vid_$vid"][$old_new] = $themed_term;
485 }
486 }
487 }
488
489 // Now that all taxonomy changes are stored in $metadata, we need to go back
490 // and remove any elements created at the top of this function that do
491 // not contain taxonomy changes.
492 foreach ($allowed as $vid => $vocabulary) {
493 if (isset($metadata["taxonomy_vid_$vid"]) && empty($metadata["taxonomy_vid_$vid"]['old']) && empty($metadata["taxonomy_vid_$vid"]['new'])) {
494 unset($metadata["taxonomy_vid_$vid"]);
495 }
496 }
497 break;
498 }
499 }
500
501 /**
502 * Implementation of hook_theme().
503 */
504 function comment_alter_taxonomy_theme() {
505 return array(
506 'comment_alter_taxonomy_project_issue_metadata_term' => array(
507 'arguments' => array('node' => NULL, 'term' => NULL),
508 ),
509 );
510 }
511
512 /**
513 * Theme a taxonomy term in a project issue metadata table.
514 *
515 * NOTE: This function (and any function that overrides it)
516 * must sanitize the term name to prevent XSS vulnerabilities.
517 *
518 * @param $node
519 * The node for which the taxonomy was altered.
520 * @param $term
521 * The taxonomy term object.
522 * @return
523 * The themed term.
524 */
525 function theme_comment_alter_taxonomy_project_issue_metadata_term($node, $term) {
526 if (isset($term->tid)) {
527 $link_options = array();
528 if (module_exists('project_issue') && $node->type == 'project_issue') {
529 $project = node_load($node->project_issue['pid']);
530 $vocabulary = taxonomy_vocabulary_load($term->vid);
531 $identifier = project_issue_views_filter_identifier($vocabulary->name);
532 $path = 'project/issues/search/'. $project->project['uri'];
533 $link_options['query'] = array($identifier => $term->name);
534 }
535 else {
536 $path = taxonomy_term_path($term);
537 }
538 return l($term->name, $path, $link_options);
539 }
540 else {
541 // New free tagging terms won't yet have a tid in the node preview mode
542 // and therefore shouldn't be printed as links.
543 return check_plain($term->name);
544 }
545 }
546
547 /**
548 * Build a list of all taxonomy terms associated with a comment.
549 *
550 * @param $node
551 * The node.
552 * @param $comment
553 * Either a comment object or the result of a posted comment.
554 * @return
555 * A straight array (not nested) of term objects with the tid of each
556 * term in the key of the array, when possible. For new free tagging
557 * terms, it's not possible to get the term object, since the term
558 * is not yet saved to the database, so an object containing
559 * all information known about the term is included instead. In the
560 * case where no information at all is saved in {comment_alter_taxonomy}
561 * for a given comment, FALSE is returned.
562 */
563 function _comment_alter_taxonomy_build_term_list($node, $comment) {
564 $term_list = array();
565 // For previews and validation, $comment->taxonomy should be set
566 // and must be processed to get the terms. Otherwise, they can
567 // be retrieved from the {comment_alter_taxonomy} table.
568 if (isset($comment->taxonomy)) {
569 foreach ($comment->taxonomy as $key => $value) {
570 if ($key == 'tags') {
571 foreach ($value as $vid => $tags) {
572 $tags_array = explode(',', $tags);
573 foreach ($tags_array as $tag) {
574 $tag = trim($tag);
575 if (empty($tag)) {
576 continue;
577 }
578
579 // See if the term exists in the chosen vocabulary
580 // and return the tid; otherwise, add a new record.
581 // This block is modified from taxonomy_node_save().
582 $possibilities = taxonomy_get_term_by_name($tag);
583 $tag_tid = NULL; // tid match, if any.
584 foreach ($possibilities as $possibility) {
585 if ($possibility->vid == $vid) {
586 $tag_tid = $possibility->tid;
587 $term_list[$tag_tid] = taxonomy_get_term($tag_tid);
588 }
589 }
590 // This term is not in the database yet. Add what we know about
591 // it to the $term_list array. We use a hack here for the key
592 // since we don't want to accidentally overwrite another term in $term_list.
593 if (empty($tag_tid)) {
594 $term_list["$vid***$tag"]->tid = NULL;
595 $term_list["$vid***$tag"]->vid = $vid;
596 $term_list["$vid***$tag"]->name = $tag;
597 $tag_tid = NULL;
598 }
599 }
600 }
601 }
602 elseif (is_object($value)) {
603 $term_list[$key] = $value;
604 }
605 elseif (is_array($value)) {
606 foreach ($value as $tid) {
607 $term_list[$tid] = taxonomy_get_term($tid);
608 }
609 }
610 else {
611 $term_list[$value] = taxonomy_get_term($value);
612 }
613 }
614 }
615 else {
616 $cid = isset($comment->cid) ? $comment->cid : 0;
617 $result = db_query(db_rewrite_sql('SELECT cat.tid, t.* FROM {comment_alter_taxonomy} cat LEFT JOIN {term_data} t ON cat.tid = t.tid LEFT JOIN {vocabulary} v ON t.vid = v.vid WHERE cat.nid = %d AND cat.cid = %d ORDER BY v.weight, t.weight, t.name', 't', 'tid'), $node->nid, $cid);
618 while ($term = db_fetch_object($result)) {
619 $term_list[$term->tid] = $term;
620 }
621 if (empty($term_list)) {
622 // This cannot be empty because we save a dummy tid = 0 term even if the
623 // node was associated to no terms at the time the comment was saved.
624 // This can only mean that this module was not enabled at that time,
625 // so abort the diff.
626 return FALSE;
627 }
628 // Remove the dummy tid = 0 if set.
629 unset($term_list[0]);
630 }
631 return $term_list;
632 }
633
634 /**
635 * Implementation of hook_nodeapi().
636 *
637 * Note that the taxonomy module must have a weight lighter
638 * than the comment_alter_taxonomy module, which itself must
639 * be lighter than the project_issue module.
640 */
641 function comment_alter_taxonomy_nodeapi(&$node, $op, $arg = 0) {
642 switch ($op) {
643 case 'load':
644 // This is necessary because taxonomy_nodeapi() retrieves the terms using
645 // taxonomy_node_get_terms(), which caches the terms for nodes it has already
646 // retrieved the terms for. Since this module changes terms, if another module
647 // were to call node_load() during the same page request and then call
648 // node_save() on the same node, the changes in terms made by this module
649 // would get eliminated. The project_issue module has this exact behavior.
650 $output['taxonomy'] = _comment_alter_taxonomy_taxonomy_node_get_terms($node, 'tid', TRUE);
651 return $output;
652 break;
653
654 case 'insert':
655 // Store any taxonomy terms associated with a node to the
656 // {comment_alter_taxonomy} table.
657 //
658 // Since the taxonomy module has a lighter weight than the
659 // comment_alter_taxonomy module, and since taxonomy_nodeapi()
660 // calls taxonomy_node_save() when $op == 'insert', the terms
661 // for this node have already been saved to the database.
662 // That makes our job easier here, because we can just call
663 // comment_alter_taxonomy_taxonomy_node_get_terms() to get them
664 // back from the database.
665 $tids = array_keys(_comment_alter_taxonomy_taxonomy_node_get_terms($node, 'tid', TRUE));
666
667 // Delete any records already in the table for this original node (for
668 // original nodes, the cid is stored as 0).
669 db_query("DELETE FROM {comment_alter_taxonomy} WHERE nid = %d AND cid = %d", $node->nid, 0);
670
671 foreach ($tids as $tid) {
672 if (!empty($tid)) {
673 db_query('INSERT INTO {comment_alter_taxonomy} (nid, cid, tid) VALUES (%d, %d, %d)', $node->nid, 0, $tid);
674 }
675 }
676 break;
677
678 case 'delete revision':
679 // We don't have anything to do here,
680 // as we version terms by cid, not by vid.
681 break;
682
683 case 'delete':
684 db_query("DELETE FROM {comment_alter_taxonomy} WHERE nid = %d", $node->nid);
685 break;
686 }
687 }
688
689 /**
690 * Get the vocabularies associated with a given node type
691 * that can be altered via comment_alter_taxonomy.
692 *
693 * @param $type
694 * Type of node for which to get vocabularies.
695 * @param $reset
696 * Whether to reset the internal vocabularies cache.
697 * @return
698 * An array of vocabulary objects that are alterable by this module.
699 */
700 function comment_alter_taxonomy_get_alterable_vocabularies($type, $reset = NULL) {
701 static $vocabularies = NULL;
702
703 if ($reset) {
704 $vocabularies = NULL;
705 }
706
707 if (!isset($vocabularies[$type])) {
708 $vocabularies[$type] = array();
709 $all_vocabularies = taxonomy_get_vocabularies($type);
710 $alterable_vocabularies = variable_get('comment_alter_taxonomy_vocabularies', array());
711 foreach ($all_vocabularies as $vid => $vocabulary) {
712 if (!empty($alterable_vocabularies[$vid])) {
713 $vocabularies[$type][$vid] = $vocabulary;
714 }
715 }
716 }
717 return $vocabularies[$type];
718 }
719
720 /**
721 * Implementation of hook_link_alter().
722 *
723 * Remove taxonomy links on project issues, when required.
724 */
725 function comment_alter_taxonomy_link_alter(&$links, $node) {
726 if (module_exists('project_issue') && $node->type == 'project_issue') {
727 $allowed = comment_alter_taxonomy_get_alterable_vocabularies('project_issue');
728 if (empty($allowed) || empty($node->taxonomy)) {
729 return;
730 }
731 if (!empty($node->taxonomy)) {
732 foreach ($node->taxonomy as $tid => $term) {
733 if (isset($allowed[$term->vid])) {
734 unset($links['taxonomy_term_'. $term->tid]);
735 }
736 }
737 }
738 }
739 }
740
741 /**
742 * Implementation of hook_taxonomy().
743 *
744 * Handle deletion of terms and vocabularies from the database.
745 */
746 function comment_alter_taxonomy_taxonomy($op, $type, $array = NULL) {
747 if ($op == 'delete') {
748 if ($type == 'vocabulary') {
749 // Delete this vocabulary from the comment_alter_taxonomy_vocabularies variable.
750 // When a vocabulary is deleted this hook is first called for each term
751 // in the vocabulary, so those rows will already be deleted by the time
752 // execution gets here.
753 $vocabularies = variable_get('comment_alter_taxonomy_vocabularies', array());
754 if (isset($vocabularies[$array['vid']])) {
755 unset($vocabularies[$array['vid']]);
756 variable_set('comment_alter_taxonomy_vocabularies', $vocabularies);
757 }
758 }
759
760 // Delete the rows in {comment_alter_taxonomy} for the term.
761 db_query('DELETE FROM {comment_alter_taxonomy} WHERE tid = %d', $tids);
762 }
763 }
764
765 /**
766 * Wrapper to define callbacks in include files.
767 */
768 function _comment_alter_taxonomy_callback($file, $function) {
769 $args = func_get_args();
770 $file = array_shift($args);
771 $function = array_shift($args);
772
773 include_once drupal_get_path('module', 'comment_alter_taxonomy') .'/'. $file;
774 return call_user_func_array($function, $args);
775 }

  ViewVC Help
Powered by ViewVC 1.1.2