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

Contents of /contributions/modules/similarterms/similarterms.module

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


Revision 1.25 - (show annotations) (download) (as text)
Sun Mar 29 22:13:52 2009 UTC (8 months ago) by rmiddle
Branch: MAIN
CVS Tags: HEAD
Changes since 1.24: +384 -79 lines
File MIME type: text/x-php
[#408262] Patch by Mark Theunissen to add a hook so people can change the node list before going to the theme.  Plus to use VID instead of NID in query.
1 <?php
2 // $Id: similarterms.module,v 1.24 2009/01/28 18:15:48 rmiddle Exp $
3 // by Jeff Robbins
4
5 /**
6 * @file
7 * Similar By Terms module displays a block with similar content
8 * based on taxonomy terms.
9 */
10
11 /**
12 * Display help and module information
13 * @param path which path of the site we're displaying help
14 * @param arg array that holds the current path as would be returned from arg() function
15 * @return help text for the path
16 */
17
18 function similarterms_help($path, $arg) {
19 $output = '';
20 switch ($path) {
21 case "admin/help#similarterms":
22 $output = '<p>'. t("Displays a block with similar content based on taxonomy terms.") .'</p>';
23 break;
24 }
25 return $output;
26 } // function similarterms_help
27
28 /**
29 * Valid permissions for this module
30 * @return array An array of valid permissions for the similarterms module
31 */
32 function similarterms_perm() {
33 return array('access similarterms content', 'administer similarterms content');
34 } // function similarterms_perm()
35
36
37 /**
38 * Implementation of hook_block().
39 */
40 function similarterms_block($op = 'list', $delta = 0, $edit = array()) {
41 $block = $form = array();
42 switch ($op) {
43 case 'list':
44 return similarterms_block_list();
45
46 case 'view':
47 return similarterms_block_view($delta);
48
49 case 'configure':
50 return similarterms_block_configure($delta);
51
52 case 'save':
53 similarterms_block_save($delta, $edit);
54 return;
55 }
56 }
57
58 /**
59 * Perform the "list" op for hook_block().
60 *
61 * @return
62 * Array of block definition.
63 */
64 function similarterms_block_list() {
65 $blocks[0]['info'] = t('Similar entries from ANY vocabulary.');
66 $blocks[0]['cache'] = BLOCK_CACHE_PER_PAGE;
67 if (variable_get("similarterms_vocabularies", 'multi_select_and_tags') == 'all') {
68 foreach (taxonomy_get_vocabularies() as $v) {
69 $blocks[$v->vid]['info'] = t('Similar entries from the @vocab vocabulary.', array('@vocab' => $v->name));
70 $blocks[$v->vid]['cache'] = BLOCK_CACHE_PER_PAGE;
71 }
72 }
73 else {
74 foreach (taxonomy_get_vocabularies() as $v) {
75 // this only makes sense for multi-select vocabularies and free tagging
76 if ($v->multiple || $v->tags) {
77 $blocks[$v->vid]['info'] = t('Similar entries from the @vocab vocabulary.', array('@vocab' => $v->name));
78 $blocks[$v->vid]['cache'] = BLOCK_CACHE_PER_PAGE;
79 }
80 }
81 }
82 return $blocks;
83 }
84
85 /**
86 * Perform the "view" op for hook_block().
87 *
88 * @param $delta
89 * String specifying which block to proocess.
90 *
91 * @return
92 * Array of block contents and title.
93 */
94 function similarterms_block_view($delta) {
95 if ($delta == 0) {
96 $block['subject'] = t('Similar');
97 $block['content'] = theme('similarterms', variable_get('similarterms_display_options', 'title_only'), similarterms_list());
98 }
99 else {
100 $block['subject'] = t('Similar');
101 $block['content'] = theme('similarterms', variable_get('similarterms_display_options', 'title_only'), similarterms_list($delta));
102 }
103 return $block;
104 }
105
106 /**
107 * Perform the "configure" op for hook_block().
108 *
109 * @param $delta
110 * String specifying which block to proocess.
111 *
112 * @return
113 * Settings form array.
114 */
115 function similarterms_block_configure($delta = 0) {
116 $form['count'] = array(
117 '#type' => 'textfield',
118 '#title' => t('Item count'),
119 '#default_value' => variable_get('simterms_count_'. $delta, 5),
120 '#size' => 3,
121 '#description' => t('The maximum number of similar items to display'),
122 );
123 //petertj addition to configuration to permit display of current node in list
124 $form['showcurrentnode'] = array(
125 '#type' => 'checkbox',
126 '#title' => t('Show current node as active in the list'),
127 '#default_value' => variable_get('similarterms_showcurrentnode_'. $delta, FALSE),
128 '#required' => FALSE,
129 );
130 //mimo addition to configuration to limit to same page type
131 $types = array('0' => t('<none>'), '1' => t('same as current'));
132 $arr_types_obj = node_get_types();
133 foreach ($arr_types_obj as $type => $obj) {
134 $types[$type] = $obj->name;
135 }
136 $form['sametype'] = array(
137 '#type' => 'select',
138 '#title' => t('Content type limit'),
139 '#default_value' => variable_get('simterms_sametype_'. $delta, FALSE),
140 '#options' => $types,
141 '#description' => t('Limit to pages of this or these content type(s)'),
142 '#multiple' => TRUE
143 );
144 if ($delta > 0) {
145 $terms = array();
146 $tree = taxonomy_get_tree($delta);
147 foreach ($tree as $term) {
148 $terms[$term->tid] = $term->name;
149 }
150 $form['ignoreterms'] = array(
151 '#type' => 'select',
152 '#title' => t('Terms to be ignored'),
153 '#default_value' => variable_get('simterms_ignoreterms_'. $delta, array()),
154 '#options' => $terms,
155 '#description' => t('Ignore selected terms here from being used to search for similar entries'),
156 '#multiple' => TRUE
157 );
158 }
159 return $form;
160 }
161
162 /**
163 * Perform the "save" op for hook_block().
164 *
165 * @param $delta
166 * String specifying which block to proocess.
167 * @param $edit
168 * Array containg the form input.
169 *
170 * @return
171 * None. Values are saved as system variables.
172 */
173 function similarterms_block_save($delta = 0, $edit = array()) {
174 variable_set('simterms_count_'. $delta, $edit['count']);
175 variable_set('simterms_sametype_'. $delta, $edit['sametype']);
176 variable_set('simterms_ignoreterms_'. $delta, $edit['ignoreterms']);
177 variable_set('similarterms_showcurrentnode_'. $delta, $edit['showcurrentnode']);
178 }
179
180 /**
181 * Output the block
182 *
183 * @param $vocid
184 * integer - vocabulary id, leave out to use ALL terms for this node
185 * @param $nid
186 * integer - nid, leave out to use the current node
187 * @return
188 * an array of node objects
189 */
190 function similarterms_list($vocid = 0, $nid = NULL) {
191 $lists = array();
192 $nodes = array();
193 $args = array();
194 $list_num = 0;
195 $sql = "";
196 $cache_lifetime = variable_get('similarterms_cache_options', 3600);
197 $count = variable_get('simterms_count_'. $vocid, 5);
198
199 if (arg(0) == 'node' && is_numeric(arg(1)) && !$nid) {
200 $nid = arg(1);
201 }
202
203 if ($nid != NULL) {
204 $cid = "$vocid:$nid";
205 if ($cache_lifetime) {
206 if ($cached = cache_get($cid, 'cache_similarterms')) {
207 return $cached->data;
208 }
209 }
210 if (variable_get('similarterms_override_options', 0)) {
211 $lists = similarterms_get_overrides($nid, $vocid);
212 if ($lists[$vocid]) {
213 foreach ($lists[$vocid] as $nid_list) {
214 if (is_numeric($nid_list)) {
215 if ($list_num <= $count) {
216 $list_num = $list_num + 1;
217 $nodes[] = node_load($nid_list);
218 }
219 }
220 }
221 }
222 }
223 $node_obj = node_load($nid);
224
225 if ($vocid == 0) {
226 $terms = array_keys(taxonomy_node_get_terms($node_obj));
227 }
228 else {
229 $terms = array_keys(taxonomy_node_get_terms_by_vocabulary($node_obj, $vocid));
230 }
231
232 // Filter out some terms
233 $terms_filter = variable_get('simterms_ignoreterms_'. $vocid, array());
234
235 foreach ($terms_filter as $v) {
236 $idx = array_search($v, $terms);
237 if ($idx >= 0) {
238 unset($terms[$idx]);
239 }
240 }
241
242 if (!empty($terms)) {
243 //past events
244 $pasts = array();
245
246 $sql = 'SELECT n.nid, n.title, COUNT(n.nid) AS ncount ';
247 $sql .= 'FROM {node} n ';
248 $sql .= 'INNER JOIN {term_node} tn ON n.vid = tn.vid ';
249
250 $sql .= 'WHERE tn.tid IN (';
251 $number_of_terms = count($terms);
252 foreach ($terms as $terms_items) {
253 $number_of_terms--;
254 if ($number_of_terms) {
255 $sql .= "'%s',";
256 }
257 else {
258 $sql .= "'%s'";
259 }
260 $args[] = $terms_items;
261 }
262 $sql .= ') ';
263
264 $types = variable_get('simterms_sametype_'. $vocid, FALSE);
265 if (($types !== FALSE) && is_array($types) && count($types) > 0 && ($types['0'] == NULL) ) {
266 if ($types[1]) {
267 $node_obj = node_load($nid);
268 $types[1] = $node_obj->type;
269 }
270 $sql .= 'AND n.type IN (';
271 $number_of_types = count($types);
272 foreach ($types as $types_items) {
273 $number_of_types--;
274 if ($number_of_types) {
275 $sql .= "'%s',";
276 }
277 else {
278 $sql .= "'%s'";
279 }
280 $args[] = $types_items;
281 }
282 $sql .= ') ';
283 }
284
285 //if showcurrentnode option is false (default state), create filter for query.
286 if (!variable_get('similarterms_showcurrentnode_'. $vocid, FALSE)) {
287 $sql .= 'AND n.nid != %d ';
288 $args[] = $nid;
289 }
290
291 $sql .= 'AND n.status = 1 ';
292 $sql .= 'AND n.moderate = 0 ';
293 $sql .= "AND (n.language = '' OR n.language = '%s') ";
294 $args[] = $node_obj->language;
295 $sql .= 'GROUP BY n.nid, n.title, n.created ';
296 if (variable_get('similarterms_ncount_options', 'default') == 'default') {
297 $sql .= 'ORDER BY ncount DESC, ';
298 }
299 else {
300 $sql .= 'ORDER BY ncount ASC, ';
301 }
302 $sql .= 'n.created DESC ';
303 $sql .= 'LIMIT %d';
304 $args[] = $count;
305
306 $sql = db_rewrite_sql($sql);
307 $result = db_query($sql, $args);
308 // watchdog('similarterms', $sql, NULL, WATCHDOG_INFO);
309 while ($r = db_fetch_object($result)) {
310 $nodes[] = node_load($r->nid);
311 }
312
313 // Allow modules to alter the list of nodes by implementing a hook.
314 // Design pattern from comment_invoke_comment().
315 foreach (module_implements('similarterms') as $name) {
316 $function = $name .'_similarterms';
317 $function($nodes, $node_obj);
318 }
319
320 if ($cache_lifetime) {
321 cache_set($cid, $nodes, 'cache_similarterms', time() + $cache_lifetime);
322 }
323 }
324 }
325 return $nodes;
326 }
327
328 /**
329 * Implementation of hook_flush_caches().
330 */
331 function similarterms_flush_caches() {
332 return array('cache_similarterms');
333 }
334
335 /**
336 * Implementation of hook_form_alter().
337 */
338 function similarterms_form_alter(&$form, $form_state, $form_id) {
339 if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
340 if (!variable_get('similarterms_override_options', 0)) {
341 return;
342 }
343 // no need to alter form if block module is off
344 if (! module_exists('block')) {
345 return;
346 }
347 $blocks = similarterms_get_active_block_vocabularies();
348 // no need to alter form if no similarterms blocks are active
349 if (sizeof($blocks) == 0) {
350 return;
351 }
352 $overrides = array();
353 if (is_numeric($form['nid']['#value'])) {
354 $overrides = similarterms_get_overrides($form['nid']['#value']);
355 }
356 $form['similarterms'] = array(
357 '#type' => 'fieldset',
358 '#title' => t('Similar Terms'),
359 '#description' => t('Override the links generated by similar terms module.'),
360 '#collapsible' => 1,
361 '#collapsed' => sizeof($overrides) ? 0 : 1,
362 );
363 $node_type = $form['type']['#value'];
364 $no_similarterms = 1;
365 foreach (similarterms_taxonomy_get_vocabularies() as $v) {
366 if (! $blocks[$v->vid]) {
367 continue;
368 }
369 $types = variable_get('simterms_sametype_'. $v->vid, array('0' => '0'));
370 if (! $types[$node_type] && ! isset($types[0])) {
371 continue;
372 }
373 $no_similarterms = 0;
374 $form['similarterms']['similarterms_vid_'. $v->vid] = array(
375 '#type' => 'fieldset',
376 '#title' => $v->name,
377 '#collapsible' => 1,
378 '#collapsed' => sizeof($overrides[$v->vid]) ? 0 : 1,
379 '#tree' => 1,
380 );
381 $form['similarterms']['similarterms_vid_'. $v->vid]['similarterms_paths'] = array(
382 '#type' => 'fieldset',
383 '#title' => t('Paths'),
384 '#tree' => 1,
385 );
386 $count = variable_get('simterms_count_'. $v->vid, 5);
387 for ($i = 0; $i < $count; $i++) {
388 $default_value = '';
389 if ($overrides[$v->vid][$i]) {
390 $default_value = drupal_lookup_path('alias', 'node/'. $overrides[$v->vid][$i]);
391 if (! $default_value) {
392 $default_value = 'node/'. $overrides[$v->vid][$i];
393 }
394 }
395 $form['similarterms']['similarterms_vid_'. $v->vid]['similarterms_paths'][$i] = array(
396 '#type' => 'textfield',
397 '#title' => t('Path %d', array('%d' => $i + 1)),
398 '#default_value' => $default_value ? $default_value : '',
399 );
400 }
401 $form['similarterms']['similarterms_vid_'. $v->vid]['similarterms_override_delete'] = array(
402 '#type' => 'checkbox',
403 '#title' => t('Delete Similar Terms Overrides?'),
404 '#description' => t('If this option is checked all paths will be deleted for this vocabulary.'),
405 '#default_value' => 0,
406 );
407 }
408 if ($no_similarterms) {
409 unset($form['similarterms']);
410 }
411 }
412 }
413
414 /**
415 * This function returns a list of overrides
416 */
417 function similarterms_get_overrides($nid, $vid = NULL) {
418 $paths = array();
419 $query = "SELECT * FROM {similarterms_override} WHERE nid = '%s'";
420 $args = array($nid);
421 if ($vid) {
422 $query .= " AND vid = %s";
423 $args[] = $vid;
424 }
425 $result = db_query($query, $args);
426 while ($object = db_fetch_object($result)) {
427 $paths[$object->vid][] = $object->path;
428 }
429 return $paths;
430 }
431
432 /**
433 * Implementation of hook_nodeapi().
434 */
435 function similarterms_nodeapi($node, $op, $arg = 0) {
436 switch ($op) {
437 case 'delete':
438 similarterms_node_delete($node);
439 break;
440 case 'insert':
441 case 'update':
442 similarterms_node_save($node);
443 break;
444 case 'validate':
445 similarterms_node_validate($node);
446 break;
447 }
448 }
449
450 /**
451 * Function to delete entries from overrides table when a node is deleted
452 */
453 function similarterms_node_delete($node, $vid = NULL) {
454 if (!variable_get('similarterms_override_options', 0)) {
455 return;
456 }
457 $query = "DELETE FROM {similarterms_override} WHERE nid = %d";
458 $args = array($node->nid);
459 if ($vid) {
460 $query .= " AND vid = %d";
461 $args[] = $vid;
462 }
463 db_query($query, $args);
464 }
465
466 /**
467 * Function to populate overrides table
468 */
469 function similarterms_node_save($node) {
470 if (!variable_get('similarterms_override_options', 0)) {
471 return;
472 }
473 $result = array();
474 $query = "INSERT INTO {similarterms_override} (nid, path, vid) VALUES(%d, %d, %d)";
475 foreach (similarterms_taxonomy_get_vocabularies() as $v) {
476 $vid = 'similarterms_vid_'. $v->vid;
477 $alias =& $node->$vid;
478 similarterms_node_delete($node, $v->vid);
479 if ($alias['similarterms_override_delete']) {
480 continue;
481 }
482 foreach ($alias['similarterms_paths'] as $id => $path) {
483 $pieces = explode('/', $path);
484 if (sizeof($pieces) == 2 && $pieces[0] == "node" && is_numeric($pieces[1])) {
485 $nid = $pieces[1];
486 }
487 else {
488 $path = drupal_lookup_path('source', $path);
489 $pieces = explode('/', $path);
490 $nid = $pieces[1];
491 }
492 if ($nid) {
493 $args = array(
494 $node->nid,
495 $nid,
496 $v->vid
497 );
498 $result[$id] = db_query($query, $args);
499 }
500 }
501 }
502 }
503
504 /**
505 * Function to validate entries into the overrides table
506 */
507 function similarterms_node_validate($node) {
508 if (!variable_get('similarterms_override_options', 0)) {
509 return;
510 }
511 foreach (similarterms_taxonomy_get_vocabularies() as $v) {
512 $vid = 'similarterms_vid_'. $v->vid;
513 $alias =& $node->$vid;
514 // Make sure that the paths are valid
515 foreach ($alias['similarterms_paths'] as $id => $path) {
516 $pieces = explode('/', $path);
517 if (sizeof($pieces) == 2 && $pieces[0] == "node" && is_numeric($pieces[1])) {
518 // If there's a better way to check if a node exists, replace this code
519 $thisnode = node_load($pieces[1]);
520 if (! $thisnode->nid) {
521 form_set_error("$vid][similarterms_paths][$id", t('%path is not a valid path', array('%path' => $path)));
522 }
523 }
524 elseif ($path == '') {
525 continue;
526 }
527 elseif (! drupal_lookup_path('source', $path)) {
528 form_set_error("$vid][similarterms_paths][$id", t('%vocab %path is not a valid path', array('%path' => $path, '%vocab' => $v->name)));
529 }
530 }
531 }
532 }
533
534 /**
535 * This function returns a list of all blocks for similarterms
536 *
537 * Note: I could not find a public function in the block module to do this
538 * so I wrote this function based on _block_rehash(). If there's a better
539 * way to do this, this code should be refactored
540 */
541 function similarterms_get_active_block_vocabularies() {
542 // TODO: add in code to check for blockcache module
543 global $theme_key;
544 init_theme();
545 $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s' AND module = '%s'", $theme_key, 'similarterms');
546 while ($object = db_fetch_object($result)) {
547 if ($object->status) {
548 $blocks[$object->delta] = 1;
549 }
550 }
551 return $blocks;
552 }
553
554 /**
555 * This function gets taxonomy vocabularies and add in 0 for "all vocabs";
556 */
557 function similarterms_taxonomy_get_vocabularies() {
558 $object = taxonomy_get_vocabularies();
559 $object[0]->vid = 0;
560 $object[0]->name = t('Any Vocabulary');
561 return $object;
562 }
563
564 /**
565 * Implementation of hook_menu().
566 */
567 function similarterms_menu() {
568 // Admin settings for the site.
569 $items['admin/settings/similarterms'] = array(
570 'title' => 'Similar By Terms',
571 'description' => 'Basic Settings for similar term most settings are in the blocks config.',
572 'page callback' => 'drupal_get_form',
573 'page arguments' => array('similarterms_admin_settings'),
574 'file' => 'similarterms.admin.inc',
575 'access arguments' => array('administer site configuration'),
576 'type' => MENU_NORMAL_ITEM, // optional
577 );
578 return $items;
579 }
580
581 /**
582 * Theme function for similar block
583 *
584 */
585 function similarterms_theme() {
586 return array(
587 'similarterms' => array(
588 'template' => 'similarterms',
589 'arguments' => array('display_options' => NULL, 'items' => NULL),
590 ),
591 );
592 }
593

  ViewVC Help
Powered by ViewVC 1.1.2