Commit 8fa274af authored by webchick's avatar webchick

#144969 by beginner, Wim Leers, and catch: Fix count returned by...

#144969 by beginner, Wim Leers, and catch: Fix count returned by taxonomy_term_count_nodes() with multi-select vocabularies (with tests).
parent 585aa50e
......@@ -798,14 +798,14 @@ function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
*
* @param $vid
* Which vocabulary to generate the tree for.
*
* @param $parent
* The term ID under which to generate the tree. If 0, generate the tree
* for the entire vocabulary.
*
* @param $max_depth
* The number of levels of the tree to return. Leave NULL to return all levels.
*
* @param $reset
* Whether to reset the static cache, you should only use this if
* updating and loading term hierarchies during a page request.
* @param $depth
* Internal use only.
*
......@@ -814,9 +814,13 @@ function taxonomy_get_children($tid, $vid = 0, $key = 'tid') {
* to have "depth" and "parents" attributes in addition to its normal ones.
* Results are statically cached.
*/
function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $depth = -1) {
function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $reset = FALSE, $depth = -1) {
static $children, $parents, $terms;
if ($reset) {
$children = $parents = $terms = array();
}
$depth++;
// We cache trees, so it's not CPU-intensive to call get_tree() on a term
......@@ -845,7 +849,7 @@ function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $depth = -1) {
$tree[] = $term;
if (!empty($children[$vid][$child])) {
$tree = array_merge($tree, taxonomy_get_tree($vid, $child, $max_depth, $depth));
$tree = array_merge($tree, taxonomy_get_tree($vid, $child, $max_depth, $reset, $depth));
}
}
}
......@@ -898,61 +902,47 @@ function taxonomy_get_synonym_root($synonym, $reset = FALSE) {
* Count the number of published nodes classified by a term.
*
* @param $tid
* The term's ID
*
* The term ID
* @param $type
* The $node->type. If given, taxonomy_term_count_nodes only counts
* (Optional) The $node->type. If given, taxonomy_term_count_nodes only counts
* nodes of $type that are classified with the term $tid.
* @param $reset
* (Optional) Boolean to indicated whether to reset the internal cache.
*
* @return int
* @return
* An integer representing a number of nodes.
* Results are statically cached.
*/
function taxonomy_term_count_nodes($tid, $type = 0) {
static $count;
if (!isset($count[$type])) {
// $type == 0 always evaluates TRUE if $type is a string
if (is_numeric($type)) {
$result = db_query(db_rewrite_sql('SELECT t.tid, COUNT(n.nid) AS c FROM {taxonomy_term_node} t INNER JOIN {node} n ON t.vid = n.vid WHERE n.status = 1 GROUP BY t.tid'));
}
else {
$result = db_query(db_rewrite_sql("SELECT t.tid, COUNT(n.nid) AS c FROM {taxonomy_term_node} t INNER JOIN {node} n ON t.vid = n.vid WHERE n.status = 1 AND n.type = '%s' GROUP BY t.tid"), $type);
}
$count[$type] = array();
while ($term = db_fetch_object($result)) {
$count[$type][$term->tid] = $term->c;
}
}
$children_count = 0;
foreach (_taxonomy_term_children($tid) as $c) {
$children_count += taxonomy_term_count_nodes($c, $type);
function taxonomy_term_count_nodes($tid, $type = NULL, $reset = FALSE) {
static $count = array();
if ($reset) {
$count = array();
}
return $children_count + (isset($count[$type][$tid]) ? $count[$type][$tid] : 0);
}
/**
* Helper for taxonomy_term_count_nodes(). Used to find out
* which terms are children of a parent term.
*
* @param $tid
* The parent term's ID
*
* @return array
* An array of term IDs representing the children of $tid.
* Results are statically cached.
*
*/
function _taxonomy_term_children($tid) {
static $children;
// If $type is NULL, change it to 0 to allow it to be used as an array key
// for the static cache.
$type = empty($type) ? 0 : $type;
if (!isset($children)) {
$result = db_query('SELECT tid, parent FROM {taxonomy_term_hierarchy}');
while ($term = db_fetch_object($result)) {
$children[$term->parent][] = $term->tid;
if (!isset($count[$type][$tid])) {
$term = taxonomy_term_load($tid);
$tree = taxonomy_get_tree($term->vid, $tid, NULL, $reset);
$tids = array($tid);
foreach ($tree as $descendent) {
$tids[] = $descendent->tid;
}
$query = db_select('taxonomy_term_node', 't');
$query->addExpression('COUNT(DISTINCT(n.nid))', 'nid_count');
$query->join('node', 'n', 't.vid = n.vid');
$query->condition('t.tid', $tids, 'IN');
$query->condition('n.status', 1);
if (!is_numeric($type)) {
$query->condition('n.type', $type);
}
$query->addTag('term_access');
$count[$type][$tid] = $query->execute()->fetchField();
}
return isset($children[$tid]) ? $children[$tid] : array();
return $count[$type][$tid];
}
/**
......
......@@ -236,6 +236,81 @@ function getInfo() {
}
}
/**
* Unit tests for taxonomy term functions.
*/
class TaxonomyTermUnitTest extends TaxonomyWebTestCase {
function getInfo() {
return array(
'name' => t('Taxonomy term unit tests'),
'description' => t('Unit tests for taxonomy term functions.'),
'group' => t('Taxonomy'),
);
}
/**
* Tests for taxonomy_term_count_nodes().
*
* Attach nodes to a hierarchical vocabulary and check they are counted
* correctly.
*/
function testTaxonomyTermCountNodes() {
// Create a vocabulary with three terms.
$vocabulary = $this->createVocabulary();
$term1 = $this->createTerm($vocabulary->vid);
$term2 = $this->createTerm($vocabulary->vid);
$term3 = $this->createTerm($vocabulary->vid);
// Attach term1 to a node.
$node1 = $this->drupalCreateNode(array('type' => 'page'));
$node1->taxonomy = array($term1->tid);
node_save($node1);
$this->assertEqual(taxonomy_term_count_nodes($term1->tid), 1, t('Term has one valid node association.'));
// Attach term2 to a node.
$node2 = $this->drupalCreateNode(array('type' => 'article'));
$node2->taxonomy = array($term2->tid);
node_save($node2);
$this->assertEqual(taxonomy_term_count_nodes($term2->tid), 1, t('Term has one valid node association.'));
// Confirm that term3 is not associated with any nodes.
//$this->assertEqual(taxonomy_term_count_nodes($term3->tid), NULL, t('Term is not associated with any nodes'));
// Set term3 as the parent of term1.
$term1->parent = array($term3->tid);
taxonomy_term_save($term1);
// Confirm that the term hierarchy is altered correctly.
$children = taxonomy_get_children($term3->tid);
$this->assertTrue(isset($children[$term1->tid]), t('Term 3 saved as parent of term 1'));
// Reset the taxonomy_get_tree() static cache to avoid stale data, since
// the hierarchy has been updated during this page request.
$this->assertEqual(count(taxonomy_get_tree($term3->vid, $term3->tid, NULL, TRUE)), 1, t('Term 3 has one child term'));
// Confirm that term3's parental relationship with term1 leads to a
// node assocation being counted.
$this->assertEqual(taxonomy_term_count_nodes($term3->tid, NULL, TRUE), 1, t('Term has one valid node association due to child term.'));
// Set term3 as the parent of term2.
$term2->parent = array($term3->tid);
taxonomy_term_save($term2);
// term3 should now have two node associations counted.
$this->assertEqual(taxonomy_term_count_nodes($term3->tid, NULL, TRUE), 2, t('Term has two valid node associations due to child terms.'));
// Save node1 with both child taxonomy terms, this should still result
// in term3 having two node associations.
$node1->taxonomy = array($term1->tid, $term2->tid);
node_save($node1);
$this->assertEqual(taxonomy_term_count_nodes($term3->tid, NULL, TRUE), 2, t('Term has two valid node associations.'));
// Confirm that the node type argument returns a single node association.
$this->assertEqual(taxonomy_term_count_nodes($term3->tid, 'page', TRUE), 1, t("Term is associated with one node of type 'page'."));
}
}
/**
* Tests for taxonomy term functions.
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment