/** * 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. * * @see taxonomy_build_node_index() */ protected function buildNodeIndex($node) { // We maintain a denormalized table of term/node relationships, containing // only data for current, published nodes. $status = NULL; if (variable_get('taxonomy_maintain_index_table', TRUE)) { // 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 (!empty($field['settings']['target_type']) && $field['settings']['target_type'] == 'taxonomy_term' && $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['target_id']] = $item['target_id']; } } } } // Re-calculate the terms added in taxonomy_build_node_index() so // we can optimize database queries. $original_tid_all = array(); 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) { $original_tid_all[$item['tid']] = $item['tid']; } } } } } // Insert index entries for all the node's terms, that were not // already inserted in taxonomy_build_node_index(). $tid_all = array_diff($tid_all, $original_tid_all); // 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('nid' => $node->nid, 'tid' => $tid, 'sticky' => $sticky, 'created' => $node->created)); } $query->execute(); } } }
/** * Write field data for an entity. * * This hook is invoked from field_attach_insert() and field_attach_update(), * to ask the field storage module to save field data. * * @param $entity_type * The entity type of entity, such as 'node' or 'user'. * @param $entity * The entity on which to operate. * @param $op * FIELD_STORAGE_UPDATE when updating an existing entity, * FIELD_STORAGE_INSERT when inserting a new entity. * @param $fields * An array listing the fields to be written. The keys and values of the * array are field IDs. */ function hook_field_storage_write($entity_type, $entity, $op, $fields) { list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity); if (!isset($vid)) { $vid = $id; } foreach ($fields as $field_id) { $field = field_info_field_by_id($field_id); $field_name = $field['field_name']; $table_name = _field_sql_storage_tablename($field); $revision_name = _field_sql_storage_revision_tablename($field); $all_languages = field_available_languages($entity_type, $field); $field_languages = array_intersect($all_languages, array_keys((array) $entity->{$field_name})); // Delete and insert, rather than update, in case a value was added. if ($op == FIELD_STORAGE_UPDATE) { // Delete languages present in the incoming $entity->$field_name. // Delete all languages if $entity->$field_name is empty. $languages = !empty($entity->{$field_name}) ? $field_languages : $all_languages; if ($languages) { db_delete($table_name)->condition('entity_type', $entity_type)->condition('entity_id', $id)->condition('language', $languages, 'IN')->execute(); db_delete($revision_name)->condition('entity_type', $entity_type)->condition('entity_id', $id)->condition('revision_id', $vid)->condition('language', $languages, 'IN')->execute(); } } // Prepare the multi-insert query. $do_insert = FALSE; $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'delta', 'language'); foreach ($field['columns'] as $column => $attributes) { $columns[] = _field_sql_storage_columnname($field_name, $column); } $query = db_insert($table_name)->fields($columns); $revision_query = db_insert($revision_name)->fields($columns); foreach ($field_languages as $langcode) { $items = (array) $entity->{$field_name}[$langcode]; $delta_count = 0; foreach ($items as $delta => $item) { // We now know we have someting to insert. $do_insert = TRUE; $record = array('entity_type' => $entity_type, 'entity_id' => $id, 'revision_id' => $vid, 'bundle' => $bundle, 'delta' => $delta, 'language' => $langcode); foreach ($field['columns'] as $column => $attributes) { $record[_field_sql_storage_columnname($field_name, $column)] = isset($item[$column]) ? $item[$column] : NULL; } $query->values($record); if (isset($vid)) { $revision_query->values($record); } if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) { break; } } } // Execute the query if we have values to insert. if ($do_insert) { $query->execute(); $revision_query->execute(); } } }
/** * Given a relationship, gets the stub entity for the source. * * @param array $relationship The relationship array. * * @return bool|mixed Either the stub entity or false on error. */ protected function getSourceStubEntity(array $relationship) { $field_name = $relationship['field_name']; $source_entity_ids = entity_get_id_by_uuid($relationship['source_type'], array($relationship['source_uuid'])); $source_entity_id = count($source_entity_ids) > 0 ? reset($source_entity_ids) : null; $source_entity_vids = entity_get_id_by_uuid($relationship['source_type'], array($relationship['source_vuuid']), true); $source_entity_vid = count($source_entity_vids) > 0 ? reset($source_entity_vids) : false; if (!$source_entity_id) { return false; } // Get the bundle for the source entity. $source_entity_bundle = Entity::getBundleFromID($relationship['source_type'], $source_entity_id); if (!$source_entity_bundle) { return false; } // Get the stub entity for the source. $source_stub = Entity::getStub($relationship['source_type'], $source_entity_id, $source_entity_bundle, $source_entity_vid); // Load the existing field onto the entity. $field_instance_info = field_info_instance($relationship['source_type'], $field_name, $source_entity_bundle); if ($field_instance_info === false) { return false; } try { // First, load the revisions. field_attach_load_revision($relationship['source_type'], array($source_entity_id => $source_stub), array('field_id' => $field_instance_info['field_id'])); // Second, get the original deltas for the revision. $deltas = db_select('field_revision_' . $field_name, 'fr')->fields('fr', array('language', 'delta'))->condition($source_entity_vid ? 'revision_id' : 'entity_id', $source_entity_vid ? $source_entity_vid : $source_entity_id)->condition('language', field_available_languages($relationship['source_type'], $field_instance_info), 'IN')->orderBy('delta')->execute(); // Assign the deltas to their languages. $deltas_languages = array(); foreach ($deltas as $delta) { if (!array_key_exists($delta->language, $deltas_languages)) { $deltas_languages[$delta->language] = array(); } $deltas_languages[$delta->language][] = $delta->delta; } // Reset the deltas to their correct orders. $field_value =& $source_stub->{$field_name}; foreach ($deltas_languages as $language => $deltas) { $new_value = array(); for ($i = 0; $i < count($field_value[$language]); $i++) { $new_value[$deltas[$i]] = $field_value[$language][$i]; } $field_value[$language] = $new_value; } } catch (\Exception $ex) { // If an exception was thrown, that probably means the field doesn't // exist, so we should return false. return false; } return $source_stub; }