Issue #1050466 by xjm, makara: Fixed The taxonomy index should be maintained in a node hook, not a field hook.
parent
eb8c4c09a2
commit
1bb30a6f12
|
@ -1734,61 +1734,107 @@ function taxonomy_field_presave($entity_type, $entity, $field, $instance, $langc
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_field_insert().
|
* Implements hook_node_insert().
|
||||||
*/
|
*/
|
||||||
function taxonomy_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
function taxonomy_node_insert($node) {
|
||||||
|
// Add taxonomy index entries for the node.
|
||||||
|
taxonomy_build_node_index($node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds and inserts taxonomy index entries for a given node.
|
||||||
|
*
|
||||||
|
* The index lists all terms that are related to a given node entity, and is
|
||||||
|
* therefore maintained at the entity level.
|
||||||
|
*
|
||||||
|
* @param $node
|
||||||
|
* The node object.
|
||||||
|
*/
|
||||||
|
function taxonomy_build_node_index($node) {
|
||||||
// We maintain a denormalized table of term/node relationships, containing
|
// We maintain a denormalized table of term/node relationships, containing
|
||||||
// only data for current, published nodes.
|
// only data for current, published nodes.
|
||||||
if (variable_get('taxonomy_maintain_index_table', TRUE) && $field['storage']['type'] == 'field_sql_storage' && $entity_type == 'node' && $entity->status) {
|
$status = NULL;
|
||||||
$query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created', ));
|
if (variable_get('taxonomy_maintain_index_table', TRUE)) {
|
||||||
foreach ($items as $item) {
|
// If a node property is not set in the node object when node_save() is
|
||||||
|
// called, the old value from $node->original is used.
|
||||||
|
if (!empty($node->original)) {
|
||||||
|
$status = (int)(!empty($node->status) || (!isset($node->status) && !empty($node->original->status)));
|
||||||
|
$sticky = (int)(!empty($node->sticky) || (!isset($node->sticky) && !empty($node->original->sticky)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$status = (int)(!empty($node->status));
|
||||||
|
$sticky = (int)(!empty($node->sticky));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We only maintain the taxonomy index for published nodes.
|
||||||
|
if ($status) {
|
||||||
|
// Collect a unique list of all the term IDs from all node fields.
|
||||||
|
$tid_all = array();
|
||||||
|
foreach (field_info_instances('node', $node->type) as $instance) {
|
||||||
|
$field_name = $instance['field_name'];
|
||||||
|
$field = field_info_field($field_name);
|
||||||
|
if ($field['module'] == 'taxonomy' && $field['storage']['type'] == 'field_sql_storage') {
|
||||||
|
// If a field value is not set in the node object when node_save() is
|
||||||
|
// called, the old value from $node->original is used.
|
||||||
|
if (isset($node->{$field_name})) {
|
||||||
|
$items = $node->{$field_name};
|
||||||
|
}
|
||||||
|
elseif (isset($node->original->{$field_name})) {
|
||||||
|
$items = $node->original->{$field_name};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (field_available_languages('node', $field) as $langcode) {
|
||||||
|
if (!empty($items[$langcode])) {
|
||||||
|
foreach ($items[$langcode] as $item) {
|
||||||
|
$tid_all[$item['tid']] = $item['tid'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Insert index entries for all the node's terms.
|
||||||
|
if (!empty($tid_all)) {
|
||||||
|
$query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created'));
|
||||||
|
foreach ($tid_all as $tid) {
|
||||||
$query->values(array(
|
$query->values(array(
|
||||||
'nid' => $entity->nid,
|
'nid' => $node->nid,
|
||||||
'tid' => $item['tid'],
|
'tid' => $tid,
|
||||||
'sticky' => $entity->sticky,
|
'sticky' => $sticky,
|
||||||
'created' => $entity->created,
|
'created' => $node->created,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
$query->execute();
|
$query->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_field_update().
|
* Implements hook_node_update().
|
||||||
*/
|
*/
|
||||||
function taxonomy_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
|
function taxonomy_node_update($node) {
|
||||||
if (variable_get('taxonomy_maintain_index_table', TRUE) && $field['storage']['type'] == 'field_sql_storage' && $entity_type == 'node') {
|
// Always rebuild the node's taxonomy index entries on node save.
|
||||||
$first_call = &drupal_static(__FUNCTION__, array());
|
taxonomy_delete_node_index($node);
|
||||||
|
taxonomy_build_node_index($node);
|
||||||
// We don't maintain data for old revisions, so clear all previous values
|
|
||||||
// from the table. Since this hook runs once per field, per object, make
|
|
||||||
// sure we only wipe values once.
|
|
||||||
if (!isset($first_call[$entity->nid])) {
|
|
||||||
$first_call[$entity->nid] = FALSE;
|
|
||||||
db_delete('taxonomy_index')->condition('nid', $entity->nid)->execute();
|
|
||||||
}
|
|
||||||
// Only save data to the table if the node is published.
|
|
||||||
if ($entity->status) {
|
|
||||||
$query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created'));
|
|
||||||
foreach ($items as $item) {
|
|
||||||
$query->values(array(
|
|
||||||
'nid' => $entity->nid,
|
|
||||||
'tid' => $item['tid'],
|
|
||||||
'sticky' => $entity->sticky,
|
|
||||||
'created' => $entity->created,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
$query->execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements hook_node_delete().
|
* Implements hook_node_delete().
|
||||||
*/
|
*/
|
||||||
function taxonomy_node_delete($node) {
|
function taxonomy_node_delete($node) {
|
||||||
if (variable_get('taxonomy_maintain_index_table', TRUE)) {
|
|
||||||
// Clean up the {taxonomy_index} table when nodes are deleted.
|
// Clean up the {taxonomy_index} table when nodes are deleted.
|
||||||
|
taxonomy_delete_node_index($node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes taxonomy index entries for a given node.
|
||||||
|
*
|
||||||
|
* @param $node
|
||||||
|
* The node object.
|
||||||
|
*/
|
||||||
|
function taxonomy_delete_node_index($node) {
|
||||||
|
if (variable_get('taxonomy_maintain_index_table', TRUE)) {
|
||||||
db_delete('taxonomy_index')->condition('nid', $node->nid)->execute();
|
db_delete('taxonomy_index')->condition('nid', $node->nid)->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -863,6 +863,208 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the hook implementations that maintain the taxonomy index.
|
||||||
|
*/
|
||||||
|
class TaxonomyTermIndexTestCase extends TaxonomyWebTestCase {
|
||||||
|
|
||||||
|
public static function getInfo() {
|
||||||
|
return array(
|
||||||
|
'name' => 'Taxonomy term index',
|
||||||
|
'description' => 'Tests the hook implementations that maintain the taxonomy index.',
|
||||||
|
'group' => 'Taxonomy',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
parent::setUp('taxonomy');
|
||||||
|
|
||||||
|
// Create an administrative user.
|
||||||
|
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access'));
|
||||||
|
$this->drupalLogin($this->admin_user);
|
||||||
|
|
||||||
|
// Create a vocabulary and add two term reference fields to article nodes.
|
||||||
|
$this->vocabulary = $this->createVocabulary();
|
||||||
|
|
||||||
|
$this->field_name_1 = drupal_strtolower($this->randomName());
|
||||||
|
$this->field_1 = array(
|
||||||
|
'field_name' => $this->field_name_1,
|
||||||
|
'type' => 'taxonomy_term_reference',
|
||||||
|
'cardinality' => FIELD_CARDINALITY_UNLIMITED,
|
||||||
|
'settings' => array(
|
||||||
|
'allowed_values' => array(
|
||||||
|
array(
|
||||||
|
'vocabulary' => $this->vocabulary->machine_name,
|
||||||
|
'parent' => 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
field_create_field($this->field_1);
|
||||||
|
$this->instance_1 = array(
|
||||||
|
'field_name' => $this->field_name_1,
|
||||||
|
'bundle' => 'article',
|
||||||
|
'entity_type' => 'node',
|
||||||
|
'widget' => array(
|
||||||
|
'type' => 'options_select',
|
||||||
|
),
|
||||||
|
'display' => array(
|
||||||
|
'default' => array(
|
||||||
|
'type' => 'taxonomy_term_reference_link',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
field_create_instance($this->instance_1);
|
||||||
|
|
||||||
|
$this->field_name_2 = drupal_strtolower($this->randomName());
|
||||||
|
$this->field_2 = array(
|
||||||
|
'field_name' => $this->field_name_2,
|
||||||
|
'type' => 'taxonomy_term_reference',
|
||||||
|
'cardinality' => FIELD_CARDINALITY_UNLIMITED,
|
||||||
|
'settings' => array(
|
||||||
|
'allowed_values' => array(
|
||||||
|
array(
|
||||||
|
'vocabulary' => $this->vocabulary->machine_name,
|
||||||
|
'parent' => 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
field_create_field($this->field_2);
|
||||||
|
$this->instance_2 = array(
|
||||||
|
'field_name' => $this->field_name_2,
|
||||||
|
'bundle' => 'article',
|
||||||
|
'entity_type' => 'node',
|
||||||
|
'widget' => array(
|
||||||
|
'type' => 'options_select',
|
||||||
|
),
|
||||||
|
'display' => array(
|
||||||
|
'default' => array(
|
||||||
|
'type' => 'taxonomy_term_reference_link',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
field_create_instance($this->instance_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the taxonomy index is maintained properly.
|
||||||
|
*/
|
||||||
|
function testTaxonomyIndex() {
|
||||||
|
// Create terms in the vocabulary.
|
||||||
|
$term_1 = $this->createTerm($this->vocabulary);
|
||||||
|
$term_2 = $this->createTerm($this->vocabulary);
|
||||||
|
|
||||||
|
// Post an article.
|
||||||
|
$edit = array();
|
||||||
|
$langcode = LANGUAGE_NONE;
|
||||||
|
$edit["title"] = $this->randomName();
|
||||||
|
$edit["body[$langcode][0][value]"] = $this->randomName();
|
||||||
|
$edit["{$this->field_name_1}[$langcode][]"] = $term_1->tid;
|
||||||
|
$edit["{$this->field_name_2}[$langcode][]"] = $term_1->tid;
|
||||||
|
$this->drupalPost('node/add/article', $edit, t('Save'));
|
||||||
|
|
||||||
|
// Check that the term is indexed, and only once.
|
||||||
|
$node = $this->drupalGetNodeByTitle($edit["title"]);
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_1->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(1, $index_count, t('Term 1 is indexed once.'));
|
||||||
|
|
||||||
|
// Update the article to change one term.
|
||||||
|
$edit["{$this->field_name_1}[$langcode][]"] = $term_2->tid;
|
||||||
|
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
|
||||||
|
|
||||||
|
// Check that both terms are indexed.
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_1->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(1, $index_count, t('Term 1 is indexed.'));
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_2->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(1, $index_count, t('Term 2 is indexed.'));
|
||||||
|
|
||||||
|
// Update the article to change another term.
|
||||||
|
$edit["{$this->field_name_2}[$langcode][]"] = $term_2->tid;
|
||||||
|
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
|
||||||
|
|
||||||
|
// Check that only one term is indexed.
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_1->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(0, $index_count, t('Term 1 is not indexed.'));
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_2->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(1, $index_count, t('Term 2 is indexed once.'));
|
||||||
|
|
||||||
|
// Redo the above tests without interface.
|
||||||
|
$update_node = array(
|
||||||
|
'nid' => $node->nid,
|
||||||
|
'vid' => $node->vid,
|
||||||
|
'uid' => $node->uid,
|
||||||
|
'type' => $node->type,
|
||||||
|
'title' => $this->randomName(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update the article with no term changed.
|
||||||
|
$updated_node = (object) $update_node;
|
||||||
|
node_save($updated_node);
|
||||||
|
|
||||||
|
// Check that the index was not changed.
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_1->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(0, $index_count, t('Term 1 is not indexed.'));
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_2->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(1, $index_count, t('Term 2 is indexed once.'));
|
||||||
|
|
||||||
|
// Update the article to change one term.
|
||||||
|
$update_node[$this->field_name_1][$langcode] = array(array('tid' => $term_1->tid));
|
||||||
|
$updated_node = (object) $update_node;
|
||||||
|
node_save($updated_node);
|
||||||
|
|
||||||
|
// Check that both terms are indexed.
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_1->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(1, $index_count, t('Term 1 is indexed.'));
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_2->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(1, $index_count, t('Term 2 is indexed.'));
|
||||||
|
|
||||||
|
// Update the article to change another term.
|
||||||
|
$update_node[$this->field_name_2][$langcode] = array(array('tid' => $term_1->tid));
|
||||||
|
$updated_node = (object) $update_node;
|
||||||
|
node_save($updated_node);
|
||||||
|
|
||||||
|
// Check that only one term is indexed.
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_1->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(1, $index_count, t('Term 1 is indexed once.'));
|
||||||
|
$index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
|
||||||
|
':nid' => $node->nid,
|
||||||
|
':tid' => $term_2->tid,
|
||||||
|
))->fetchField();
|
||||||
|
$this->assertEqual(0, $index_count, t('Term 2 is not indexed.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the taxonomy_term_load_multiple() function.
|
* Test the taxonomy_term_load_multiple() function.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue