diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/taxonomy/taxonomy.api.php | 6 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.module | 187 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.test | 44 |
3 files changed, 186 insertions, 51 deletions
diff --git a/modules/taxonomy/taxonomy.api.php b/modules/taxonomy/taxonomy.api.php index 21790e17b..7c3106bb6 100644 --- a/modules/taxonomy/taxonomy.api.php +++ b/modules/taxonomy/taxonomy.api.php @@ -20,8 +20,10 @@ * @param $vocabulary * A taxonomy vocabulary object. */ -function hook_taxonomy_vocabulary_load($vocabulary) { - $vocabulary->synonyms = variable_get('taxonomy_' . $vocabulary->vid . '_synonyms', FALSE); +function hook_taxonomy_vocabulary_load($vocabularies) { + foreach ($vocabularies as $vocabulary) { + $vocabulary->synonyms = variable_get('taxonomy_' . $vocabulary->vid . '_synonyms', FALSE); + } } /** diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module index 39ee62af3..96823daa9 100644 --- a/modules/taxonomy/taxonomy.module +++ b/modules/taxonomy/taxonomy.module @@ -452,31 +452,9 @@ function taxonomy_form_all($free_tags = 0) { * @param $type * If set, return only those vocabularies associated with this node type. */ -function taxonomy_get_vocabularies($type = NULL) { - if ($type) { - $result = db_query(db_rewrite_sql("SELECT v.vid, v.*, n.type FROM {taxonomy_vocabulary} v LEFT JOIN {taxonomy_vocabulary_node_type} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", 'v', 'vid'), $type); - } - else { - $result = db_query(db_rewrite_sql('SELECT v.*, n.type FROM {taxonomy_vocabulary} v LEFT JOIN {taxonomy_vocabulary_node_type} n ON v.vid = n.vid ORDER BY v.weight, v.name', 'v', 'vid')); - } - - $vocabularies = array(); - $node_types = array(); - while ($voc = db_fetch_object($result)) { - // If no node types are associated with a vocabulary, the LEFT JOIN will - // return a NULL value for type. - if (isset($voc->type)) { - $node_types[$voc->vid][$voc->type] = $voc->type; - unset($voc->type); - $voc->nodes = $node_types[$voc->vid]; - } - elseif (!isset($voc->nodes)) { - $voc->nodes = array(); - } - $vocabularies[$voc->vid] = $voc; - } - - return $vocabularies; +function taxonomy_get_vocabularies($type = NULL, $reset = FALSE) { + $conditions = !empty($type) ? array('type' => $type) : NULL; + return taxonomy_vocabulary_load_multiple(array(), $conditions, $reset); } /** @@ -967,44 +945,157 @@ function taxonomy_get_term_by_name($name) { } /** - * Return the vocabulary object matching a vocabulary ID. + * Load multiple taxonomy vocabularies based on certain conditions. * - * @param $vid - * The vocabulary's ID. + * This function should be used whenever you need to load more than one + * vocabulary from the database. Terms are loaded into memory and will not + * require database access if loaded again during the same page request. * + * @param $vids + * An array of taxonomy vocabulary IDs. + * @param $conditions + * An array of conditions to add to the query. * @param $reset - * A boolean flag indicating whether to reset the internal cache. + * Whether to reset the internal cache. * * @return - * The vocabulary object with all of its metadata, if exists, FALSE otherwise. - * Results are statically cached. + * An array of vocabulary objects, indexed by vid. */ -function taxonomy_vocabulary_load($vid, $reset = FALSE) { - static $vocabularies = array(); +function taxonomy_vocabulary_load_multiple($vids = array(), $conditions = array(), $reset = FALSE) { + static $vocabulary_cache = array(); + // Node type associations are not stored in the vocabulary table, so remove + // this from conditions into it's own variable. + if (isset($conditions['type'])) { + $type = $conditions['type']; + unset($conditions['type']); + } if ($reset) { - unset($vocabularies[$vid]); + $vocabulary_cache = array(); + } + + $vocabularies = array(); + + // Create a new variable which is either a prepared version of the $vids + // array for later comparison with the term cache, or FALSE if no $vids were + // passed. The $vids array is reduced as items are loaded from cache, and we + // need to know if it's empty for this reason to avoid querying the database + // when all requested items are loaded from cache. + $passed_vids = !empty($vids) ? array_flip($vids) : FALSE; + + // Load any available items from the internal cache. + if ($vocabulary_cache) { + if ($vids) { + $vocabularies += array_intersect_key($vocabulary_cache, $passed_vids); + // If any items were loaded, remove them from the $vids still to load. + $vids = array_keys(array_diff_key($passed_vids, $vocabularies)); + } + // If only conditions is passed, load all items from the cache. Items + // which don't match conditions will be removed later. + elseif ($conditions) { + $vocabularies = $vocabulary_cache; + } } - if (empty($vocabularies[$vid])) { - // Initialize so if this vocabulary does not exist, we have - // that cached, and we will not try to load this later. - $vocabularies[$vid] = FALSE; - // Try to load the data and fill up the object. - $result = db_query('SELECT v.*, n.type FROM {taxonomy_vocabulary} v LEFT JOIN {taxonomy_vocabulary_node_type} n ON v.vid = n.vid WHERE v.vid = %d', $vid); + // Remove any loaded terms from the array if they don't match $conditions. + if ($conditions || isset($type)) { + foreach ($vocabularies as $vocabulary) { + $vocabulary_values = (array) $vocabulary; + if (array_diff_assoc($conditions, $vocabulary_values)) { + unset($vocabularies[$vocabulary->vid]); + } + if (isset($type) && !in_array($type, $vocabulary->nodes)) { + unset($vocabularies[$vocabulary->vid]); + } + } + } + + // Load any remaining vocabularies from the database, this is necessary if + // we have $vids still to load, or if no $vids were passed. + if ($vids || !$passed_vids) { + $query = db_select('taxonomy_vocabulary', 'v'); + $query->fields('v'); + $query->addField('n', 'type'); + $query->orderBy('v.weight'); + $query->orderBy('v.name'); + + if (!empty($type)) { + $query->leftJoin('taxonomy_vocabulary_node_type', 'n', 'v.vid = n.vid WHERE n.type = :type', array(':type' => $type)); + } + else { + $query->leftJoin('taxonomy_vocabulary_node_type', 'n', 'v.vid = n.vid'); + } + + // If the $vids array is populated, add those to the query. + if ($vids) { + $query->condition('v.vid', $vids, 'IN'); + } + + // If the conditions array is populated, add those to the query. + if ($conditions) { + foreach ($conditions as $field => $value) { + $query->condition('v.' . $field, $value); + } + } + $result = $query->execute(); + + $queried_vocabularies = array(); $node_types = array(); - while ($voc = db_fetch_object($result)) { - if (!empty($voc->type)) { - $node_types[$voc->type] = $voc->type; + foreach ($result as $record) { + // If no node types are associated with a vocabulary, the LEFT JOIN will + // return a NULL value for type. + if (isset($record->type)) { + $node_types[$record->vid][$record->type] = $record->type; + unset($record->type); + $record->nodes = $node_types[$record->vid]; } - unset($voc->type); - $voc->nodes = $node_types; - $vocabularies[$vid] = $voc; + elseif (!isset($record->nodes)) { + $record->nodes = array(); + } + $queried_vocabularies[$record->vid] = $record; + } + + // Invoke hook_taxonomy_vocabulary_load() on the vocabularies loaded from + // the database and add them to the static cache. + if (!empty($queried_vocabularies)) { + foreach (module_implements('taxonomy_vocabulary_load') as $module) { + $function = $module . '_taxonomy_vocabulary_load'; + $function($queried_vocabularies); + } + $vocabularies += $queried_vocabularies; + $vocabulary_cache += $queried_vocabularies; + } + } + + // Ensure that the returned array is ordered the same as the original $vids + // array if this was passed in and remove any invalid vids. + if ($passed_vids) { + // Remove any invalid vids from the array. + $passed_vids = array_intersect_key($passed_vids, $vocabularies); + foreach ($vocabularies as $vocabulary) { + $passed_vids[$vocabulary->vid] = $vocabulary; } + $vocabularies = $passed_vids; } - // Return FALSE if this vocabulary does not exist. - return !empty($vocabularies[$vid]) ? $vocabularies[$vid] : FALSE; + return $vocabularies; +} + +/** + * Return the vocabulary object matching a vocabulary ID. + * + * @param $vid + * The vocabulary's ID. + * + * @param $reset + * A boolean flag indicating whether to reset the internal cache. + * + * @return + * The vocabulary object with all of its metadata, if exists, FALSE otherwise. + * Results are statically cached. + */ +function taxonomy_vocabulary_load($vid, $reset = FALSE) { + return reset(taxonomy_vocabulary_load_multiple(array($vid), array(), $reset)); } /** diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test index 1c02294c5..a32a48cfc 100644 --- a/modules/taxonomy/taxonomy.test +++ b/modules/taxonomy/taxonomy.test @@ -213,7 +213,7 @@ function getInfo() { * Ensure that the vocabulary static reset works correctly. */ function testTaxonomyVocabularyLoadStaticReset() { - $original_vocabulary = taxonomy_vocabulary_load($this->vocabulary->vid); + $original_vocabulary = taxonomy_vocabulary_load($this->vocabulary->vid, TRUE); $this->assertTrue(is_object($original_vocabulary), t('Vocabulary loaded successfully')); $this->assertEqual($this->vocabulary->name, $original_vocabulary->name, t('Vocabulary loaded successfully')); @@ -233,6 +233,48 @@ function getInfo() { $vocabularies = taxonomy_get_vocabularies(); $this->assertTrue(!isset($vocabularies[$this->vocabulary->vid]), t('The vocabulary was deleted')); } + + /** + * Tests for loading multiple vocabularies. + */ + function testTaxonomyVocabularyLoadMultiple() { + + // Delete any existing vocabularies. + foreach (taxonomy_get_vocabularies() as $vocabulary) { + taxonomy_vocabulary_delete($vocabulary->vid); + } + + // Create some vocabularies and assign weights. + $vocabulary1 = $this->createVocabulary(); + $vocabulary1->weight = 0; + taxonomy_vocabulary_save($vocabulary1); + $vocabulary2 = $this->createVocabulary(); + $vocabulary2->weight = 1; + taxonomy_vocabulary_save($vocabulary2); + $vocabulary3 = $this->createVocabulary(); + $vocabulary3->weight = 2; + taxonomy_vocabulary_save($vocabulary3); + + // Fetch all of the vocabularies using taxonomy_get_vocabularies(). + // Confirm that the vocabularies are ordered by weight. + $vocabularies = taxonomy_get_vocabularies(); + $this->assertEqual(array_shift($vocabularies), $vocabulary1, t('Vocabulary was found in the vocabularies array.')); + $this->assertEqual(array_shift($vocabularies), $vocabulary2, t('Vocabulary was found in the vocabularies array.')); + $this->assertEqual(array_shift($vocabularies), $vocabulary3, t('Vocabulary was found in the vocabularies array.')); + + // Fetch the vocabularies with taxonomy_vocabulary_load_multiple(), specifying IDs. + // Ensure they are returned in the same order as the original array. + $vocabularies = taxonomy_vocabulary_load_multiple(array($vocabulary3->vid, $vocabulary2->vid, $vocabulary1->vid)); + $this->assertEqual(array_shift($vocabularies), $vocabulary3, t('Vocabulary loaded successfully by ID.')); + $this->assertEqual(array_shift($vocabularies), $vocabulary2, t('Vocabulary loaded successfully by ID.')); + $this->assertEqual(array_shift($vocabularies), $vocabulary1, t('Vocabulary loaded successfully by ID.')); + + // Fetch vocabulary 1 by name. + $this->assertTrue(current(taxonomy_vocabulary_load_multiple(array(), array('name' => $vocabulary1->name))) == $vocabulary1, t('Vocabulary loaded successfully by name.')); + + // Fetch vocabulary 1 by name and ID. + $this->assertTrue(current(taxonomy_vocabulary_load_multiple(array($vocabulary1->vid), array('name' => $vocabulary1->name))) == $vocabulary1, t('Vocabulary loaded successfully by name and ID.')); + } } /** |