diff --git term_node_count.info term_node_count.info index 0f5075e..06de31f 100644 --- term_node_count.info +++ term_node_count.info @@ -1,10 +1,11 @@ ; $Id: term_node_count.info,v 1.1 2009/02/02 03:41:47 archard Exp $ -name = Term Node Count -description = Provides a means for displaying the number of nodes associated with a term efficiently. +name = Term Node Count Domain +description = Provides a means for displaying the number of nodes associated with a term efficiently. Patched to support domain and i18n access core = 6.x version = "6.x-1.0" dependencies[] = taxonomy +dependencies[] = domain ; Information added by drupal.org packaging script on 2009-03-05 version = "6.x-1.3" core = "6.x" diff --git term_node_count.install term_node_count.install index 75c20d7..0a5bbe2 100644 --- term_node_count.install +++ term_node_count.install @@ -7,18 +7,17 @@ */ function term_node_count_install() { drupal_install_schema('term_node_count'); + drupal_load('module', 'term_node_count'); // we have to set the weight high so that our module's hooks run after node and taxonomy $sql = "UPDATE {system} SET weight = 10 WHERE name = 'term_node_count'"; db_query($sql); - // first we'll count all the number of published, current revisions for each term that has at least one - $sql = 'INSERT INTO {term_node_count} (tid, node_count) (SELECT tid, COUNT(np.nid) FROM {term_node} tn LEFT JOIN {node} np ON tn.vid = np.vid AND np.status = 1 GROUP BY tid)'; - db_query($sql); - - // then we'll say that if there is a term id that isnt in term_count_count then it has 0 nodes - $sql = 'INSERT INTO {term_node_count} (tid, node_count) (SELECT tid, 0 FROM {term_data} WHERE tid NOT IN (SELECT tid FROM {term_node_count}))'; - db_query($sql); + // Use utility functions to return counts for all domains and tids + // Per-domain big COUNT()s would be quicker, but this is a one-off install + // action. And this means hook_install() works the same as hook_nodeapi("update") + $domains = domain_domains(); + term_node_count_update(array("all"), $domains); } /** @@ -40,6 +39,12 @@ function term_node_count_schema() { 'not null' => TRUE, 'default' => 0 ), + 'gid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'default' => 0 + ), 'node_count' => array( 'type' => 'int', 'unsigned' => TRUE, @@ -47,7 +52,7 @@ function term_node_count_schema() { 'default' => 0 ) ), - 'primary key' => array('tid') + 'primary key' => array('tid', 'gid') ); return $schema; -} \ No newline at end of file +} diff --git term_node_count.module term_node_count.module index 67f180c..d12ddf7 100644 --- term_node_count.module +++ term_node_count.module @@ -48,7 +48,7 @@ function term_node_count_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { // since the node is first being created, all we have to do // is check which terms were saved to term_node $tids_to_update = term_node_count_saved_terms($node); - term_node_count_update($tids_to_update); + term_node_count_update($tids_to_update, $node->domains); break; case 'presave': // when a node is updated we need to first get the tids previously saved @@ -65,7 +65,7 @@ function term_node_count_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { $submitted_tids = term_node_count_submitted_terms($node->taxonomy); $tids_to_update = $saved_tids + $submitted_tids; $tids_to_update = array_unique($tids_to_update); - term_node_count_update($tids_to_update); + term_node_count_update($tids_to_update, $node->domains); } break; case 'delete': @@ -74,22 +74,27 @@ function term_node_count_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { foreach ($node->taxonomy as $tid => $term) { $tids_to_update[$tid] = $tid; } - term_node_count_update($tids_to_update); + term_node_count_update($tids_to_update, $node->domains); break; } } /** * Updates terms in term_node_count given an array of tids. + * + * Note during hook_install, $tids_to_update = array("all"). + * This gets passed into term_node_count_count_nodes() which returns all tid counts */ -function term_node_count_update($tids_to_update) { +function term_node_count_update($tids_to_update, $domains) { // go through each tid provided, count the number of nodes attached // to it and update the term_node_count table if (!empty($tids_to_update)) { - $sql = 'UPDATE {term_node_count} SET node_count = %d WHERE tid = %d'; - $counts = term_node_count_count_nodes($tids_to_update); - foreach ($counts as $tid => $count) { - db_query($sql, $count, $tid); + $sql = 'INSERT INTO term_node_count (tid, gid, node_count) VALUES (%d, %d, %d) ON DUPLICATE KEY UPDATE gid=%d, node_count=%d'; + foreach ($domains as $gid => $domain) { + $counts = term_node_count_count_nodes($tids_to_update, $gid); + foreach ($counts as $tid => $count) { + db_query($sql, $tid, $gid, $count, $gid, $count); + } } } } @@ -98,19 +103,35 @@ function term_node_count_update($tids_to_update) { * Function used to count nodes. It's like taxonomy_term_count_nodes but without static caching. * Also I don't think child terms should be included. */ -function term_node_count_count_nodes($terms) { +function term_node_count_count_nodes($terms, $gid) { if (!empty($terms)) { - $tids_list = implode(',', $terms); - $tids_list = rtrim($tids_list, ','); - // note that we're only bringing back published nodes - $sql = "SELECT tid, COUNT(tid) AS count FROM {term_node} tn INNER JOIN {node} n ON tn.vid = n.vid WHERE tid IN (%s) AND n.status = 1 GROUP BY tid"; - $result = db_query($sql, $tids_list); + // Because da.realm can bring back 0, 1 or 2 rows, we have to do + // a DISTINCT subquery and only then count over it. + // This could have some performance impact on many (10,000s) nodes + $count_sql = "SELECT num_subquery.tid, COUNT(*) AS num FROM (SELECT DISTINCT tn.tid AS tid, n.nid AS num " + . " FROM {term_node} tn LEFT JOIN {node} n ON tn.vid = n.vid " # join on vid to permit revisioning + . " LEFT JOIN {domain_access} da ON n.nid = da.nid " + . " WHERE n.status = 1 " # only return published nodes + . " AND (da.realm = 'domain_site' OR (da.realm = 'domain_id' AND da.gid = %d) )"; # include cross-site content + + $count_args = array($gid); + + // Hack to let this work during hook_install phase + // If we're sent a single term argument of "all", return ALL tids + if ($terms[0] != "all") { + $count_sql .= " AND tn.tid IN (". db_placeholders($terms) . ") "; + $count_args = array_merge($count_args, $terms); + } + + // COUNT() needs a GROUP BY clause + $count_sql .= ") AS num_subquery GROUP BY num_subquery.tid "; + $result = db_query($count_sql, $count_args); $counts = array(); while ($term = db_fetch_object($result)) { - $counts[$term->tid] = $term->count; + $counts[$term->tid] = $term->num; } - // if the term id didn't return any results, then there are no nodes attached to it + // If a given term tid didn't return a node count row, then explicitly set zero counts foreach ($terms as $tid) { if (!isset($counts[$tid])) { $counts[$tid] = 0; @@ -206,4 +227,4 @@ function term_node_count_views_api() { return array( 'api' => 2 ); -} \ No newline at end of file +} diff --git term_node_count.views.inc term_node_count.views.inc index 1369a65..02ad29b 100644 --- term_node_count.views.inc +++ term_node_count.views.inc @@ -9,11 +9,17 @@ function term_node_count_views_data() { $data = array(); $data['term_node_count']['table']['group'] = t('Taxonomy'); + + // Define the joins. $data['term_node_count']['table']['join']['term_data'] = array( 'left_field' => 'tid', 'field' => 'tid' ); + + // Define the fields. $data['term_node_count']['node_count'] = array( + 'title' => t('Term Node Count'), + 'help' => t('The number of nodes associated with this term'), 'field' => array( 'handler' => 'term_node_count_handler_field' ), @@ -24,8 +30,22 @@ function term_node_count_views_data() { 'handler' => 'views_handler_sort' ) ); - $data['term_node_count']['node_count']['title'] = t('Term Node Count'); - $data['term_node_count']['node_count']['help'] = t('The number of nodes associated with this term'); + $data['term_node_count']['gid'] = array( + 'title' => t('Term Node Count Domain ID'), + 'help' => t('The unique id key for the active domain.'), + 'field' => array( + 'click sortable' => TRUE, + 'handler' => 'domain_views_handler_field_domain_id', + ), + // Information for accepting a domain_id as a filter + 'filter' => array( + 'handler' => 'domain_views_handler_filter_domain_domain_id', + ), + // Information for sorting on a domain_id. + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + ); return $data; } @@ -40,4 +60,4 @@ function term_node_count_views_handlers() { ) ) ); -} \ No newline at end of file +}