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

Contents of /contributions/modules/directory/directory.module

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


Revision 1.35 - (show annotations) (download) (as text)
Tue Sep 30 09:16:27 2008 UTC (13 months, 3 weeks ago) by augustin
Branch: MAIN
CVS Tags: HEAD
Changes since 1.34: +5 -4 lines
File MIME type: text/x-php
 * Fixed hook_uninsall() to cover all variable that may be set in the future.
  * update_6001() remove one obsolete variable.
1 <?php
2 // $Id: directory.module,v 1.34 2008/08/13 12:25:42 augustin Exp $
3
4 /**
5 * @file
6 * Creates a directory view of all taxonomy terms of the site.
7 *
8 * Authored by Matt Westgate <drupal at asitis dot org>
9 * Original Frontier implementation by John VanDyk <jvandyk at iastate dot edu>
10 * Drupal 4.7 maintainer Michael Curry, Exodus Development, Inc. http://exodusdev.com exodusdev@gmail.com
11 * Current maintainer (drupal 5 onwards) Augustin Masquilier, http://overshoot.tv/ , http://minguo.info/
12 */
13
14
15 /********************************************************************
16 * Drupal hooks
17 * *****************************************************************/
18
19 /**
20 * Implementation of hook_help().
21 */
22 function directory_help($path, $arg) {
23 if ('taxonomy/term/%' == $path) {
24 return theme('directory_taxonomy_subterms', arg(2));
25 }
26 }
27
28 /**
29 * Implementation of hook_init().
30 */
31 function directory_init() {
32 drupal_add_css(drupal_get_path('module', 'directory') . '/directory.css');
33 }
34
35 /**
36 * Implementation of hook_menu().
37 */
38 function directory_menu() {
39 $items = array();
40
41 $items['directory'] = array(
42 'title' => 'directory',
43 'page callback' => 'directory_page',
44 'access arguments' => array('access content')
45 );
46 $items['admin/settings/directory'] = array(
47 'title' => 'Directory Settings',
48 'description' => 'Set which node types and which vocabularies to include, the depth to display on the directory page, etc.',
49 'page callback' => 'drupal_get_form',
50 'page arguments' => array('directory_admin_settings'),
51 'access arguments' => array('administer site configuration'),
52 'type' => MENU_NORMAL_ITEM
53 );
54 $vocabularies = taxonomy_get_vocabularies();
55 foreach ($vocabularies AS $vid => $vocabulary) {
56 $items['directory/vocabulary/' . $vocabulary->vid] = array(
57 'title' => t('Directory for !vocabulary-name', array('!vocabulary-name' => $vocabulary->name)),
58 'page callback' => 'directory_vocabulary_page',
59 'page arguments' => array(2),
60 'access arguments' => array('access content'),
61 'type' => MENU_SUGGESTED_ITEM,
62 );
63 }
64
65 return $items;
66 }
67
68 /**
69 * Implementation of hook_theme().
70 */
71 function directory_theme($existing, $type, $theme, $path) {
72 return array(
73 'directory_node_count' => array(
74 'arguments' => array('nodecount' => NULL, 'term' => NULL),
75 ),
76 'directory_list_subterms' => array(
77 'arguments' => array('terms' => NULL),
78 ),
79 'directory_list_terms' => array(
80 'arguments' => array('terms' => NULL, 'title' => '', 'parent' => 0),
81 ),
82 'directory_pager_detail' => array(
83 'arguments' => array('limit' => NULL, 'element' => 0, 'format' => '%d through %d of %d.'),
84 ),
85 'directory_home_vocabulary' => array(
86 'arguments' => array('vid' => NULL, 'collapse' => TRUE),
87 ),
88 'directory_resource' => array(
89 'arguments' => array('tid' => NULL, 'filter' => NULL, 'fid' => NULL),
90 ),
91 'directory_taxonomy_subterms' => array(
92 'arguments' => array('tid' => NULL),
93 ),
94 );
95 }
96
97 /********************************************************************
98 * Menu callbacks.
99 * ******************************************************************/
100
101 /**
102 * Menu callback for directory/.
103 */
104 function directory_page() {
105 $output = '';
106 if ($help = variable_get('directory_help', '')) {
107 $output = '<div class="directory-help">' . $help . '</div>';
108 }
109 $allowed_vids = variable_get('directory_vocabularies_root', array());
110
111 if (empty($allowed_vids)) {
112 $output .= t('The module has not been properly configured yet. No vocabulary is set to be displayed.');
113 }
114
115 foreach (taxonomy_get_vocabularies() as $v) {
116 if (in_array($v->vid, $allowed_vids)) {
117 $output .= theme('directory_home_vocabulary', $v->vid);
118 }
119 }
120
121 return $output;
122 }
123
124 /**
125 * Menu callback for directory/vocabulary.
126 *
127 * @param $vid
128 * the vocabulary Id.
129 */
130 function directory_vocabulary_page($vid) {
131 $vocabulary = taxonomy_vocabulary_load($vid);
132 // If we don't have a real vocabulary, redirect to the main directory page.
133 if (!$vocabulary) {
134 drupal_goto('directory');
135 }
136 else {
137 return theme_directory_home_vocabulary($vocabulary->vid, FALSE);
138 }
139 }
140
141 /**
142 * Menu callback for admin/settings/directory.
143 */
144 function directory_admin_settings() {
145 global $user;
146 $output = '';
147
148 if (function_exists('taxonomy_help')) {
149 $vocs[0] = '<' . t('none') . '>';
150 foreach (taxonomy_get_vocabularies() as $vid => $voc) {
151 $vocs[$vid] = $voc->name;
152 }
153 }
154
155 $nodetypes = array();
156 foreach (node_get_types() AS $type) {
157 $nodetypes[$type->type] = $type->name;
158 }
159
160 $collapsed = TRUE;
161 $time = time();
162 $time_limit = $time - (60 * 60 * 24 * 30);
163 if (variable_get('directory_supported_' . $user->uid, 0) < $time_limit) {
164 $collapsed = FALSE;
165 variable_set('directory_supported_' . $user->uid, $time);
166 }
167
168 $form['directory_support_maintainers'] = array(
169 '#type' => 'fieldset',
170 '#title' => t('Support'),
171 '#collapsible' => TRUE,
172 '#collapsed' => $collapsed,
173 );
174
175
176 $form['directory_support_maintainers']['directory_support_text'] = array(
177 '#value' => '<p>'
178 . t("<strong>The directory module is charity-ware</strong>.") . '<br />'
179 . t("Please contribute back by supporting the charity work of the following web sites. ") . '<br />'
180 . t("None of the web sites listed here are for profit, and none of them carry advertising.") . '<br />'
181 . t("They are all <strong>web sites dedicated to creating a better tomorrow for the whole society</strong>.") . '<br />'
182 . '</p>'
183 . '<ul>'
184 . '<li>' . t('<a href="http://activistsolutions.org/">Activist Solutions</a>: harvesting grassroots power.') . '</li>'
185 . '<li>' . t('<a href="http://www.reuniting.info/">Reuniting</a>: healing with sexual relationships.') . '</li>'
186 . '<li>' . t('<a href="http://overshoot.tv/">Overshoot TV</a>: making high quality videos and documentaries promoting environmental and economical sustainability.') . '</li>'
187 . '<li>' . t('<a href="http://minguo.info/">Minguo.info</a>: promotting better voting systems, and an experiment in direct democracy.') . '</li>'
188 . '<li>' . t('<a href="http://www.wechange.org/">We Change</a>: because we live in a world of solutions...') . '</li>'
189 . '</ul>'
190 . '<p>'
191 . t("You can support those web sites in the following ways:") . '<br />'
192 . '</p>'
193 . '<ul>'
194 . '<li>' . t("Blog about them.") . '</li>'
195 . '<li>' . t("Put links in a block in a sidebar.") . '</li>'
196 . '<li>' . t("Put links in any other logical place in your web site, where your visitors will find the information useful.") . '</li>'
197 . '<li>' . t("Register and participate if they match your own interest!") . '</li>'
198 . '<li>' . t("We also appreciate if, on behalf of this maintainer, you help <em>any charity of your choice</em>, or/and make a donation to them.") . '</li>'
199 . '</ul>'
200 . '<p>'
201 . t("Please, let the maintainer know about the options you chose.") . '<br />'
202 . '</p>'
203 . '<p>'
204 . t("Thank you for your support and cooperation.") . '<br />'
205 . '</p>',
206 );
207
208 $form['directory_support_maintainers']['directory_maintainers'] = array(
209 '#type' => 'markup',
210 '#value' => '<div style="border: solid 1px #eee; margin: .5em; padding: .5em;"> Module development sponsored by
211 <ul>
212 <li><a href="http://exodusdev.com">Exodus Development</a> (Drupal 4.7)</li>
213 <li><a href="http://activistsolutions.org/">Activist Solutions</a> (Drupal 5 onwards)</li>
214 <li><a href="http://minguo.info/">minguo.info</a> (Drupal 5 onwards)</li>
215 </ul></div>',
216 );
217
218 $form['directory_vocabularies_root'] = array(
219 '#type' => 'select',
220 '#title' => t('Which vocabularies should be displayed on the directory main page'),
221 '#default_value' => variable_get('directory_vocabularies_root', ''),
222 '#options' => $vocs,
223 '#description' => t('The vocabularies that will visible at the root level of the directory page.'),
224 '#extra' => 0,
225 '#multiple' => TRUE,
226 );
227
228 $form['directory_vocabularies_collapsed'] = array(
229 '#type' => 'select',
230 '#title' => t('Which vocabularies are collapsed by default?'),
231 '#description' => t('The checked vocabularies will be collapsed by default if they are shown on the main directory page.'),
232 '#options' => $vocs,
233 '#default_value' => variable_get('directory_vocabularies_collapsed', array()),
234 '#required' => FALSE,
235 '#extra' => 0,
236 '#multiple' => TRUE,
237 );
238
239 $form['directory_show_child_counts'] = array(
240 '#type' => 'checkbox',
241 '#title' => t('Show count of nodes in categories'),
242 '#default_value' => variable_get('directory_show_child_counts', TRUE),
243 '#description' => t('Append a count of items contained in each term, if the count is greater than zero.'),
244 '#required' => FALSE,
245 );
246
247 $form['directory_hide_empty_terms'] = array(
248 '#type' => 'checkbox',
249 '#title' => t('Hide terms with no content'),
250 '#default_value' => variable_get('directory_hide_empty_terms', FALSE),
251 '#description' => t('If checked, hide taxonomy terms having no node content.'),
252 '#required' => FALSE,
253 );
254
255 $form['directory_help'] = array(
256 '#type' => 'textarea',
257 '#title' => t('Help text for the Directory home'),
258 '#default_value' => variable_get('directory_help', ''),
259 '#cols' => 70,
260 '#rows' => 5,
261 '#description' => t('This text will be displayed at the top of <strong>the main directory page</strong>. It is useful for helping or instructing your users.'),
262 );
263
264 $form['directory_term_help'] = array(
265 '#type' => 'textarea',
266 '#title' => t('Help text for each Directory term page'),
267 '#default_value' => variable_get('directory_term_help', ''),
268 '#cols' => 70,
269 '#rows' => 5,
270 '#description' => t('This text will be displayed at the top of <strong>each directory term page</strong>. It is useful for helping or instructing your users.'),
271 );
272
273
274 $form['directory_support_websites'] = array(
275 '#type' => 'fieldset',
276 '#title' => t("Other charitable web sites..."),
277 '#collapsible' => TRUE,
278 '#collapsed' => TRUE,
279 );
280 $form['directory_support_websites']['directory_support_other'] = array(
281 '#value' => '<p>'
282 . t("If your web site meets <em>all</em> the following criteria, you can ask for it to be listed here.")
283 . '</p>'
284 . '<ul>'
285 . '<li>' . t('It uses directory module.') . '</li>'
286 . '<li>' . t('It is a charity (registered or not) dedicated to creating a better society.') . '</li>'
287 . '<li>' . t('It is not for profit.') . '</li>'
288 . '<li>' . t('It does not carry any advertising (e.g. google ads).') . '</li>'
289 . '</ul>',
290 );
291
292 return system_settings_form($form);
293 }
294
295
296 /********************************************************************
297 * Drupal Hooks :: Themeable Functions
298 * ******************************************************************/
299
300 /**
301 * @addtogroup themeable
302 * @{
303 */
304
305
306 /**
307 * Theme one section of the directory home page, corresponding to one vocabulary.
308 * There will be as many sections as there are vocabularies displayed on the home page.
309 *
310 * @param $vid
311 * integer: the vocabulary ID.
312 *
313 * @param $collapse
314 * boolean: say if the vocabulary should follow the collapsed setting.
315 * if we are going to print only one vocabulary
316 * it would be bad design to have it collapsed.
317 *
318 * @return $output
319 * formatted html.
320 */
321 function theme_directory_home_vocabulary($vid, $collapse = TRUE) {
322 static $js_added;
323 $vocabulary = taxonomy_vocabulary_load($vid);
324 $terms = taxonomy_get_children(0, $vid);
325
326
327 $collapsed_vids = array();
328 if ($collapse) {
329 $collapsed_vids = variable_get('directory_vocabularies_collapsed', array());
330 }
331
332 $collapsed_string = '';
333 if (in_array($vid, $collapsed_vids)) {
334 $collapsed_string = 'directory-home-vocabulary-collapsed';
335 }
336
337 if (empty($js_added)) {
338 drupal_add_js(drupal_get_path('module', 'directory') . '/directory.js');
339 drupal_add_js("var toggleT = " . drupal_to_js(t('show / hide')) . ';', 'inline');
340 $js_added = TRUE;
341 }
342
343 $output = '<div class="directory-home-vocabulary ' . $collapsed_string . ' directory-home-vocabulary-collapsible" id="directory-vid-' . $vocabulary->vid . '">';
344 $output .= theme('directory_list_terms', $terms, t('By !vocabulary-name',
345 array('!vocabulary-name' => l($vocabulary->name, 'directory/vocabulary/'. $vocabulary->vid))));
346 $output .= '</div>';
347
348 return $output;
349 }
350
351 /**
352 * Display a list of terms
353 * Each list item is a link to its corresponding term page.
354 *
355 * @param $terms
356 * An array of term objects.
357 *
358 * @param $title
359 * Translated text.
360 *
361 // FIXME: $parent not needed ?? beginner.
362 * @param $parent
363 * Display all the children whose parent tid is $parent.
364 * If we are on the main page, $parent = 0 and all terms within the vocabulary are displayed.
365 * If we are on a term page, $parent = $tid of that term and we display only the sub-terms.
366 *
367 * @return
368 * formatted html
369 */
370 function theme_directory_list_terms($terms, $title = '', $parent = 0) {
371 $output = '';
372 $showcounts = variable_get('directory_show_child_counts', TRUE);
373 $hideempty = variable_get('directory_hide_empty_terms', FALSE);
374
375 $item_span = '';
376
377 // Build a list of categories (taxonomy terms) and child counts.
378 foreach ($terms as $term) {
379 $nodecount = array('count_own' => 0, 'count_children' => 0);
380 if ($showcounts || $hideempty) {
381 $nodecount = directory_taxonomy_term_count_nodes($term->tid);
382 }
383
384 $nodecount_span = '';
385 if ($showcounts) {
386 $item_span = '<span class="directory-category-nochildren">';
387 if ($nodecount['count_own'] || $nodecount['count_children']) {
388 $item_span = '<span class="directory-category-haschildren">';
389 $nodecount_span = theme('directory_node_count', $nodecount, $term);
390 }
391 }
392
393 // if desired, exclude items
394 if ((!$hideempty) || ($nodecount['count_own'] || $nodecount['count_children'])) {
395 $children = taxonomy_get_children($term->tid);
396 if (is_array($children)) {
397 $children = theme('directory_list_subterms', $children);
398 }
399 $items[] = array('data' => $item_span . l($term->name, "taxonomy/term/$term->tid", (($term->description) ? array('title' => $term->description) : array())) . $nodecount_span . '</span>', 'children' => $children);
400 }
401 }
402
403 $output = theme('item_list', $items, $title);
404 return $output;
405 }
406
407 /**
408 * Prints the number of nodes that belong to a term.
409 *
410 * @param $nodecount
411 * array returned by directory_taxonomy_term_count_nodes($term->tid)
412 *
413 * @param $term
414 * term object that may be needed by some themes.
415 *
416 * @return
417 * either an empty string '' if there is nothing to display,
418 * or formatted HTML.
419 *
420 */
421 function theme_directory_node_count($nodecount, $term) {
422 $output = "<span class='directory-nodecount'> [" . $nodecount['count_own'];
423 $output .= $nodecount['count_children'] ? ' + ' . $nodecount['count_children'] . ']</span>' : ']</span>';
424 return $output;
425 }
426
427 /**
428 * Recursively display the sub-terms within a themed list
429 *
430 * @param $terms
431 * An array of term objects.
432 *
433 * @return
434 * array of elements to put in the themed list.
435 */
436 function theme_directory_list_subterms($terms) {
437 $items = array();
438 $showcounts = variable_get('directory_show_child_counts', TRUE);
439 $hideempty = variable_get('directory_hide_empty_terms', FALSE);
440 foreach ($terms as $term) {
441 $nodecount = 0;
442 if ($showcounts || $hideempty) {
443 $nodecount = directory_taxonomy_term_count_nodes($term->tid);
444 }
445 $nodecount_span = '';
446 $item_span = '';
447 if ($showcounts) {
448 $item_span = '<span class="directory-category-nochildren">';
449 if ($nodecount['count_own'] || $nodecount['count_children']) {
450 $item_span = '<span class="directory-category-haschildren">';
451 $nodecount_span = theme('directory_node_count', $nodecount, $term);
452 }
453 }
454 // if desired, exclude items
455 if ((!$hideempty) || ($nodecount['count_own'] || $nodecount['count_children'])) {
456 $children = NULL;
457 if ($get_children = taxonomy_get_children($term->tid)) {
458 $children = theme('directory_list_subterms', $get_children);
459 }
460
461 $items[] = array('data' => $item_span . l($term->name, "taxonomy/term/$term->tid", (($term->description) ? array('title' => $term->description) : array())) . $nodecount_span . '</span>', 'children' => $children);
462 }
463 }
464 return $items;
465 }
466
467 /**
468 * Format a summary of the current pager position, such as "6 through 10 of 52".
469 *
470 * @param $limit
471 * The number of query results to display per page.
472 * @param $element
473 * An optional integer to distinguish between multiple pagers on one page.
474 * @param $format
475 * A printf-style format string for customizing the pager text.
476 * @return
477 * An HTML string that generates this piece of the query pager.
478 *
479 * @ingroup themeable
480 */
481 function theme_directory_pager_detail($limit, $element = 0, $format = '%d through %d of %d.') {
482 global $pager_from_array, $_directory_pager_total;
483
484 $output = '<div class="pager-detail">';
485 if ($_directory_pager_total[$element] > (int)$pager_from_array[$element] + 1) {
486 $output .= sprintf($format, (int)$pager_from_array[$element] + 1, ((int)$pager_from_array[$element] + $limit <= $_directory_pager_total[$element] ? (int)$pager_from_array[$element] + $limit : $_directory_pager_total[$element]), $_directory_pager_total[$element]);
487 }
488 $output .= '</div>';
489
490 return $output;
491 }
492
493 /**
494 * Theme a container to list children terms of a taxonomy term.
495 *
496 * @param $tid integer
497 * the ID of the term whose children to display
498 */
499 function theme_directory_taxonomy_subterms($tids) {
500 $tids = explode(' ', $tids); // assuming $tid1+$tid2.
501 if (1 == count($tids)) {
502 $tids = explode(',', $tids[0]); // looking for $tid1,$tid2 instead.
503 }
504 $output = '';
505
506 // If we have more than one term, we print a link to a single term page.
507 $add_link = FALSE;
508 if (count($tids) > 1) {
509 $add_link = TRUE;
510 }
511
512 foreach ($tids AS $tid) {
513 $term = taxonomy_get_term($tid);
514 if ($children = taxonomy_get_children($tid)) {
515 $output .= '<div class="subterms">';
516 $items = theme('directory_list_subterms', $children);
517 if ($add_link) {
518 $title = t('Subterms for !term', array('!term' => l($term->name, 'taxonomy/term/' . $term->tid)));
519 }
520 else {
521 $title = t('Subterms');
522 }
523 $output .= theme('item_list', $items, $title);
524 $output .= '</div>';
525 }
526 }
527 return $output;
528 }
529
530
531 /** @} End of addtogroup themeable */
532
533 /********************************************************************
534 * Module Specific :: Private Functions
535 * ******************************************************************/
536
537 /**
538 * Set the title of a directory view as well as create the breadcrumb trail
539 * back to the directory root.
540 */
541 function directory_set_breadcrumb($tid) {
542 $breadcrumb[] = l(t('Home'), '');
543 $breadcrumb[] = l(t('browse'), 'directory');
544
545 $taxonomy = array_reverse(taxonomy_get_parents_all($tid));
546 $term = array_pop($taxonomy);
547 $current_page = $term->name;
548 drupal_set_title($current_page);
549
550 foreach ($taxonomy as $term) {
551 $breadcrumb[] = l($term->name, "taxonomy/term/$term->tid");
552 }
553 if ($current_page) {
554 $breadcrumb[] = "<strong>$current_page</strong>";
555 }
556
557 drupal_set_breadcrumb($breadcrumb);
558 }
559
560 /**
561 * Return a navigaton toolbar for alphatical directory browsing.
562 */
563 function directory_toolbar_alpha($current_letter) {
564 $letters = array('0-9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
565 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z');
566 foreach ($letters as $letter) {
567 $items[] = l($letter, 'directory/' . drupal_strtolower($letter), (drupal_strtoupper($current_letter) == $letter ? array('class' => 'active') : array()));
568 }
569
570 return '<div class="directory-toolbar alpha">' . implode(' ', $items) . '</div>';
571 }
572
573 /**
574 * Create the filter links to sort a directory by another vocabulary.
575 */
576 function directory_filters_toolbar($uri) {
577 $output = '';
578
579 $uri_array = explode('/', $uri);
580 foreach ($uri_array as $key => $part) {
581 if ($part == 'directory' || $part == 'eiir_search' && is_numeric($uri_array[$key + 1])) {
582 $tid = $uri_array[$key + 1];
583 $clean_uri = $part . '/' . $tid;
584 $current_filter = trim(str_replace($clean_uri, '', $uri), '/');
585 }
586 }
587
588 if ($clean_uri && $tid) {
589 foreach (taxonomy_get_vocabularies() as $v) {
590 $valid_filters[$v->name] = "vid/$v->vid";
591 }
592
593 $vid = db_result(db_query('SELECT vid FROM {term_data} WHERE tid = %d', $tid));
594 $hide_filter = "vid/$vid";
595 $current_filter = (!$current_filter) ? 'alpha' : $current_filter;
596
597 $output = '<div class="directory-filter-wrapper">' . t('Sort by:<br />');
598 foreach ($valid_filters as $name => $filter_params_as_uri) {
599 if ($hide_filter != $filter_params_as_uri) {
600 if (strstr($current_filter, $filter_params_as_uri)) {
601 $links[] = '<input type="radio" name="sorted" checked="checked" /> ' . t("<strong>$name</strong>");
602 }
603 else {
604 $new_uri = $clean_uri;
605 if ($filter_params_as_uri != 'alpha') {
606 $new_uri .= '/' . $filter_params_as_uri;
607 }
608
609 $url = url($new_uri);
610 $links[] = '<input type="radio" name="sorted" onClick="javascript:void(window.location.href = \'' . $url . '\')" /> ' . l($name, $url);
611 }
612 }
613 }
614 $output .= implode('<br />', $links) . '</div>';
615 }
616
617 return $output;
618 }
619
620 /**
621 * This is a replacement function for taxonomy_term_count_nodes.
622 * See: http://drupal.org/node/144969 (drupal issue)
623 * and: http://drupal.org/node/145023 (directory issue).
624 *
625 * Count the number of published nodes classified by a term.
626 *
627 * @param $tid
628 * The term's ID
629 *
630 * @param $type
631 * The $node->type. If given, taxonomy_term_count_nodes only counts
632 * nodes of $type that are classified with the term $tid.
633 *
634 * @param $save_to_db
635 * This function is recursive, and we don't need to save the result in the DB at each iteration.
636 * $save_to_db is set to FALSE at each nested call, so that the actual saving to DB can happen only
637 * when the function exits the last time.
638 *
639 * @return $array
640 * where:
641 * $array['count_own'] being the number of nodes within the term proper.
642 * $array['count_children'] being the number of nodes in children terms, not counting those which are already counted in the parent term.
643 * $array['own_nodes'] array of nid's within this $tid.
644 * $array['children_nodes'] array of all the descendent nid's from children terms, not including those already set as one's own.
645 *
646 * Results are statically cached.
647 * Also, in order to improve performance accross requests, we cache the serialized array on database, in {cache_page} (this table is flushed each time a node or a taxonomy item is added/updated/deleted).
648 */
649 function directory_taxonomy_term_count_nodes($tid, $type = 0, $save_to_db = TRUE) {
650 static $count = array();
651 $modified = FALSE; // We keep track of modification of $count, to check whether we need to save it to DB.
652
653 if (empty($count)) {
654 $count = cache_get('taxonomy_term_count_nodes', 'cache_page');
655 if ($count) {
656 $count = unserialize($count->data);
657 }
658 else { // Initialize $count if the cache is empty.
659 $count = array();
660 }
661 }
662
663 if (!isset($count[$type])) {
664 $modified = TRUE;
665 $count[$type] = array();
666 // In the queries below, we cannot use 'SELECT t.tid, COUNT(n.nid) AS c FROM ...'
667 // because a node may be assigned more than one term and be counted more than once.
668 // We therefore take note of the nid's and count the number of items in the $count array,
669 // making sure there is no duplicate.
670
671 // $type == 0 always evaluates TRUE if $type is a string
672 if (is_numeric($type)) {
673 $result = db_query(db_rewrite_sql('SELECT t.tid, n.nid FROM {term_node} t JOIN {node} n ON t.nid = n.nid WHERE n.status = 1', 't', 'tid'));
674 }
675 else {
676 $result = db_query(db_rewrite_sql("SELECT t.tid, n.nid FROM {term_node} t JOIN {node} n ON t.nid = n.nid WHERE n.status = 1 AND n.type = '%s'", 't', 'tid'), $type);
677 }
678 while ($item = db_fetch_object($result)) {
679 if (!isset($count[$type][$item->tid])) {
680 $count[$type][$item->tid] = array('own_nodes' => array(), 'count_children' => 0, 'children_nodes' => array());
681 }
682 $count[$type][$item->tid]['own_nodes'][$item->nid] = 1;
683 }
684 }
685
686 if (!isset($count[$type][$tid]['count_own'])) {
687 $modified = TRUE;
688
689 if (!isset($count[$type][$tid]['own_nodes'])) { // It's an empty term, not set in the previous code block.
690 $count[$type][$tid] = array('count_own' => 0, 'own_nodes' => array(), 'count_children' => 0, 'children_nodes' => array());
691 }
692 else {
693 $count[$type][$tid]['count_own'] = count($count[$type][$tid]['own_nodes']);
694 }
695
696 foreach (_taxonomy_term_children($tid) as $c) {
697 if ($children = directory_taxonomy_term_count_nodes($c, $type, FALSE)) { // FALSE: we do not need to save $count in the db at this iteration.
698 // Add the children's own nodes:
699 if (is_array($children['own_nodes'])) {
700 foreach ($children['own_nodes'] AS $child_nid => $n) {
701 if (!isset($count[$type][$tid]['own_nodes'][$child_nid])) { // make sure the nid is not already counted for the parent.
702 $count[$type][$tid]['children_nodes'][$child_nid] = 1;
703 }
704 }
705 }
706 // Add the nodes of the children's children.
707 if (is_array($children['children_nodes'])) {
708 foreach ($children['children_nodes'] AS $child_nid => $n) {
709 if (!isset($count[$type][$tid]['own_nodes'][$child_nid])) { // make sure the nid is not already counted for the parent.
710 $count[$type][$tid]['children_nodes'][$child_nid] = 1;
711 }
712 }
713 }
714 }
715 }
716 $count[$type][$tid]['count_children'] = count($count[$type][$tid]['children_nodes']);
717 }
718
719 if ($modified && $save_to_db) {
720 $cache = serialize($count);
721 // the cached data will be used for at least one hour before being flushed.
722 // TODO, make the nb of seconds before this cache is cleared configurable: time() + variable_get();
723 cache_set('taxonomy_term_count_nodes', $cache, 'cache_page', time() + 60 * 60);
724 }
725
726 return $count[$type][$tid];
727 }
728

  ViewVC Help
Powered by ViewVC 1.1.2