diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php index 2bed3f6..b7ae0b5 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php +++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php @@ -22,28 +22,9 @@ /** * Defines a base entity controller class. * - * Default implementation of Drupal\Core\Entity\EntityStorageControllerInterface. - * - * This class can be used as-is by most simple entity types. Entity types - * requiring special handling can extend the class. + * This class only supports bare, non-content entities. */ -class DatabaseStorageController extends FieldableEntityStorageControllerBase { - - /** - * Name of entity's revision database table field, if it supports revisions. - * - * Has the value FALSE if this entity does not use revisions. - * - * @var string - */ - protected $revisionKey; - - /** - * The table that stores revisions, if the entity supports revisions. - * - * @var string - */ - protected $revisionTable; +class DatabaseStorageController extends EntityStorageControllerBase { /** * Whether this entity type should use the static cache. @@ -75,8 +56,7 @@ public static function createInstance(ContainerInterface $container, $entity_typ return new static( $entity_type, $entity_info, - $container->get('database'), - $container->get('field.info') + $container->get('database') ); } @@ -89,14 +69,11 @@ public static function createInstance(ContainerInterface $container, $entity_typ * An array of entity info for the entity type. * @param \Drupal\Core\Database\Connection $database * The database connection to be used. - * @param \Drupal\field\FieldInfo $field_info - * The field info service. */ - public function __construct($entity_type, array $entity_info, Connection $database, FieldInfo $field_info) { + public function __construct($entity_type, array $entity_info, Connection $database) { parent::__construct($entity_type, $entity_info); $this->database = $database; - $this->fieldInfo = $field_info; // Check if the entity type supports IDs. if (isset($this->entityInfo['entity_keys']['id'])) { @@ -113,15 +90,6 @@ public function __construct($entity_type, array $entity_info, Connection $databa else { $this->uuidKey = FALSE; } - - // Check if the entity type supports revisions. - if (!empty($this->entityInfo['entity_keys']['revision'])) { - $this->revisionKey = $this->entityInfo['entity_keys']['revision']; - $this->revisionTable = $this->entityInfo['revision_table']; - } - else { - $this->revisionKey = FALSE; - } } /** @@ -200,50 +168,21 @@ public function load($id) { } /** - * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::loadRevision(). + * {@inheritdoc} */ public function loadRevision($revision_id) { - // Build and execute the query. - $query_result = $this->buildQuery(array(), $revision_id)->execute(); - - if (!empty($this->entityInfo['class'])) { - // We provide the necessary arguments for PDO to create objects of the - // specified entity class. - // @see Drupal\Core\Entity\EntityInterface::__construct() - $query_result->setFetchMode(\PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType)); - } - $queried_entities = $query_result->fetchAllAssoc($this->idKey); - - // Pass the loaded entities from the database through $this->attachLoad(), - // which attaches fields (if supported by the entity type) and calls the - // entity type specific load callback, for example hook_node_load(). - if (!empty($queried_entities)) { - $this->attachLoad($queried_entities, $revision_id); - } - return reset($queried_entities); + throw new \Exception('Database storage controller does not support revisions.'); } /** - * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::deleteRevision(). + * {@inheritdoc} */ public function deleteRevision($revision_id) { - if ($revision = $this->loadRevision($revision_id)) { - // Prevent deletion if this is the default revision. - if ($revision->isDefaultRevision()) { - throw new EntityStorageException('Default revision can not be deleted'); - } - - $this->database->delete($this->revisionTable) - ->condition($this->revisionKey, $revision->getRevisionId()) - ->execute(); - $this->invokeFieldMethod('deleteRevision', $revision); - $this->deleteFieldItemsRevision($revision); - $this->invokeHook('revision_delete', $revision); - } + throw new \Exception('Database storage controller does not support revisions.'); } /** - * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::loadByProperties(). + * {@inheritdoc} */ public function loadByProperties(array $values = array()) { // Build a query to fetch the entity IDs. @@ -271,19 +210,8 @@ protected function buildPropertyQuery(QueryInterface $entity_query, array $value /** * Builds the query to load the entity. * - * This has full revision support. For entities requiring special queries, - * the class can be extended, and the default query can be constructed by - * calling parent::buildQuery(). This is usually necessary when the object - * being loaded needs to be augmented with additional data from another - * table, such as loading node type into comments or vocabulary machine name - * into terms, however it can also support $conditions on different tables. - * See Drupal\comment\CommentStorageController::buildQuery() for an example. - * * @param array|null $ids * An array of entity IDs, or NULL to load all entities. - * @param $revision_id - * The ID of the revision to load, or FALSE if this query is asking for the - * most current revision(s). * * @return SelectQuery * A SelectQuery object for loading the entity. @@ -293,37 +221,9 @@ protected function buildQuery($ids, $revision_id = FALSE) { $query->addTag($this->entityType . '_load_multiple'); - if ($revision_id) { - $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id)); - } - elseif ($this->revisionKey) { - $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}"); - } - // Add fields from the {entity} table. $entity_fields = drupal_schema_fields_sql($this->entityInfo['base_table']); - if ($this->revisionKey) { - // Add all fields from the {entity_revision} table. - $entity_revision_fields = drupal_map_assoc(drupal_schema_fields_sql($this->entityInfo['revision_table'])); - // The id field is provided by entity, so remove it. - unset($entity_revision_fields[$this->idKey]); - - // Remove all fields from the base table that are also fields by the same - // name in the revision table. - $entity_field_keys = array_flip($entity_fields); - foreach ($entity_revision_fields as $name) { - if (isset($entity_field_keys[$name])) { - unset($entity_fields[$entity_field_keys[$name]]); - } - } - $query->fields('revision', $entity_revision_fields); - - // Compare revision id of the base and revision table, if equal then this - // is the default revision. - $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isDefaultRevision'); - } - $query->fields('base', $entity_fields); if ($ids) { @@ -336,41 +236,21 @@ protected function buildQuery($ids, $revision_id = FALSE) { /** * Attaches data to entities upon loading. * - * This will attach fields, if the entity is fieldable. It calls - * hook_entity_load() for modules which need to add data to all entities. - * It also calls hook_TYPE_load() on the loaded entities. For example - * hook_node_load() or hook_user_load(). If your hook_TYPE_load() - * expects special parameters apart from the queried entities, you can set - * $this->hookLoadArguments prior to calling the method. - * See Drupal\node\NodeStorageController::attachLoad() for an example. - * * @param $queried_entities * Associative array of query results, keyed on the entity ID. * @param $load_revision * (optional) TRUE if the revision should be loaded, defaults to FALSE. */ protected function attachLoad(&$queried_entities, $load_revision = FALSE) { - // Attach field values. - if ($this->entityInfo['fieldable']) { - $this->loadFieldItems($queried_entities, $load_revision ? static::FIELD_LOAD_REVISION : static::FIELD_LOAD_CURRENT); - } - // Call hook_entity_load(). foreach (\Drupal::moduleHandler()->getImplementations('entity_load') as $module) { $function = $module . '_entity_load'; $function($queried_entities, $this->entityType); } - // Call hook_TYPE_load(). The first argument for hook_TYPE_load() are - // always the queried entities, followed by additional arguments set in - // $this->hookLoadArguments. - $args = array_merge(array($queried_entities), $this->hookLoadArguments); - foreach (\Drupal::moduleHandler()->getImplementations($this->entityType . '_load') as $module) { - call_user_func_array($module . '_' . $this->entityType . '_load', $args); - } } /** - * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::create(). + * {@inheritdoc} */ public function create(array $values) { $entity_class = $this->entityInfo['class']; @@ -393,7 +273,7 @@ public function create(array $values) { } /** - * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::delete(). + * {@inheritdoc} */ public function delete(array $entities) { if (!$entities) { @@ -414,19 +294,11 @@ public function delete(array $entities) { ->condition($this->idKey, $ids, 'IN') ->execute(); - if ($this->revisionKey) { - $this->database->delete($this->revisionTable) - ->condition($this->idKey, $ids, 'IN') - ->execute(); - } - // Reset the cache as soon as the changes have been applied. $this->resetCache($ids); $entity_class::postDelete($this, $entities); foreach ($entities as $entity) { - $this->invokeFieldMethod('delete', $entity); - $this->deleteFieldItems($entity); $this->invokeHook('delete', $entity); } // Ignore slave server temporarily. @@ -440,7 +312,7 @@ public function delete(array $entities) { } /** - * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::save(). + * {@inheritdoc} */ public function save(EntityInterface $entity) { $transaction = $this->database->startTransaction(); @@ -451,39 +323,21 @@ public function save(EntityInterface $entity) { } $entity->preSave($this); - $this->invokeFieldMethod('preSave', $entity); $this->invokeHook('presave', $entity); if (!$entity->isNew()) { - if ($entity->isDefaultRevision()) { - $return = drupal_write_record($this->entityInfo['base_table'], $entity, $this->idKey); - } - else { - // @todo, should a different value be returned when saving an entity - // with $isDefaultRevision = FALSE? - $return = FALSE; - } - if ($this->revisionKey) { - $this->saveRevision($entity); - } + $return = drupal_write_record($this->entityInfo['base_table'], $entity, $this->idKey); $this->resetCache(array($entity->id())); $entity->postSave($this, TRUE); - $this->invokeFieldMethod('update', $entity); - $this->saveFieldItems($entity, TRUE); $this->invokeHook('update', $entity); } else { $return = drupal_write_record($this->entityInfo['base_table'], $entity); - if ($this->revisionKey) { - $this->saveRevision($entity); - } // Reset general caches, but keep caches specific to certain entities. $this->resetCache(array()); $entity->enforceIsNew(FALSE); $entity->postSave($this, FALSE); - $this->invokeFieldMethod('insert', $entity); - $this->saveFieldItems($entity, FALSE); $this->invokeHook('insert', $entity); } @@ -501,694 +355,10 @@ public function save(EntityInterface $entity) { } /** - * Saves an entity revision. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity object. - */ - protected function saveRevision(EntityInterface $entity) { - // Convert the entity into an array as it might not have the same properties - // as the entity, it is just a raw structure. - $record = (array) $entity; - - // When saving a new revision, set any existing revision ID to NULL so as to - // ensure that a new revision will actually be created. - if ($entity->isNewRevision() && $record[$this->revisionKey]) { - $record[$this->revisionKey] = NULL; - } - - // Cast to object as preSaveRevision() expects one to be compatible with the - // upcoming NG storage controller. - $record = (object) $record; - $entity->preSaveRevision($this, $record); - $record = (array) $record; - - if ($entity->isNewRevision()) { - drupal_write_record($this->revisionTable, $record); - if ($entity->isDefaultRevision()) { - $this->database->update($this->entityInfo['base_table']) - ->fields(array($this->revisionKey => $record[$this->revisionKey])) - ->condition($this->idKey, $entity->id()) - ->execute(); - } - $entity->setNewRevision(FALSE); - } - else { - drupal_write_record($this->revisionTable, $record, $this->revisionKey); - } - // Make sure to update the new revision key for the entity. - $entity->{$this->revisionKey} = $record[$this->revisionKey]; - } - - /** * {@inheritdoc} */ public function getQueryServiceName() { return 'entity.query.sql'; } - /** - * {@inheritdoc} - */ - protected function doLoadFieldItems($entities, $age) { - $load_current = $age == static::FIELD_LOAD_CURRENT; - - // Collect entities ids and bundles. - $bundles = array(); - $ids = array(); - foreach ($entities as $key => $entity) { - $bundles[$entity->bundle()] = TRUE; - $ids[] = $load_current ? $key : $entity->getRevisionId(); - } - - // Collect impacted fields. - $fields = array(); - foreach ($bundles as $bundle => $v) { - foreach ($this->fieldInfo->getBundleInstances($this->entityType, $bundle) as $field_name => $instance) { - $fields[$field_name] = $instance->getField(); - } - } - - // Load field data. - $all_langcodes = array_keys(language_list()); - foreach ($fields as $field_name => $field) { - $table = $load_current ? static::_fieldTableName($field) : static::_fieldRevisionTableName($field); - - // If the field is translatable ensure that only values having valid - // languages are retrieved. Since we are loading values for multiple - // entities, we cannot limit the query to the available translations. - $langcodes = $field['translatable'] ? $all_langcodes : array(Language::LANGCODE_NOT_SPECIFIED); - $results = $this->database->select($table, 't') - ->fields('t') - ->condition($load_current ? 'entity_id' : 'revision_id', $ids, 'IN') - ->condition('deleted', 0) - ->condition('langcode', $langcodes, 'IN') - ->orderBy('delta') - ->execute(); - - $delta_count = array(); - foreach ($results as $row) { - if (!isset($delta_count[$row->entity_id][$row->langcode])) { - $delta_count[$row->entity_id][$row->langcode] = 0; - } - - if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->langcode] < $field['cardinality']) { - $item = array(); - // For each column declared by the field, populate the item from the - // prefixed database column. - foreach ($field['columns'] as $column => $attributes) { - $column_name = static::_fieldColumnName($field, $column); - // Unserialize the value if specified in the column schema. - $item[$column] = (!empty($attributes['serialize'])) ? unserialize($row->$column_name) : $row->$column_name; - } - - // Add the item to the field values for the entity. - $entities[$row->entity_id]->getTranslation($row->langcode)->{$field_name}[$delta_count[$row->entity_id][$row->langcode]] = $item; - $delta_count[$row->entity_id][$row->langcode]++; - } - } - } - } - - /** - * {@inheritdoc} - */ - protected function doSaveFieldItems(EntityInterface $entity, $update) { - $vid = $entity->getRevisionId(); - $id = $entity->id(); - $bundle = $entity->bundle(); - $entity_type = $entity->entityType(); - if (!isset($vid)) { - $vid = $id; - } - - foreach ($this->fieldInfo->getBundleInstances($entity_type, $bundle) as $field_name => $instance) { - $field = $instance->getField(); - $table_name = static::_fieldTableName($field); - $revision_name = static::_fieldRevisionTableName($field); - - // Delete and insert, rather than update, in case a value was added. - if ($update) { - // Only overwrite the field's base table if saving the default revision - // of an entity. - if ($entity->isDefaultRevision()) { - $this->database->delete($table_name) - ->condition('entity_id', $id) - ->execute(); - } - $this->database->delete($revision_name) - ->condition('entity_id', $id) - ->condition('revision_id', $vid) - ->execute(); - } - - // Prepare the multi-insert query. - $do_insert = FALSE; - $columns = array('entity_id', 'revision_id', 'bundle', 'delta', 'langcode'); - foreach ($field['columns'] as $column => $attributes) { - $columns[] = static::_fieldColumnName($field, $column); - } - $query = $this->database->insert($table_name)->fields($columns); - $revision_query = $this->database->insert($revision_name)->fields($columns); - - $langcodes = $field['translatable'] ? array_keys($entity->getTranslationLanguages()) : array(Language::LANGCODE_NOT_SPECIFIED); - foreach ($langcodes as $langcode) { - $items = $entity->getTranslation($langcode)->{$field_name}->getValue(); - if (!isset($items)) { - continue; - } - $delta_count = 0; - foreach ($items as $delta => $item) { - // We now know we have someting to insert. - $do_insert = TRUE; - $record = array( - 'entity_id' => $id, - 'revision_id' => $vid, - 'bundle' => $bundle, - 'delta' => $delta, - 'langcode' => $langcode, - ); - foreach ($field['columns'] as $column => $attributes) { - $column_name = static::_fieldColumnName($field, $column); - $value = isset($item[$column]) ? $item[$column] : NULL; - // Serialize the value if specified in the column schema. - $record[$column_name] = (!empty($attributes['serialize'])) ? serialize($value) : $value; - } - $query->values($record); - $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) { - // Only overwrite the field's base table if saving the default revision - // of an entity. - if ($entity->isDefaultRevision()) { - $query->execute(); - } - $revision_query->execute(); - } - } - } - - /** - * {@inheritdoc} - */ - protected function doDeleteFieldItems(EntityInterface $entity) { - foreach ($this->fieldInfo->getBundleInstances($entity->entityType(), $entity->bundle()) as $instance) { - $field = $instance->getField(); - $table_name = static::_fieldTableName($field); - $revision_name = static::_fieldRevisionTableName($field); - $this->database->delete($table_name) - ->condition('entity_id', $entity->id()) - ->execute(); - $this->database->delete($revision_name) - ->condition('entity_id', $entity->id()) - ->execute(); - } - } - - /** - * {@inheritdoc} - */ - protected function doDeleteFieldItemsRevision(EntityInterface $entity) { - $vid = $entity->getRevisionId(); - if (isset($vid)) { - foreach ($this->fieldInfo->getBundleInstances($entity->entityType(), $entity->bundle()) as $instance) { - $revision_name = static::_fieldRevisionTableName($instance->getField()); - $this->database->delete($revision_name) - ->condition('entity_id', $entity->id()) - ->condition('revision_id', $vid) - ->execute(); - } - } - } - - /** - * {@inheritdoc} - */ - public function onFieldCreate(FieldInterface $field) { - $schema = $this->_fieldSqlSchema($field); - foreach ($schema as $name => $table) { - $this->database->schema()->createTable($name, $table); - } - } - - /** - * {@inheritdoc} - */ - public function onFieldUpdate(FieldInterface $field) { - $original = $field->original; - - if (!$field->hasData()) { - // There is no data. Re-create the tables completely. - - if ($this->database->supportsTransactionalDDL()) { - // If the database supports transactional DDL, we can go ahead and rely - // on it. If not, we will have to rollback manually if something fails. - $transaction = $this->database->startTransaction(); - } - - try { - $original_schema = $this->_fieldSqlSchema($original); - foreach ($original_schema as $name => $table) { - $this->database->schema()->dropTable($name, $table); - } - $schema = $this->_fieldSqlSchema($field); - foreach ($schema as $name => $table) { - $this->database->schema()->createTable($name, $table); - } - } - catch (\Exception $e) { - if ($this->database->supportsTransactionalDDL()) { - $transaction->rollback(); - } - else { - // Recreate tables. - $original_schema = $this->_fieldSqlSchema($original); - foreach ($original_schema as $name => $table) { - if (!$this->database->schema()->tableExists($name)) { - $this->database->schema()->createTable($name, $table); - } - } - } - throw $e; - } - } - else { - if ($field['columns'] != $original['columns']) { - throw new FieldUpdateForbiddenException("The SQL storage cannot change the schema for an existing field with data."); - } - // There is data, so there are no column changes. Drop all the prior - // indexes and create all the new ones, except for all the priors that - // exist unchanged. - $table = static::_fieldTableName($original); - $revision_table = static::_fieldRevisionTableName($original); - - $schema = $field->getSchema(); - $original_schema = $original->getSchema(); - - foreach ($original_schema['indexes'] as $name => $columns) { - if (!isset($schema['indexes'][$name]) || $columns != $schema['indexes'][$name]) { - $real_name = static::_fieldIndexName($field, $name); - $this->database->schema()->dropIndex($table, $real_name); - $this->database->schema()->dropIndex($revision_table, $real_name); - } - } - $table = static::_fieldTableName($field); - $revision_table = static::_fieldRevisionTableName($field); - foreach ($schema['indexes'] as $name => $columns) { - if (!isset($original_schema['indexes'][$name]) || $columns != $original_schema['indexes'][$name]) { - $real_name = static::_fieldIndexName($field, $name); - $real_columns = array(); - foreach ($columns as $column_name) { - // Indexes can be specified as either a column name or an array with - // column name and length. Allow for either case. - if (is_array($column_name)) { - $real_columns[] = array( - static::_fieldColumnName($field, $column_name[0]), - $column_name[1], - ); - } - else { - $real_columns[] = static::_fieldColumnName($field, $column_name); - } - } - $this->database->schema()->addIndex($table, $real_name, $real_columns); - $this->database->schema()->addIndex($revision_table, $real_name, $real_columns); - } - } - } - } - - /** - * {@inheritdoc} - */ - public function onFieldDelete(FieldInterface $field) { - // Mark all data associated with the field for deletion. - $field['deleted'] = FALSE; - $table = static::_fieldTableName($field); - $revision_table = static::_fieldRevisionTableName($field); - $this->database->update($table) - ->fields(array('deleted' => 1)) - ->execute(); - - // Move the table to a unique name while the table contents are being - // deleted. - $field['deleted'] = TRUE; - $new_table = static::_fieldTableName($field); - $revision_new_table = static::_fieldRevisionTableName($field); - $this->database->schema()->renameTable($table, $new_table); - $this->database->schema()->renameTable($revision_table, $revision_new_table); - } - - /** - * {@inheritdoc} - */ - public function onInstanceDelete(FieldInstanceInterface $instance) { - $field = $instance->getField(); - $table_name = static::_fieldTableName($field); - $revision_name = static::_fieldRevisionTableName($field); - $this->database->update($table_name) - ->fields(array('deleted' => 1)) - ->condition('bundle', $instance['bundle']) - ->execute(); - $this->database->update($revision_name) - ->fields(array('deleted' => 1)) - ->condition('bundle', $instance['bundle']) - ->execute(); - } - - /** - * {@inheritdoc} - */ - public function onBundleRename($bundle, $bundle_new) { - // We need to account for deleted or inactive fields and instances. - $instances = field_read_instances(array('entity_type' => $this->entityType, 'bundle' => $bundle_new), array('include_deleted' => TRUE, 'include_inactive' => TRUE)); - foreach ($instances as $instance) { - $field = $instance->getField(); - if ($field['storage']['type'] == 'field_sql_storage') { - $table_name = static::_fieldTableName($field); - $revision_name = static::_fieldRevisionTableName($field); - $this->database->update($table_name) - ->fields(array('bundle' => $bundle_new)) - ->condition('bundle', $bundle) - ->execute(); - $this->database->update($revision_name) - ->fields(array('bundle' => $bundle_new)) - ->condition('bundle', $bundle) - ->execute(); - } - } - } - - /** - * {@inheritdoc} - */ - protected function readFieldItemsToPurge(EntityInterface $entity, FieldInstanceInterface $instance) { - $field = $instance->getField(); - $table_name = static::_fieldTableName($field); - $query = $this->database->select($table_name, 't', array('fetch' => \PDO::FETCH_ASSOC)) - ->condition('entity_id', $entity->id()) - ->orderBy('delta'); - foreach ($field->getColumns() as $column_name => $data) { - $query->addField('t', static::_fieldColumnName($field, $column_name), $column_name); - } - return $query->execute()->fetchAll(); - } - - /** - * {@inheritdoc} - */ - public function purgeFieldItems(EntityInterface $entity, FieldInstanceInterface $instance) { - $field = $instance->getField(); - $table_name = static::_fieldTableName($field); - $revision_name = static::_fieldRevisionTableName($field); - $this->database->delete($table_name) - ->condition('entity_id', $entity->id()) - ->execute(); - $this->database->delete($revision_name) - ->condition('entity_id', $entity->id()) - ->execute(); - } - - /** - * {@inheritdoc} - */ - public function onFieldPurge(FieldInterface $field) { - $table_name = static::_fieldTableName($field); - $revision_name = static::_fieldRevisionTableName($field); - $this->database->schema()->dropTable($table_name); - $this->database->schema()->dropTable($revision_name); - } - - /** - * Gets the SQL table schema. - * - * @private Calling this function circumvents the entity system and is - * strongly discouraged. This function is not considered part of the public - * API and modules relying on it might break even in minor releases. - * - * @param \Drupal\field\FieldInterface $field - * The field object - * @param array $schema - * The field schema array. Mandatory for upgrades, omit otherwise. - * - * @return array - * The same as a hook_schema() implementation for the data and the - * revision tables. - * - * @see hook_schema() - */ - public static function _fieldSqlSchema(FieldInterface $field, array $schema = NULL) { - if ($field['deleted']) { - $description_current = "Data storage for deleted field {$field['id']} ({$field['entity_type']}, {$field['field_name']})."; - $description_revision = "Revision archive storage for deleted field {$field['id']} ({$field['entity_type']}, {$field['field_name']})."; - } - else { - $description_current = "Data storage for {$field['entity_type']} field {$field['field_name']}."; - $description_revision = "Revision archive storage for {$field['entity_type']} field {$field['field_name']}."; - } - - $current = array( - 'description' => $description_current, - 'fields' => array( - 'bundle' => array( - 'type' => 'varchar', - 'length' => 128, - 'not null' => TRUE, - 'default' => '', - 'description' => 'The field instance bundle to which this row belongs, used when deleting a field instance', - ), - 'deleted' => array( - 'type' => 'int', - 'size' => 'tiny', - 'not null' => TRUE, - 'default' => 0, - 'description' => 'A boolean indicating whether this data item has been deleted' - ), - 'entity_id' => array( - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'description' => 'The entity id this data is attached to', - ), - 'revision_id' => array( - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => FALSE, - 'description' => 'The entity revision id this data is attached to, or NULL if the entity type is not versioned', - ), - 'langcode' => array( - 'type' => 'varchar', - 'length' => 32, - 'not null' => TRUE, - 'default' => '', - 'description' => 'The language code for this data item.', - ), - 'delta' => array( - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'description' => 'The sequence number for this data item, used for multi-value fields', - ), - ), - 'primary key' => array('entity_id', 'deleted', 'delta', 'langcode'), - 'indexes' => array( - 'bundle' => array('bundle'), - 'deleted' => array('deleted'), - 'entity_id' => array('entity_id'), - 'revision_id' => array('revision_id'), - 'langcode' => array('langcode'), - ), - ); - - if (!$schema) { - $schema = $field->getSchema(); - } - - // Add field columns. - foreach ($schema['columns'] as $column_name => $attributes) { - $real_name = static::_fieldColumnName($field, $column_name); - $current['fields'][$real_name] = $attributes; - } - - // Add indexes. - foreach ($schema['indexes'] as $index_name => $columns) { - $real_name = static::_fieldIndexName($field, $index_name); - foreach ($columns as $column_name) { - // Indexes can be specified as either a column name or an array with - // column name and length. Allow for either case. - if (is_array($column_name)) { - $current['indexes'][$real_name][] = array( - static::_fieldColumnName($field, $column_name[0]), - $column_name[1], - ); - } - else { - $current['indexes'][$real_name][] = static::_fieldColumnName($field, $column_name); - } - } - } - - // Add foreign keys. - foreach ($schema['foreign keys'] as $specifier => $specification) { - $real_name = static::_fieldIndexName($field, $specifier); - $current['foreign keys'][$real_name]['table'] = $specification['table']; - foreach ($specification['columns'] as $column_name => $referenced) { - $sql_storage_column = static::_fieldColumnName($field, $column_name); - $current['foreign keys'][$real_name]['columns'][$sql_storage_column] = $referenced; - } - } - - // Construct the revision table. - $revision = $current; - $revision['description'] = $description_revision; - $revision['primary key'] = array('entity_id', 'revision_id', 'deleted', 'delta', 'langcode'); - $revision['fields']['revision_id']['not null'] = TRUE; - $revision['fields']['revision_id']['description'] = 'The entity revision id this data is attached to'; - - return array( - static::_fieldTableName($field) => $current, - static::_fieldRevisionTableName($field) => $revision, - ); - } - - /** - * Generates a table name for a field data table. - * - * @private Calling this function circumvents the entity system and is - * strongly discouraged. This function is not considered part of the public - * API and modules relying on it might break even in minor releases. Only - * call this function to write a query that \Drupal::entityQuery() does not - * support. Always call entity_load() before using the data found in the - * table. - * - * @param \Drupal\field\FieldInterface $field - * The field object. - * - * @return string - * A string containing the generated name for the database table. - * - */ - static public function _fieldTableName(FieldInterface $field) { - if ($field['deleted']) { - // When a field is a deleted, the table is renamed to - // {field_deleted_data_FIELD_UUID}. To make sure we don't end up with - // table names longer than 64 characters, we hash the uuid and return the - // first 10 characters so we end up with a short unique ID. - return "field_deleted_data_" . substr(hash('sha256', $field['uuid']), 0, 10); - } - else { - return static::_generateFieldTableName($field, FALSE); - } - } - - /** - * Generates a table name for a field revision archive table. - * - * @private Calling this function circumvents the entity system and is - * strongly discouraged. This function is not considered part of the public - * API and modules relying on it might break even in minor releases. Only - * call this function to write a query that \Drupal::entityQuery() does not - * support. Always call entity_load() before using the data found in the - * table. - * - * @param \Drupal\field\FieldInterface $field - * The field object. - * - * @return string - * A string containing the generated name for the database table. - */ - static public function _fieldRevisionTableName(FieldInterface $field) { - if ($field['deleted']) { - // When a field is a deleted, the table is renamed to - // {field_deleted_revision_FIELD_UUID}. To make sure we don't end up with - // table names longer than 64 characters, we hash the uuid and return the - // first 10 characters so we end up with a short unique ID. - return "field_deleted_revision_" . substr(hash('sha256', $field['uuid']), 0, 10); - } - else { - return static::_generateFieldTableName($field, TRUE); - } - } - - /** - * Generates a safe and unanbiguous field table name. - * - * The method accounts for a maximum table name length of 64 characters, and - * takes care of disambiguation. - * - * @param \Drupal\field\FieldInterface $field - * The field object. - * @param bool $revision - * TRUE for revision table, FALSE otherwise. - * - * @return string - * The final table name. - */ - static protected function _generateFieldTableName($field, $revision) { - $separator = $revision ? '_revision__' : '__'; - $table_name = $field->entity_type . $separator . $field->name; - // Limit the string to 48 characters, keeping a 16 characters margin for db - // prefixes. - if (strlen($table_name) > 48) { - // Use a shorter separator, a truncated entity_type, and a hash of the - // field UUID. - $separator = $revision ? '_r__' : '__'; - // Truncate to the same length for the current and revision tables. - $entity_type = substr($field->entity_type, 0, 34); - $field_hash = substr(hash('sha256', $field->uuid), 0, 10); - $table_name = $entity_type . $separator . $field_hash; - } - return $table_name; - } - - /** - * Generates an index name for a field data table. - * - * @private Calling this function circumvents the entity system and is - * strongly discouraged. This function is not considered part of the public - * API and modules relying on it might break even in minor releases. - * - * @param \Drupal\field\FieldInterface $field - * The field structure - * @param string $index - * The name of the index. - * - * @return string - * A string containing a generated index name for a field data table that is - * unique among all other fields. - */ - static public function _fieldIndexName(FieldInterface $field, $index) { - return $field->getFieldName() . '_' . $index; - } - - /** - * Generates a column name for a field data table. - * - * @private Calling this function circumvents the entity system and is - * strongly discouraged. This function is not considered part of the public - * API and modules relying on it might break even in minor releases. Only - * call this function to write a query that \Drupal::entityQuery() does not - * support. Always call entity_load() before using the data found in the - * table. - * - * @param \Drupal\field\FieldInterface $field - * The field object. - * @param string $column - * The name of the column. - * - * @return string - * A string containing a generated column name for a field data table that is - * unique among all other fields. - */ - static public function _fieldColumnName(FieldInterface $field, $column) { - return in_array($column, Field::getReservedColumns()) ? $column : $field->getFieldName() . '_' . $column; - } - } diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php deleted file mode 100644 index 9fb88df..0000000 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php +++ /dev/null @@ -1,611 +0,0 @@ -bundleKey = !empty($this->entityInfo['entity_keys']['bundle']) ? $this->entityInfo['entity_keys']['bundle'] : FALSE; - $this->entityClass = $this->entityInfo['class']; - - // Check if the entity type has a dedicated table for properties. - if (!empty($this->entityInfo['data_table'])) { - $this->dataTable = $this->entityInfo['data_table']; - } - - // Work-a-round to let load() get stdClass storage records without having to - // override it. We map storage records to entities in - // DatabaseStorageControllerNG:: mapFromStorageRecords(). - // @todo: Remove this once this is moved in the main controller. - unset($this->entityInfo['class']); - } - - /** - * Overrides DatabaseStorageController::create(). - * - * @param array $values - * An array of values to set, keyed by field name. The value has to be - * the plain value of an entity field, i.e. an array of field items. - * If no numerically indexed array is given, the value will be set for the - * first field item. For example, to set the first item of a 'name' - * field one can pass: - * @code - * $values = array('name' => array(0 => array('value' => 'the name'))); - * @endcode - * or - * @code - * $values = array('name' => array('value' => 'the name')); - * @endcode - * If the 'name' field is a defined as 'string_item' which supports - * setting its value by a string, it's also possible to just pass the name - * string: - * @code - * $values = array('name' => 'the name'); - * @endcode - * - * @return \Drupal\Core\Entity\EntityInterface - * A new entity object. - */ - public function create(array $values) { - $entity_class = $this->entityClass; - $entity_class::preCreate($this, $values); - - // We have to determine the bundle first. - $bundle = FALSE; - if ($this->bundleKey) { - if (!isset($values[$this->bundleKey])) { - throw new EntityStorageException(format_string('Missing bundle for entity type @type', array('@type' => $this->entityType))); - } - $bundle = $values[$this->bundleKey]; - } - $entity = new $this->entityClass(array(), $this->entityType, $bundle); - - foreach ($entity as $name => $field) { - if (isset($values[$name])) { - $entity->$name = $values[$name]; - } - elseif (!array_key_exists($name, $values)) { - $entity->get($name)->applyDefaultValue(); - } - unset($values[$name]); - } - - // Set any passed values for non-defined fields also. - foreach ($values as $name => $value) { - $entity->$name = $value; - } - $entity->postCreate($this); - - // Modules might need to add or change the data initially held by the new - // entity object, for instance to fill-in default values. - $this->invokeHook('create', $entity); - - return $entity; - } - - /** - * Builds an entity query. - * - * @param \Drupal\Core\Entity\Query\QueryInterface $entity_query - * EntityQuery instance. - * @param array $values - * An associative array of properties of the entity, where the keys are the - * property names and the values are the values those properties must have. - */ - protected function buildPropertyQuery(QueryInterface $entity_query, array $values) { - if ($this->dataTable) { - // @todo We should not be using a condition to specify whether conditions - // apply to the default language. See http://drupal.org/node/1866330. - // Default to the original entity language if not explicitly specified - // otherwise. - if (!array_key_exists('default_langcode', $values)) { - $values['default_langcode'] = 1; - } - // If the 'default_langcode' flag is explicitly not set, we do not care - // whether the queried values are in the original entity language or not. - elseif ($values['default_langcode'] === NULL) { - unset($values['default_langcode']); - } - } - - parent::buildPropertyQuery($entity_query, $values); - } - - /** - * {@inheritdoc} - */ - protected function buildQuery($ids, $revision_id = FALSE) { - $query = $this->database->select($this->entityInfo['base_table'], 'base'); - $is_revision_query = $this->revisionKey && ($revision_id || !$this->dataTable); - - $query->addTag($this->entityType . '_load_multiple'); - - if ($revision_id) { - $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id)); - } - elseif ($is_revision_query) { - $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}"); - } - - // Add fields from the {entity} table. - $entity_fields = drupal_schema_fields_sql($this->entityInfo['base_table']); - - if ($is_revision_query) { - // Add all fields from the {entity_revision} table. - $entity_revision_fields = drupal_map_assoc(drupal_schema_fields_sql($this->entityInfo['revision_table'])); - // The ID field is provided by entity, so remove it. - unset($entity_revision_fields[$this->idKey]); - - // Remove all fields from the base table that are also fields by the same - // name in the revision table. - $entity_field_keys = array_flip($entity_fields); - foreach ($entity_revision_fields as $name) { - if (isset($entity_field_keys[$name])) { - unset($entity_fields[$entity_field_keys[$name]]); - } - } - $query->fields('revision', $entity_revision_fields); - - // Compare revision ID of the base and revision table, if equal then this - // is the default revision. - $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isDefaultRevision'); - } - - $query->fields('base', $entity_fields); - - if ($ids) { - $query->condition("base.{$this->idKey}", $ids, 'IN'); - } - - return $query; - } - - /** - * Overrides DatabaseStorageController::attachLoad(). - * - * Added mapping from storage records to entities. - */ - protected function attachLoad(&$queried_entities, $load_revision = FALSE) { - // Map the loaded stdclass records into entity objects and according fields. - $queried_entities = $this->mapFromStorageRecords($queried_entities, $load_revision); - parent::attachLoad($queried_entities, $load_revision); - } - - /** - * Maps from storage records to entity objects. - * - * @param array $records - * Associative array of query results, keyed on the entity ID. - * @param boolean $load_revision - * (optional) TRUE if the revision should be loaded, defaults to FALSE. - * - * @return array - * An array of entity objects implementing the EntityInterface. - */ - protected function mapFromStorageRecords(array $records, $load_revision = FALSE) { - $entities = array(); - foreach ($records as $id => $record) { - $entities[$id] = array(); - foreach ($record as $name => $value) { - // Skip the item delta and item value levels but let the field assign - // the value as suiting. This avoids unnecessary array hierarchies and - // saves memory here. - $entities[$id][$name][Language::LANGCODE_DEFAULT] = $value; - } - // If we have no multilingual values we can instantiate entity objecs - // right now, otherwise we need to collect all the field values first. - if (!$this->dataTable) { - $bundle = $this->bundleKey ? $record->{$this->bundleKey} : FALSE; - // Turn the record into an entity class. - $entities[$id] = new $this->entityClass($entities[$id], $this->entityType, $bundle); - } - } - $this->attachPropertyData($entities, $load_revision); - return $entities; - } - - /** - * Attaches property data in all languages for translatable properties. - * - * @param array &$entities - * Associative array of entities, keyed on the entity ID. - * @param int $revision_id - * (optional) The revision to be loaded. Defaults to FALSE. - */ - protected function attachPropertyData(array &$entities, $revision_id = FALSE) { - if ($this->dataTable) { - // If a revision table is available, we need all the properties of the - // latest revision. Otherwise we fall back to the data table. - $table = $this->revisionTable ?: $this->dataTable; - $query = $this->database->select($table, 'data', array('fetch' => \PDO::FETCH_ASSOC)) - ->fields('data') - ->condition($this->idKey, array_keys($entities)) - ->orderBy('data.' . $this->idKey); - - if ($this->revisionTable) { - if ($revision_id) { - $query->condition($this->revisionKey, $revision_id); - } - else { - // Get the revision IDs. - $revision_ids = array(); - foreach ($entities as $values) { - $revision_ids[] = $values[$this->revisionKey]; - } - $query->condition($this->revisionKey, $revision_ids); - } - } - - $data = $query->execute(); - $field_definition = \Drupal::entityManager()->getFieldDefinitions($this->entityType); - $translations = array(); - if ($this->revisionTable) { - $data_fields = array_flip(array_diff(drupal_schema_fields_sql($this->entityInfo['revision_table']), drupal_schema_fields_sql($this->entityInfo['base_table']))); - } - else { - $data_fields = array_flip(drupal_schema_fields_sql($this->entityInfo['data_table'])); - } - - foreach ($data as $values) { - $id = $values[$this->idKey]; - - // Field values in default language are stored with - // Language::LANGCODE_DEFAULT as key. - $langcode = empty($values['default_langcode']) ? $values['langcode'] : Language::LANGCODE_DEFAULT; - $translations[$id][$langcode] = TRUE; - - foreach ($field_definition as $name => $definition) { - // Set only translatable properties, unless we are dealing with a - // revisable entity, in which case we did not load the untranslatable - // data before. - $translatable = !empty($definition['translatable']); - if (isset($data_fields[$name]) && ($this->revisionTable || $translatable)) { - $entities[$id][$name][$langcode] = $values[$name]; - } - } - } - - foreach ($entities as $id => $values) { - $bundle = $this->bundleKey ? $values[$this->bundleKey][Language::LANGCODE_DEFAULT] : FALSE; - // Turn the record into an entity class. - $entities[$id] = new $this->entityClass($values, $this->entityType, $bundle, array_keys($translations[$id])); - } - } - } - - /** - * Overrides DatabaseStorageController::save(). - * - * Added mapping from entities to storage records before saving. - */ - public function save(EntityInterface $entity) { - $transaction = $this->database->startTransaction(); - try { - // Sync the changes made in the fields array to the internal values array. - $entity->updateOriginalValues(); - - // Load the stored entity, if any. - if (!$entity->isNew() && !isset($entity->original)) { - $entity->original = entity_load_unchanged($this->entityType, $entity->id()); - } - - $entity->preSave($this); - $this->invokeFieldMethod('preSave', $entity); - $this->invokeHook('presave', $entity); - - // Create the storage record to be saved. - $record = $this->mapToStorageRecord($entity); - - if (!$entity->isNew()) { - if ($entity->isDefaultRevision()) { - $return = drupal_write_record($this->entityInfo['base_table'], $record, $this->idKey); - } - else { - // @todo, should a different value be returned when saving an entity - // with $isDefaultRevision = FALSE? - $return = FALSE; - } - if ($this->revisionKey) { - $record->{$this->revisionKey} = $this->saveRevision($entity); - } - if ($this->dataTable) { - $this->savePropertyData($entity); - } - $this->resetCache(array($entity->id())); - $entity->postSave($this, TRUE); - $this->invokeFieldMethod('update', $entity); - $this->saveFieldItems($entity, TRUE); - $this->invokeHook('update', $entity); - if ($this->dataTable) { - $this->invokeTranslationHooks($entity); - } - } - else { - $return = drupal_write_record($this->entityInfo['base_table'], $record); - $entity->{$this->idKey}->value = $record->{$this->idKey}; - if ($this->revisionKey) { - $record->{$this->revisionKey} = $this->saveRevision($entity); - } - $entity->{$this->idKey}->value = $record->{$this->idKey}; - if ($this->dataTable) { - $this->savePropertyData($entity); - } - - // Reset general caches, but keep caches specific to certain entities. - $this->resetCache(array()); - - $entity->enforceIsNew(FALSE); - $entity->postSave($this, FALSE); - $this->invokeFieldMethod('insert', $entity); - $this->saveFieldItems($entity, FALSE); - $this->invokeHook('insert', $entity); - } - - // Ignore slave server temporarily. - db_ignore_slave(); - unset($entity->original); - - return $return; - } - catch (\Exception $e) { - $transaction->rollback(); - watchdog_exception($this->entityType, $e); - throw new EntityStorageException($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * Saves an entity revision. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity object. - * - * @return integer - * The revision id. - */ - protected function saveRevision(EntityInterface $entity) { - $return = $entity->id(); - $default_langcode = $entity->getUntranslated()->language()->id; - - if (!$entity->isNewRevision()) { - // Delete to handle removed values. - $this->database->delete($this->revisionTable) - ->condition($this->idKey, $entity->id()) - ->condition($this->revisionKey, $entity->getRevisionId()) - ->execute(); - } - - $languages = $this->dataTable ? $entity->getTranslationLanguages() : array($default_langcode => $entity->language()); - foreach ($languages as $langcode => $language) { - $translation = $entity->getTranslation($langcode); - $record = $this->mapToRevisionStorageRecord($translation); - $record->langcode = $langcode; - $record->default_langcode = $langcode == $default_langcode; - - // When saving a new revision, set any existing revision ID to NULL so as - // to ensure that a new revision will actually be created. - if ($entity->isNewRevision() && isset($record->{$this->revisionKey})) { - $record->{$this->revisionKey} = NULL; - } - - $entity->preSaveRevision($this, $record); - - if ($entity->isNewRevision()) { - drupal_write_record($this->revisionTable, $record); - if ($entity->isDefaultRevision()) { - $this->database->update($this->entityInfo['base_table']) - ->fields(array($this->revisionKey => $record->{$this->revisionKey})) - ->condition($this->idKey, $record->{$this->idKey}) - ->execute(); - } - $entity->setNewRevision(FALSE); - } - else { - // @todo Use multiple insertions to improve performance. - drupal_write_record($this->revisionTable, $record); - } - - // Make sure to update the new revision key for the entity. - $entity->{$this->revisionKey}->value = $record->{$this->revisionKey}; - $return = $record->{$this->revisionKey}; - } - - return $return; - } - - /** - * Stores the entity property language-aware data. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity object. - */ - protected function savePropertyData(EntityInterface $entity) { - // Delete and insert to handle removed values. - $this->database->delete($this->dataTable) - ->condition($this->idKey, $entity->id()) - ->execute(); - - $query = $this->database->insert($this->dataTable); - - foreach ($entity->getTranslationLanguages() as $langcode => $language) { - $record = $this->mapToDataStorageRecord($entity, $langcode); - $values = (array) $record; - $query - ->fields(array_keys($values)) - ->values($values); - } - - $query->execute(); - } - - /** - * Maps from an entity object to the storage record of the base table. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity object. - * - * @return \stdClass - * The record to store. - */ - protected function mapToStorageRecord(EntityInterface $entity) { - $record = new \stdClass(); - foreach (drupal_schema_fields_sql($this->entityInfo['base_table']) as $name) { - $record->$name = $entity->$name->value; - } - return $record; - } - - /** - * Maps from an entity object to the storage record of the revision table. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity object. - * - * @return \stdClass - * The record to store. - */ - protected function mapToRevisionStorageRecord(EntityInterface $entity) { - $record = new \stdClass(); - $definitions = $entity->getPropertyDefinitions(); - foreach (drupal_schema_fields_sql($this->entityInfo['revision_table']) as $name) { - if (isset($definitions[$name]) && isset($entity->$name->value)) { - $record->$name = $entity->$name->value; - } - } - return $record; - } - - /** - * Maps from an entity object to the storage record of the data table. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity object. - * @param $langcode - * The language code of the translation to get. - * - * @return \stdClass - * The record to store. - */ - protected function mapToDataStorageRecord(EntityInterface $entity, $langcode) { - $default_langcode = $entity->getUntranslated()->language()->id; - // Don't use strict mode, this way there's no need to do checks here, as - // non-translatable properties are replicated for each language. - $translation = $entity->getTranslation($langcode); - $definitions = $translation->getPropertyDefinitions(); - $schema = drupal_get_schema($this->entityInfo['data_table']); - - $record = new \stdClass(); - foreach (drupal_schema_fields_sql($this->entityInfo['data_table']) as $name) { - $info = $schema['fields'][$name]; - $value = isset($definitions[$name]) && isset($translation->$name->value) ? $translation->$name->value : NULL; - $record->$name = drupal_schema_get_field_value($info, $value); - } - $record->langcode = $langcode; - $record->default_langcode = intval($default_langcode == $langcode); - - return $record; - } - - /** - * Overwrites \Drupal\Core\Entity\DatabaseStorageController::delete(). - */ - public function delete(array $entities) { - if (!$entities) { - // If no IDs or invalid IDs were passed, do nothing. - return; - } - - $transaction = $this->database->startTransaction(); - try { - $entity_class = $this->entityClass; - $entity_class::preDelete($this, $entities); - - foreach ($entities as $entity) { - $this->invokeHook('predelete', $entity); - } - $ids = array_keys($entities); - - $this->database->delete($this->entityInfo['base_table']) - ->condition($this->idKey, $ids) - ->execute(); - - if ($this->revisionKey) { - $this->database->delete($this->revisionTable) - ->condition($this->idKey, $ids) - ->execute(); - } - - if ($this->dataTable) { - $this->database->delete($this->dataTable) - ->condition($this->idKey, $ids) - ->execute(); - } - - // Reset the cache as soon as the changes have been applied. - $this->resetCache($ids); - - $entity_class::postDelete($this, $entities); - foreach ($entities as $entity) { - $this->invokeFieldMethod('delete', $entity); - $this->deleteFieldItems($entity); - $this->invokeHook('delete', $entity); - } - // Ignore slave server temporarily. - db_ignore_slave(); - } - catch (\Exception $e) { - $transaction->rollback(); - watchdog_exception($this->entityType, $e); - throw new EntityStorageException($e->getMessage(), $e->getCode(), $e); - } - } -} diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php similarity index 76% copy from core/lib/Drupal/Core/Entity/DatabaseStorageController.php copy to core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php index 2bed3f6..affb8d6 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php +++ b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php @@ -27,7 +27,7 @@ * This class can be used as-is by most simple entity types. Entity types * requiring special handling can extend the class. */ -class DatabaseStorageController extends FieldableEntityStorageControllerBase { +class FieldableDatabaseStorageController extends FieldableEntityStorageControllerBase { /** * Name of entity's revision database table field, if it supports revisions. @@ -69,6 +69,20 @@ class DatabaseStorageController extends FieldableEntityStorageControllerBase { protected $fieldInfo; /** + * The entity bundle key. + * + * @var string|bool + */ + protected $bundleKey; + + /** + * The table that stores properties, if the entity has multilingual support. + * + * @var string + */ + protected $dataTable; + + /** * {@inheritdoc} */ public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) { @@ -97,6 +111,7 @@ public function __construct($entity_type, array $entity_info, Connection $databa $this->database = $database; $this->fieldInfo = $field_info; + $this->bundleKey = !empty($this->entityInfo['entity_keys']['bundle']) ? $this->entityInfo['entity_keys']['bundle'] : FALSE; // Check if the entity type supports IDs. if (isset($this->entityInfo['entity_keys']['id'])) { @@ -122,6 +137,11 @@ public function __construct($entity_type, array $entity_info, Connection $databa else { $this->revisionKey = FALSE; } + + // Check if the entity type has a dedicated table for properties. + if (!empty($this->entityInfo['data_table'])) { + $this->dataTable = $this->entityInfo['data_table']; + } } /** @@ -152,13 +172,6 @@ public function loadMultiple(array $ids = NULL) { if ($ids === NULL || $ids) { // Build and execute the query. $query_result = $this->buildQuery($ids)->execute(); - - if (!empty($this->entityInfo['class'])) { - // We provide the necessary arguments for PDO to create objects of the - // specified entity class. - // @see Drupal\Core\Entity\EntityInterface::__construct() - $query_result->setFetchMode(\PDO::FETCH_CLASS, $this->entityInfo['class'], array(array(), $this->entityType)); - } $queried_entities = $query_result->fetchAllAssoc($this->idKey); } @@ -263,6 +276,21 @@ public function loadByProperties(array $values = array()) { * property names and the values are the values those properties must have. */ protected function buildPropertyQuery(QueryInterface $entity_query, array $values) { + if ($this->dataTable) { + // @todo We should not be using a condition to specify whether conditions + // apply to the default language. See http://drupal.org/node/1866330. + // Default to the original entity language if not explicitly specified + // otherwise. + if (!array_key_exists('default_langcode', $values)) { + $values['default_langcode'] = 1; + } + // If the 'default_langcode' flag is explicitly not set, we do not care + // whether the queried values are in the original entity language or not. + elseif ($values['default_langcode'] === NULL) { + unset($values['default_langcode']); + } + } + foreach ($values as $name => $value) { $entity_query->condition($name, $value); } @@ -290,23 +318,24 @@ protected function buildPropertyQuery(QueryInterface $entity_query, array $value */ protected function buildQuery($ids, $revision_id = FALSE) { $query = $this->database->select($this->entityInfo['base_table'], 'base'); + $is_revision_query = $this->revisionKey && ($revision_id || !$this->dataTable); $query->addTag($this->entityType . '_load_multiple'); if ($revision_id) { $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", array(':revisionId' => $revision_id)); } - elseif ($this->revisionKey) { + elseif ($is_revision_query) { $query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}"); } // Add fields from the {entity} table. $entity_fields = drupal_schema_fields_sql($this->entityInfo['base_table']); - if ($this->revisionKey) { + if ($is_revision_query) { // Add all fields from the {entity_revision} table. $entity_revision_fields = drupal_map_assoc(drupal_schema_fields_sql($this->entityInfo['revision_table'])); - // The id field is provided by entity, so remove it. + // The ID field is provided by entity, so remove it. unset($entity_revision_fields[$this->idKey]); // Remove all fields from the base table that are also fields by the same @@ -319,7 +348,7 @@ protected function buildQuery($ids, $revision_id = FALSE) { } $query->fields('revision', $entity_revision_fields); - // Compare revision id of the base and revision table, if equal then this + // Compare revision ID of the base and revision table, if equal then this // is the default revision. $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, 'isDefaultRevision'); } @@ -350,6 +379,9 @@ protected function buildQuery($ids, $revision_id = FALSE) { * (optional) TRUE if the revision should be loaded, defaults to FALSE. */ protected function attachLoad(&$queried_entities, $load_revision = FALSE) { + // Map the loaded records into entity objects and according fields. + $queried_entities = $this->mapFromStorageRecords($queried_entities, $load_revision); + // Attach field values. if ($this->entityInfo['fieldable']) { $this->loadFieldItems($queried_entities, $load_revision ? static::FIELD_LOAD_REVISION : static::FIELD_LOAD_CURRENT); @@ -370,18 +402,35 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) { } /** - * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::create(). + * {@inheritdoc} */ public function create(array $values) { $entity_class = $this->entityInfo['class']; $entity_class::preCreate($this, $values); - $entity = new $entity_class($values, $this->entityType); + // We have to determine the bundle first. + $bundle = FALSE; + if ($this->bundleKey) { + if (!isset($values[$this->bundleKey])) { + throw new EntityStorageException(format_string('Missing bundle for entity type @type', array('@type' => $this->entityType))); + } + $bundle = $values[$this->bundleKey]; + } + $entity = new $entity_class(array(), $this->entityType, $bundle); + + foreach ($entity as $name => $field) { + if (isset($values[$name])) { + $entity->$name = $values[$name]; + } + elseif (!array_key_exists($name, $values)) { + $entity->get($name)->applyDefaultValue(); + } + unset($values[$name]); + } - // Assign a new UUID if there is none yet. - if ($this->uuidKey && !isset($entity->{$this->uuidKey})) { - $uuid = new Uuid(); - $entity->{$this->uuidKey} = $uuid->generate(); + // Set any passed values for non-defined fields also. + foreach ($values as $name => $value) { + $entity->$name = $value; } $entity->postCreate($this); @@ -445,6 +494,9 @@ public function delete(array $entities) { public function save(EntityInterface $entity) { $transaction = $this->database->startTransaction(); try { + // Sync the changes made in the fields array to the internal values array. + $entity->updateOriginalValues(); + // Load the stored entity, if any. if (!$entity->isNew() && !isset($entity->original)) { $entity->original = entity_load_unchanged($this->entityType, $entity->id()); @@ -454,9 +506,12 @@ public function save(EntityInterface $entity) { $this->invokeFieldMethod('preSave', $entity); $this->invokeHook('presave', $entity); + // Create the storage record to be saved. + $record = $this->mapToStorageRecord($entity); + if (!$entity->isNew()) { if ($entity->isDefaultRevision()) { - $return = drupal_write_record($this->entityInfo['base_table'], $entity, $this->idKey); + $return = drupal_write_record($this->entityInfo['base_table'], $record, $this->idKey); } else { // @todo, should a different value be returned when saving an entity @@ -464,19 +519,31 @@ public function save(EntityInterface $entity) { $return = FALSE; } if ($this->revisionKey) { - $this->saveRevision($entity); + $record->{$this->revisionKey} = $this->saveRevision($entity); + } + if ($this->dataTable) { + $this->savePropertyData($entity); } $this->resetCache(array($entity->id())); $entity->postSave($this, TRUE); $this->invokeFieldMethod('update', $entity); $this->saveFieldItems($entity, TRUE); $this->invokeHook('update', $entity); + if ($this->dataTable) { + $this->invokeTranslationHooks($entity); + } } else { - $return = drupal_write_record($this->entityInfo['base_table'], $entity); + $return = drupal_write_record($this->entityInfo['base_table'], $record); + $entity->{$this->idKey}->value = $record->{$this->idKey}; if ($this->revisionKey) { - $this->saveRevision($entity); + $record->{$this->revisionKey} = $this->saveRevision($entity); } + $entity->{$this->idKey}->value = $record->{$this->idKey}; + if ($this->dataTable) { + $this->savePropertyData($entity); + } + // Reset general caches, but keep caches specific to certain entities. $this->resetCache(array()); @@ -500,44 +567,64 @@ public function save(EntityInterface $entity) { } } + /** * Saves an entity revision. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. + * + * @return integer + * The revision id. */ protected function saveRevision(EntityInterface $entity) { - // Convert the entity into an array as it might not have the same properties - // as the entity, it is just a raw structure. - $record = (array) $entity; - - // When saving a new revision, set any existing revision ID to NULL so as to - // ensure that a new revision will actually be created. - if ($entity->isNewRevision() && $record[$this->revisionKey]) { - $record[$this->revisionKey] = NULL; + $return = $entity->id(); + $default_langcode = $entity->getUntranslated()->language()->id; + + if (!$entity->isNewRevision()) { + // Delete to handle removed values. + $this->database->delete($this->revisionTable) + ->condition($this->idKey, $entity->id()) + ->condition($this->revisionKey, $entity->getRevisionId()) + ->execute(); } - // Cast to object as preSaveRevision() expects one to be compatible with the - // upcoming NG storage controller. - $record = (object) $record; - $entity->preSaveRevision($this, $record); - $record = (array) $record; - - if ($entity->isNewRevision()) { - drupal_write_record($this->revisionTable, $record); - if ($entity->isDefaultRevision()) { - $this->database->update($this->entityInfo['base_table']) - ->fields(array($this->revisionKey => $record[$this->revisionKey])) - ->condition($this->idKey, $entity->id()) - ->execute(); + $languages = $this->dataTable ? $entity->getTranslationLanguages() : array($default_langcode => $entity->language()); + foreach ($languages as $langcode => $language) { + $translation = $entity->getTranslation($langcode); + $record = $this->mapToRevisionStorageRecord($translation); + $record->langcode = $langcode; + $record->default_langcode = $langcode == $default_langcode; + + // When saving a new revision, set any existing revision ID to NULL so as + // to ensure that a new revision will actually be created. + if ($entity->isNewRevision() && isset($record->{$this->revisionKey})) { + $record->{$this->revisionKey} = NULL; } - $entity->setNewRevision(FALSE); - } - else { - drupal_write_record($this->revisionTable, $record, $this->revisionKey); + + $entity->preSaveRevision($this, $record); + + if ($entity->isNewRevision()) { + drupal_write_record($this->revisionTable, $record); + if ($entity->isDefaultRevision()) { + $this->database->update($this->entityInfo['base_table']) + ->fields(array($this->revisionKey => $record->{$this->revisionKey})) + ->condition($this->idKey, $record->{$this->idKey}) + ->execute(); + } + $entity->setNewRevision(FALSE); + } + else { + // @todo Use multiple insertions to improve performance. + drupal_write_record($this->revisionTable, $record); + } + + // Make sure to update the new revision key for the entity. + $entity->{$this->revisionKey}->value = $record->{$this->revisionKey}; + $return = $record->{$this->revisionKey}; } - // Make sure to update the new revision key for the entity. - $entity->{$this->revisionKey} = $record[$this->revisionKey]; + + return $return; } /** @@ -1191,4 +1278,201 @@ static public function _fieldColumnName(FieldInterface $field, $column) { return in_array($column, Field::getReservedColumns()) ? $column : $field->getFieldName() . '_' . $column; } + /** + * Maps from storage records to entity objects. + * + * @param array $records + * Associative array of query results, keyed on the entity ID. + * @param boolean $load_revision + * (optional) TRUE if the revision should be loaded, defaults to FALSE. + * + * @return array + * An array of entity objects implementing the EntityInterface. + */ + protected function mapFromStorageRecords(array $records, $load_revision = FALSE) { + $entities = array(); + foreach ($records as $id => $record) { + $entities[$id] = array(); + foreach ($record as $name => $value) { + // Skip the item delta and item value levels but let the field assign + // the value as suiting. This avoids unnecessary array hierarchies and + // saves memory here. + $entities[$id][$name][Language::LANGCODE_DEFAULT] = $value; + } + // If we have no multilingual values we can instantiate entity objecs + // right now, otherwise we need to collect all the field values first. + if (!$this->dataTable) { + $bundle = $this->bundleKey ? $record->{$this->bundleKey} : FALSE; + // Turn the record into an entity class. + $entity_class = $this->entityInfo['class']; + $entities[$id] = new $entity_class($entities[$id], $this->entityType, $bundle); + } + } + $this->attachPropertyData($entities, $load_revision); + return $entities; + } + + /** + * Attaches property data in all languages for translatable properties. + * + * @param array &$entities + * Associative array of entities, keyed on the entity ID. + * @param int $revision_id + * (optional) The revision to be loaded. Defaults to FALSE. + */ + protected function attachPropertyData(array &$entities, $revision_id = FALSE) { + if ($this->dataTable) { + // If a revision table is available, we need all the properties of the + // latest revision. Otherwise we fall back to the data table. + $table = $this->revisionTable ?: $this->dataTable; + $query = $this->database->select($table, 'data', array('fetch' => \PDO::FETCH_ASSOC)) + ->fields('data') + ->condition($this->idKey, array_keys($entities)) + ->orderBy('data.' . $this->idKey); + + if ($this->revisionTable) { + if ($revision_id) { + $query->condition($this->revisionKey, $revision_id); + } + else { + // Get the revision IDs. + $revision_ids = array(); + foreach ($entities as $values) { + $revision_ids[] = $values[$this->revisionKey]; + } + $query->condition($this->revisionKey, $revision_ids); + } + } + + $data = $query->execute(); + $field_definition = \Drupal::entityManager()->getFieldDefinitions($this->entityType); + $translations = array(); + if ($this->revisionTable) { + $data_fields = array_flip(array_diff(drupal_schema_fields_sql($this->entityInfo['revision_table']), drupal_schema_fields_sql($this->entityInfo['base_table']))); + } + else { + $data_fields = array_flip(drupal_schema_fields_sql($this->entityInfo['data_table'])); + } + + foreach ($data as $values) { + $id = $values[$this->idKey]; + + // Field values in default language are stored with + // Language::LANGCODE_DEFAULT as key. + $langcode = empty($values['default_langcode']) ? $values['langcode'] : Language::LANGCODE_DEFAULT; + $translations[$id][$langcode] = TRUE; + + foreach ($field_definition as $name => $definition) { + // Set only translatable properties, unless we are dealing with a + // revisable entity, in which case we did not load the untranslatable + // data before. + $translatable = !empty($definition['translatable']); + if (isset($data_fields[$name]) && ($this->revisionTable || $translatable)) { + $entities[$id][$name][$langcode] = $values[$name]; + } + } + } + + foreach ($entities as $id => $values) { + $bundle = $this->bundleKey ? $values[$this->bundleKey][Language::LANGCODE_DEFAULT] : FALSE; + // Turn the record into an entity class. + $entity_class = $this->entityInfo['class']; + $entities[$id] = new $entity_class($values, $this->entityType, $bundle, array_keys($translations[$id])); + } + } + } + + /** + * Stores the entity property language-aware data. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + */ + protected function savePropertyData(EntityInterface $entity) { + // Delete and insert to handle removed values. + $this->database->delete($this->dataTable) + ->condition($this->idKey, $entity->id()) + ->execute(); + + $query = $this->database->insert($this->dataTable); + + foreach ($entity->getTranslationLanguages() as $langcode => $language) { + $record = $this->mapToDataStorageRecord($entity, $langcode); + $values = (array) $record; + $query + ->fields(array_keys($values)) + ->values($values); + } + + $query->execute(); + } + + /** + * Maps from an entity object to the storage record of the base table. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * + * @return \stdClass + * The record to store. + */ + protected function mapToStorageRecord(EntityInterface $entity) { + $record = new \stdClass(); + foreach (drupal_schema_fields_sql($this->entityInfo['base_table']) as $name) { + $record->$name = $entity->$name->value; + } + return $record; + } + + /** + * Maps from an entity object to the storage record of the revision table. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * + * @return \stdClass + * The record to store. + */ + protected function mapToRevisionStorageRecord(EntityInterface $entity) { + $record = new \stdClass(); + $definitions = $entity->getPropertyDefinitions(); + foreach (drupal_schema_fields_sql($this->entityInfo['revision_table']) as $name) { + if (isset($definitions[$name]) && isset($entity->$name->value)) { + $record->$name = $entity->$name->value; + } + } + return $record; + } + + /** + * Maps from an entity object to the storage record of the data table. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity object. + * @param $langcode + * The language code of the translation to get. + * + * @return \stdClass + * The record to store. + */ + protected function mapToDataStorageRecord(EntityInterface $entity, $langcode) { + $default_langcode = $entity->getUntranslated()->language()->id; + // Don't use strict mode, this way there's no need to do checks here, as + // non-translatable properties are replicated for each language. + $translation = $entity->getTranslation($langcode); + $definitions = $translation->getPropertyDefinitions(); + $schema = drupal_get_schema($this->entityInfo['data_table']); + + $record = new \stdClass(); + foreach (drupal_schema_fields_sql($this->entityInfo['data_table']) as $name) { + $info = $schema['fields'][$name]; + $value = isset($definitions[$name]) && isset($translation->$name->value) ? $translation->$name->value : NULL; + $record->$name = drupal_schema_get_field_value($info, $value); + } + $record->langcode = $langcode; + $record->default_langcode = intval($default_langcode == $langcode); + + return $record; + } + } diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php index 9607dd1..1593cce 100644 --- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php +++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php @@ -9,7 +9,7 @@ use Drupal\Core\Database\Query\SelectInterface; use Drupal\Core\Entity\EntityStorageControllerInterface; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Core\Entity\Plugin\DataType\EntityReference; use Drupal\Core\Entity\Query\QueryException; use Drupal\field\Entity\Field; @@ -162,7 +162,7 @@ public function addField($field, $type, $langcode) { $column = 'value'; } $table = $this->ensureFieldTable($index_prefix, $field, $type, $langcode, $base_table, $entity_id_field, $field_id_field); - $sql_column = DatabaseStorageController::_fieldColumnName($field, $column); + $sql_column = FieldableDatabaseStorageController::_fieldColumnName($field, $column); } // This is an entity property (non-configurable field). else { @@ -250,7 +250,7 @@ protected function ensureEntityTable($index_prefix, $property, $type, $langcode, protected function ensureFieldTable($index_prefix, &$field, $type, $langcode, $base_table, $entity_id_field, $field_id_field) { $field_name = $field['field_name']; if (!isset($this->fieldTables[$index_prefix . $field_name])) { - $table = $this->sqlQuery->getMetaData('age') == EntityStorageControllerInterface::FIELD_LOAD_CURRENT ? DatabaseStorageController::_fieldTableName($field) : DatabaseStorageController::_fieldRevisionTableName($field); + $table = $this->sqlQuery->getMetaData('age') == EntityStorageControllerInterface::FIELD_LOAD_CURRENT ? FieldableDatabaseStorageController::_fieldTableName($field) : FieldableDatabaseStorageController::_fieldRevisionTableName($field); if ($field['cardinality'] != 1) { $this->sqlQuery->addMetaData('simple_query', FALSE); } diff --git a/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php b/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php index 6db9b3f..17ea1e2 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php @@ -7,7 +7,7 @@ namespace Drupal\aggregator; -use Drupal\Core\Entity\DatabaseStorageControllerNG; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\aggregator\Entity\Feed; use Drupal\Core\Entity\EntityInterface; @@ -17,7 +17,7 @@ * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding * required special handling for feed entities. */ -class FeedStorageController extends DatabaseStorageControllerNG implements FeedStorageControllerInterface { +class FeedStorageController extends FieldableDatabaseStorageController implements FeedStorageControllerInterface { /** * Overrides Drupal\Core\Entity\DataBaseStorageController::attachLoad(). diff --git a/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php b/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php index e17c82b..7e05027 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/ItemStorageController.php @@ -10,7 +10,7 @@ use Drupal\aggregator\Entity\Item; use Drupal\Core\Database\Query\PagerSelectExtender; use Drupal\Core\Database\Query\SelectInterface; -use Drupal\Core\Entity\DatabaseStorageControllerNG; +use Drupal\Core\Entity\FieldableDatabaseStorageController; /** * Controller class for aggregators items. @@ -18,7 +18,7 @@ * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding * required special handling for feed item entities. */ -class ItemStorageController extends DatabaseStorageControllerNG implements ItemStorageControllerInterface { +class ItemStorageController extends FieldableDatabaseStorageController implements ItemStorageControllerInterface { /** * Overrides Drupal\Core\Entity\DataBaseStorageController::attachLoad(). diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php index 9c5eb21..2078f58 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php @@ -7,16 +7,16 @@ namespace Drupal\custom_block; -use Drupal\Core\Entity\DatabaseStorageControllerNG; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Core\Entity\EntityStorageControllerInterface; /** * Controller class for custom blocks. * - * This extends the Drupal\Core\Entity\DatabaseStorageControllerNG class, + * This extends the Drupal\Core\Entity\DatabaseStorageController class, * adding required special handling for custom block entities. */ -class CustomBlockStorageController extends DatabaseStorageControllerNG { +class CustomBlockStorageController extends FieldableDatabaseStorageController { /** * Overrides \Drupal\Core\Entity\DatabaseStorageController::attachLoad(). diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php index 6068ce9..cbf316b 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php +++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php @@ -8,7 +8,7 @@ namespace Drupal\comment; use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Entity\DatabaseStorageControllerNG; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Component\Uuid\Uuid; /** @@ -17,7 +17,7 @@ * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding * required special handling for comment entities. */ -class CommentStorageController extends DatabaseStorageControllerNG implements CommentStorageControllerInterface { +class CommentStorageController extends FieldableDatabaseStorageController implements CommentStorageControllerInterface { /** * The thread for which a lock was acquired. diff --git a/core/modules/contact/lib/Drupal/contact/Entity/Message.php b/core/modules/contact/lib/Drupal/contact/Entity/Message.php index 0c3c622..be1d34a 100644 --- a/core/modules/contact/lib/Drupal/contact/Entity/Message.php +++ b/core/modules/contact/lib/Drupal/contact/Entity/Message.php @@ -20,7 +20,7 @@ * label = @Translation("Contact message"), * module = "contact", * controllers = { - * "storage" = "Drupal\Core\Entity\DatabaseStorageControllerNG", + * "storage" = "Drupal\Core\Entity\DatabaseStorageController", * "render" = "Drupal\contact\MessageRenderController", * "form" = { * "default" = "Drupal\contact\MessageFormController" diff --git a/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php b/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php index 650a216..709449c 100644 --- a/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php +++ b/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactFieldsTest.php @@ -7,7 +7,7 @@ namespace Drupal\contact\Tests\Views; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\views\Tests\ViewTestBase; /** @@ -62,7 +62,7 @@ protected function setUp() { public function testViewsData() { // Test that the field is not exposed to views, since contact_message // entities have no storage. - $table_name = DatabaseStorageController::_fieldTableName($this->field); + $table_name = FieldableDatabaseStorageController::_fieldTableName($this->field); $data = $this->container->get('views.views_data')->get($table_name); $this->assertFalse($data, 'The field is not exposed to Views.'); } diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php index b43d921..8bd4876 100644 --- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php +++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationTestBase.php @@ -7,7 +7,7 @@ namespace Drupal\content_translation\Tests; -use Drupal\Core\Entity\DatabaseStorageControllerNG; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Core\Language\Language; use Drupal\simpletest\WebTestBase; @@ -204,7 +204,7 @@ protected function createEntity($values, $langcode, $bundle_name = NULL) { $entity_values[$info['entity_keys']['bundle']] = $bundle_name ?: $this->bundle; } $controller = $this->container->get('entity.manager')->getStorageController($this->entityType); - if (!($controller instanceof DatabaseStorageControllerNG)) { + if (!($controller instanceof FieldableDatabaseStorageController)) { foreach ($values as $property => $value) { if (is_array($value)) { $entity_values[$property] = array($langcode => $value); diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/field_type/ConfigurableEntityReferenceItem.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/field_type/ConfigurableEntityReferenceItem.php index ee5e79a..bcfa301 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/field_type/ConfigurableEntityReferenceItem.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Plugin/field/field_type/ConfigurableEntityReferenceItem.php @@ -68,7 +68,7 @@ public static function schema(FieldInterface $field) { // Create a foreign key to the target entity type base type. $entity_manager = \Drupal::service('entity.manager'); - if (is_subclass_of($entity_manager->getControllerClass($field['settings']['target_type'], 'storage'), 'Drupal\Core\Entity\DatabaseStorageController')) { + if (is_subclass_of($entity_manager->getControllerClass($field['settings']['target_type'], 'storage'), 'Drupal\Core\Entity\FieldableDatabaseStorageController')) { $entity_info = $entity_manager->getDefinition($field['settings']['target_type']); $base_table = $entity_info['base_table']; diff --git a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php index 2a50949..82fae68 100644 --- a/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php +++ b/core/modules/entity_reference/lib/Drupal/entity_reference/Tests/EntityReferenceItemTest.php @@ -7,7 +7,7 @@ namespace Drupal\entity_reference\Tests; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Core\Entity\Field\FieldInterface; use Drupal\Core\Entity\Field\FieldItemInterface; use Drupal\Core\Language\Language; @@ -115,12 +115,12 @@ public function testEntityReferenceFieldSchema() { $foreign_key_column_name = 'target_id'; // Grab the SQL schema and verify that the 'foreign keys' are present. - $schemas = DatabaseStorageController::_fieldSqlSchema($field); - $schema = $schemas[DatabaseStorageController::_fieldTableName($field)]; + $schemas = FieldableDatabaseStorageController::_fieldSqlSchema($field); + $schema = $schemas[FieldableDatabaseStorageController::_fieldTableName($field)]; $this->assertEqual(count($schema['foreign keys']), 1, 'There is 1 foreign key in the schema.'); $foreign_key = reset($schema['foreign keys']); - $foreign_key_column = DatabaseStorageController::_fieldColumnName($field, $foreign_key_column_name); + $foreign_key_column = FieldableDatabaseStorageController::_fieldColumnName($field, $foreign_key_column_name); $this->assertEqual($foreign_key['table'], 'taxonomy_term_data', 'Foreign key table name preserved in the schema.'); $this->assertEqual($foreign_key['columns'][$foreign_key_column], 'tid', 'Foreign key column name preserved in the schema.'); @@ -130,8 +130,8 @@ public function testEntityReferenceFieldSchema() { entity_reference_create_instance('entity_test', 'entity_test', $field_name, 'Test vocabulary reference', 'taxonomy_vocabulary'); $field = field_info_field('entity_test', $field_name); - $schemas = DatabaseStorageController::_fieldSqlSchema($field); - $schema = $schemas[DatabaseStorageController::_fieldTableName($field)]; + $schemas = FieldableDatabaseStorageController::_fieldSqlSchema($field); + $schema = $schemas[FieldableDatabaseStorageController::_fieldTableName($field)]; $this->assertFalse(isset($schema['foreign keys']), 'There is no foreign key in the schema.'); } } diff --git a/core/modules/field/field.install b/core/modules/field/field.install index 5f70ee1..acbd5c6 100644 --- a/core/modules/field/field.install +++ b/core/modules/field/field.install @@ -6,7 +6,7 @@ */ use Drupal\Component\Uuid\Uuid; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\field\Entity\Field; /** @@ -49,7 +49,7 @@ function _update_8003_field_create_field(array &$field_config) { // Create storage for the field. This requires a field entity, but cannot use // the regular entity_create() function here. - $schema = DatabaseStorageController::_fieldSqlSchema(new Field($field_config), $field_config['schema']); + $schema = FieldableDatabaseStorageController::_fieldSqlSchema(new Field($field_config), $field_config['schema']); foreach ($schema as $name => $table) { db_create_table($name, $table); } @@ -119,8 +119,8 @@ function _update_8006_field_write_data_sql($entity_type, $bundle, $entity_id, $r $field_config = \Drupal::config("field.field.$entity_type.$field_name"); $field = new Field($field_config); - $table_name = DatabaseStorageController::_fieldTableName($field); - $revision_name = DatabaseStorageController::_fieldRevisionTableName($field); + $table_name = FieldableDatabaseStorageController::_fieldTableName($field); + $revision_name = FieldableDatabaseStorageController::_fieldRevisionTableName($field); db_delete($table_name) ->condition('entity_id', $entity_id) @@ -141,7 +141,7 @@ function _update_8006_field_write_data_sql($entity_type, $bundle, $entity_id, $r 'langcode' => $langcode, ); foreach ($item as $column => $value) { - $record[DatabaseStorageController::_fieldColumnName($field_name, $column)] = $value; + $record[FieldableDatabaseStorageController::_fieldColumnName($field_name, $column)] = $value; } $records[] = $record; @@ -363,8 +363,8 @@ function field_update_8003() { $field = new Field($config); // Additionally, rename the data tables for deleted fields. $tables = array( - "field_deleted_data_{$record['id']}" => 'old_' . DatabaseStorageController::_fieldTableName($field), - "field_deleted_revision_{$record['id']}" => 'old_' . DatabaseStorageController::_fieldRevisionTableName($field), + "field_deleted_data_{$record['id']}" => 'old_' . FieldableDatabaseStorageController::_fieldTableName($field), + "field_deleted_revision_{$record['id']}" => 'old_' . FieldableDatabaseStorageController::_fieldRevisionTableName($field), ); foreach ($tables as $table_old => $table_new) { if (db_table_exists($table_old)) { @@ -512,7 +512,7 @@ function field_update_8006(&$sandbox) { $tables = array( array( 'old_table' => 'field_data_' . $field_config['name'], - 'new_table' => DatabaseStorageController::_fieldTableName($field), + 'new_table' => FieldableDatabaseStorageController::_fieldTableName($field), 'primary_key' => array( 'entity_id', 'deleted', @@ -522,7 +522,7 @@ function field_update_8006(&$sandbox) { ), array( 'old_table' => 'field_revision_' . $field_config['name'], - 'new_table' => DatabaseStorageController::_fieldRevisionTableName($field), + 'new_table' => FieldableDatabaseStorageController::_fieldRevisionTableName($field), 'primary_key' => array( 'entity_id', 'revision_id', diff --git a/core/modules/field/field.views.inc b/core/modules/field/field.views.inc index 8269575..ac3d137 100644 --- a/core/modules/field/field.views.inc +++ b/core/modules/field/field.views.inc @@ -8,7 +8,7 @@ */ use Drupal\Component\Utility\NestedArray; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\field\FieldInterface; @@ -70,7 +70,7 @@ function field_views_data_alter(&$data) { function _field_views_is_sql_entity_type(FieldInterface $field) { $entity_manager = \Drupal::entityManager(); try { - if ($entity_manager->getStorageController($field->entity_type) instanceof DatabaseStorageController) { + if ($entity_manager->getStorageController($field->entity_type) instanceof FieldableDatabaseStorageController) { return TRUE; } } @@ -146,13 +146,13 @@ function field_views_field_default_views_data(FieldInterface $field) { // Description of the field tables. $field_tables = array( EntityStorageControllerInterface::FIELD_LOAD_CURRENT => array( - 'table' => DatabaseStorageController::_fieldTableName($field), + 'table' => FieldableDatabaseStorageController::_fieldTableName($field), 'alias' => "{$entity_type}__{$field->name}", ), ); if ($supports_revisions) { $field_tables[EntityStorageControllerInterface::FIELD_LOAD_REVISION] = array( - 'table' => DatabaseStorageController::_fieldRevisionTableName($field), + 'table' => FieldableDatabaseStorageController::_fieldRevisionTableName($field), 'alias' => "{$entity_type}_revision__{$field->name}", ); } @@ -184,7 +184,7 @@ function field_views_field_default_views_data(FieldInterface $field) { // Build the list of additional fields to add to queries. $add_fields = array('delta', 'langcode', 'bundle'); foreach (array_keys($field['columns']) as $column) { - $add_fields[] = DatabaseStorageController::_fieldColumnName($field, $column); + $add_fields[] = FieldableDatabaseStorageController::_fieldColumnName($field, $column); } // Determine the label to use for the field. We don't have a label available // at the field level, so we just go through all instances and take the one @@ -308,10 +308,10 @@ function field_views_field_default_views_data(FieldInterface $field) { else { $group = t('@group (historical data)', array('@group' => $group_name)); } - $column_real_name = DatabaseStorageController::_fieldColumnName($field, $column); + $column_real_name = FieldableDatabaseStorageController::_fieldColumnName($field, $column); // Load all the fields from the table by default. - $field_sql_schema = DatabaseStorageController::_fieldSqlSchema($field); + $field_sql_schema = FieldableDatabaseStorageController::_fieldSqlSchema($field); $additional_fields = array_keys($field_sql_schema[$table]['fields']); $data[$table_alias][$column_real_name] = array( diff --git a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php index ea74a94..78cc573 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php +++ b/core/modules/field/lib/Drupal/field/Plugin/views/field/Field.php @@ -7,7 +7,7 @@ namespace Drupal\field\Plugin\views\field; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\Language\Language; @@ -289,7 +289,7 @@ public function clickSort($order) { $this->ensureMyTable(); $field = field_info_field($this->definition['entity_type'], $this->definition['field_name']); - $column = DatabaseStorageController::_fieldColumnName($field, $this->options['click_sort_column']); + $column = FieldableDatabaseStorageController::_fieldColumnName($field, $this->options['click_sort_column']); if (!isset($this->aliases[$column])) { // Column is not in query; add a sort on it (without adding the column). $this->aliases[$column] = $this->tableAlias . '.' . $column; diff --git a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php index 0baa951..f22b7d1 100644 --- a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php @@ -7,7 +7,7 @@ namespace Drupal\field\Tests; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Core\Entity\EntityInterface; use Drupal\field\FieldInterface; @@ -186,9 +186,9 @@ function testDeleteFieldInstance() { $this->assertEqual($instance['bundle'], $bundle, 'The deleted instance is for the correct bundle'); // Check that the actual stored content did not change during delete. - $schema = DatabaseStorageController::_fieldSqlSchema($field); - $table = DatabaseStorageController::_fieldTableName($field); - $column = DatabaseStorageController::_fieldColumnName($field, 'value'); + $schema = FieldableDatabaseStorageController::_fieldSqlSchema($field); + $table = FieldableDatabaseStorageController::_fieldTableName($field); + $column = FieldableDatabaseStorageController::_fieldColumnName($field, 'value'); $result = db_select($table, 't') ->fields('t', array_keys($schema[$table]['fields'])) ->execute(); diff --git a/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php b/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php index 1f60380..5da93b0 100644 --- a/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php +++ b/core/modules/field/lib/Drupal/field/Tests/Views/ApiDataTest.php @@ -6,7 +6,7 @@ */ namespace Drupal\field\Tests\Views; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; /** * Test the produced views_data. @@ -62,8 +62,8 @@ function testViewsData() { // Check the table and the joins of the first field. // Attached to node only. $field = $this->fields[0]; - $current_table = DatabaseStorageController::_fieldTableName($field); - $revision_table = DatabaseStorageController::_fieldRevisionTableName($field); + $current_table = FieldableDatabaseStorageController::_fieldTableName($field); + $revision_table = FieldableDatabaseStorageController::_fieldRevisionTableName($field); $data[$current_table] = $views_data->get($current_table); $data[$revision_table] = $views_data->get($revision_table); diff --git a/core/modules/file/file.install b/core/modules/file/file.install index 7fb5772..c5ec889 100644 --- a/core/modules/file/file.install +++ b/core/modules/file/file.install @@ -5,7 +5,7 @@ * Install, update and uninstall functions for File module. */ -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\field\Entity\Field; /** @@ -271,10 +271,10 @@ function file_update_8003() { if (in_array($field_config->get('type'), array('file', 'image'))) { $field = new Field($field_config->get()); - if (db_table_exists(DatabaseStorageController::_fieldTableName($field))) { + if (db_table_exists(FieldableDatabaseStorageController::_fieldTableName($field))) { $tables = array( - DatabaseStorageController::_fieldTableName($field), - DatabaseStorageController::_fieldRevisionTableName($field), + FieldableDatabaseStorageController::_fieldTableName($field), + FieldableDatabaseStorageController::_fieldRevisionTableName($field), ); foreach ($tables as $table_name) { diff --git a/core/modules/file/file.views.inc b/core/modules/file/file.views.inc index 501ce7c..81f6066 100644 --- a/core/modules/file/file.views.inc +++ b/core/modules/file/file.views.inc @@ -7,7 +7,7 @@ * @ingroup views_module_handlers */ -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\field\FieldInterface; /** @@ -498,7 +498,7 @@ function file_field_views_data_views_data_alter(array &$data, FieldInterface $fi 'id' => 'entity_reverse', 'field_name' => $field['field_name'], 'entity_type' => $field['entity_type'], - 'field table' => DatabaseStorageController::_fieldTableName($field), + 'field table' => FieldableDatabaseStorageController::_fieldTableName($field), 'field field' => $field['field_name'] . '_target_id', 'base' => $entity_info['base_table'], 'base field' => $entity_info['entity_keys']['id'], diff --git a/core/modules/file/lib/Drupal/file/FileStorageController.php b/core/modules/file/lib/Drupal/file/FileStorageController.php index 2f27551..9dbe289 100644 --- a/core/modules/file/lib/Drupal/file/FileStorageController.php +++ b/core/modules/file/lib/Drupal/file/FileStorageController.php @@ -7,12 +7,12 @@ namespace Drupal\file; -use Drupal\Core\Entity\DatabaseStorageControllerNG; +use Drupal\Core\Entity\FieldableDatabaseStorageController; /** * File storage controller for files. */ -class FileStorageController extends DatabaseStorageControllerNG implements FileStorageControllerInterface { +class FileStorageController extends FieldableDatabaseStorageController implements FileStorageControllerInterface { /** * {@inheritdoc} diff --git a/core/modules/image/image.views.inc b/core/modules/image/image.views.inc index 356f140..786559a 100644 --- a/core/modules/image/image.views.inc +++ b/core/modules/image/image.views.inc @@ -7,7 +7,7 @@ * @ingroup views_module_handlers */ -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\field\FieldInterface; /** @@ -52,7 +52,7 @@ function image_field_views_data_views_data_alter(array &$data, FieldInterface $f 'id' => 'entity_reverse', 'field_name' => $field['field_name'], 'entity_type' => $field['entity_type'], - 'field table' => DatabaseStorageController::_fieldTableName($field), + 'field table' => FieldableDatabaseStorageController::_fieldTableName($field), 'field field' => $field['field_name'] . '_target_id', 'base' => $entity_info['base_table'], 'base field' => $entity_info['entity_keys']['id'], diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php index 7330147..a1265b0 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php @@ -53,13 +53,11 @@ class MenuLinkStorageController extends DatabaseStorageController implements Men * An array of entity info for the entity type. * @param \Drupal\Core\Database\Connection $database * The database connection to be used. - * @param \Drupal\field\FieldInfo $field_info - * The field info service. * @param \Symfony\Cmf\Component\Routing\RouteProviderInterface $route_provider * The route provider service. */ - public function __construct($entity_type, array $entity_info, Connection $database, FieldInfo $field_info, RouteProviderInterface $route_provider) { - parent::__construct($entity_type, $entity_info, $database, $field_info); + public function __construct($entity_type, array $entity_info, Connection $database, RouteProviderInterface $route_provider) { + parent::__construct($entity_type, $entity_info, $database); $this->routeProvider = $route_provider; @@ -88,7 +86,6 @@ public static function createInstance(ContainerInterface $container, $entity_typ $entity_type, $entity_info, $container->get('database'), - $container->get('field.info'), $container->get('router.route_provider') ); } diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php index 1360af3..f7192f1 100644 --- a/core/modules/node/lib/Drupal/node/NodeStorageController.php +++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php @@ -7,7 +7,7 @@ namespace Drupal\node; -use Drupal\Core\Entity\DatabaseStorageControllerNG; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Core\Entity\EntityInterface; /** @@ -16,7 +16,7 @@ * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding * required special handling for node entities. */ -class NodeStorageController extends DatabaseStorageControllerNG { +class NodeStorageController extends FieldableDatabaseStorageController { /** * Overrides Drupal\Core\Entity\DatabaseStorageController::create(). @@ -30,7 +30,7 @@ public function create(array $values) { } /** - * Overrides Drupal\Core\Entity\DatabaseStorageControllerNG::attachLoad(). + * Overrides Drupal\Core\Entity\DatabaseStorageController::attachLoad(). */ protected function attachLoad(&$queried_entities, $load_revision = FALSE) { $queried_entities = $this->mapFromStorageRecords($queried_entities, $load_revision); diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/FieldSqlStorageTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/FieldSqlStorageTest.php index 4988b49..c05f0c6 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/FieldSqlStorageTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/FieldSqlStorageTest.php @@ -8,7 +8,7 @@ namespace Drupal\system\Tests\Entity; use Drupal\Core\Database\Database; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\field\FieldException; use Drupal\field\Entity\Field; use Drupal\system\Tests\Entity\EntityUnitTestBase; @@ -84,8 +84,8 @@ function setUp() { )); $this->instance->save(); - $this->table = DatabaseStorageController::_fieldTableName($this->field); - $this->revision_table = DatabaseStorageController::_fieldRevisionTableName($this->field); + $this->table = FieldableDatabaseStorageController::_fieldTableName($this->field); + $this->revision_table = FieldableDatabaseStorageController::_fieldRevisionTableName($this->field); } /** @@ -95,7 +95,7 @@ function testFieldLoad() { $entity_type = $bundle = 'entity_test_rev'; $storage_controller = $this->container->get('entity.manager')->getStorageController($entity_type); - $columns = array('bundle', 'deleted', 'entity_id', 'revision_id', 'delta', 'langcode', DatabaseStorageController::_fieldColumnName($this->field, 'value')); + $columns = array('bundle', 'deleted', 'entity_id', 'revision_id', 'delta', 'langcode', FieldableDatabaseStorageController::_fieldColumnName($this->field, 'value')); // Create an entity with four revisions. $revision_ids = array(); @@ -352,7 +352,7 @@ function testFieldUpdateFailure() { } // Ensure that the field tables are still there. - foreach (DatabaseStorageController::_fieldSqlSchema($prior_field) as $table_name => $table_info) { + foreach (FieldableDatabaseStorageController::_fieldSqlSchema($prior_field) as $table_name => $table_info) { $this->assertTrue(db_table_exists($table_name), t('Table %table exists.', array('%table' => $table_name))); } } @@ -376,7 +376,7 @@ function testFieldUpdateIndexesWithData() { 'bundle' => $entity_type, )); $instance->save(); - $tables = array(DatabaseStorageController::_fieldTableName($field), DatabaseStorageController::_fieldRevisionTableName($field)); + $tables = array(FieldableDatabaseStorageController::_fieldTableName($field), FieldableDatabaseStorageController::_fieldRevisionTableName($field)); // Verify the indexes we will create do not exist yet. foreach ($tables as $table) { @@ -449,11 +449,11 @@ function testFieldSqlStorageForeignKeys() { $this->assertEqual($schema['foreign keys'][$foreign_key_name]['columns'][$foreign_key_name], 'id', 'Foreign key column name modified after update'); // Verify the SQL schema. - $schemas = DatabaseStorageController::_fieldSqlSchema($field); - $schema = $schemas[DatabaseStorageController::_fieldTableName($field)]; + $schemas = FieldableDatabaseStorageController::_fieldSqlSchema($field); + $schema = $schemas[FieldableDatabaseStorageController::_fieldTableName($field)]; $this->assertEqual(count($schema['foreign keys']), 1, 'There is 1 foreign key in the schema'); $foreign_key = reset($schema['foreign keys']); - $foreign_key_column = DatabaseStorageController::_fieldColumnName($field, $foreign_key_name); + $foreign_key_column = FieldableDatabaseStorageController::_fieldColumnName($field, $foreign_key_name); $this->assertEqual($foreign_key['table'], $foreign_key_name, 'Foreign key table name preserved in the schema'); $this->assertEqual($foreign_key['columns'][$foreign_key_column], 'id', 'Foreign key column name preserved in the schema'); } @@ -475,9 +475,9 @@ public function testTableNames() { 'type' => 'test_field', )); $expected = 'short_entity_type__short_field_name'; - $this->assertEqual(DatabaseStorageController::_fieldTableName($field), $expected); + $this->assertEqual(FieldableDatabaseStorageController::_fieldTableName($field), $expected); $expected = 'short_entity_type_revision__short_field_name'; - $this->assertEqual(DatabaseStorageController::_fieldRevisionTableName($field), $expected); + $this->assertEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), $expected); // Short entity type, long field name $entity_type = 'short_entity_type'; @@ -488,9 +488,9 @@ public function testTableNames() { 'type' => 'test_field', )); $expected = 'short_entity_type__' . substr(hash('sha256', $field->uuid), 0, 10); - $this->assertEqual(DatabaseStorageController::_fieldTableName($field), $expected); + $this->assertEqual(FieldableDatabaseStorageController::_fieldTableName($field), $expected); $expected = 'short_entity_type_r__' . substr(hash('sha256', $field->uuid), 0, 10); - $this->assertEqual(DatabaseStorageController::_fieldRevisionTableName($field), $expected); + $this->assertEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), $expected); // Long entity type, short field name $entity_type = 'long_entity_type_abcdefghijklmnopqrstuvwxyz'; @@ -501,9 +501,9 @@ public function testTableNames() { 'type' => 'test_field', )); $expected = 'long_entity_type_abcdefghijklmnopq__' . substr(hash('sha256', $field->uuid), 0, 10); - $this->assertEqual(DatabaseStorageController::_fieldTableName($field), $expected); + $this->assertEqual(FieldableDatabaseStorageController::_fieldTableName($field), $expected); $expected = 'long_entity_type_abcdefghijklmnopq_r__' . substr(hash('sha256', $field->uuid), 0, 10); - $this->assertEqual(DatabaseStorageController::_fieldRevisionTableName($field), $expected); + $this->assertEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), $expected); // Long entity type and field name. $entity_type = 'long_entity_type_abcdefghijklmnopqrstuvwxyz'; @@ -514,17 +514,17 @@ public function testTableNames() { 'type' => 'test_field', )); $expected = 'long_entity_type_abcdefghijklmnopq__' . substr(hash('sha256', $field->uuid), 0, 10); - $this->assertEqual(DatabaseStorageController::_fieldTableName($field), $expected); + $this->assertEqual(FieldableDatabaseStorageController::_fieldTableName($field), $expected); $expected = 'long_entity_type_abcdefghijklmnopq_r__' . substr(hash('sha256', $field->uuid), 0, 10); - $this->assertEqual(DatabaseStorageController::_fieldRevisionTableName($field), $expected); + $this->assertEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), $expected); // Try creating a second field and check there are no clashes. $field2 = entity_create('field_entity', array( 'entity_type' => $entity_type, 'name' => $field_name . '2', 'type' => 'test_field', )); - $this->assertNotEqual(DatabaseStorageController::_fieldTableName($field), DatabaseStorageController::_fieldTableName($field2)); - $this->assertNotEqual(DatabaseStorageController::_fieldRevisionTableName($field), DatabaseStorageController::_fieldRevisionTableName($field2)); + $this->assertNotEqual(FieldableDatabaseStorageController::_fieldTableName($field), FieldableDatabaseStorageController::_fieldTableName($field2)); + $this->assertNotEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), FieldableDatabaseStorageController::_fieldRevisionTableName($field2)); // Deleted field. $field = entity_create('field_entity', array( @@ -534,9 +534,9 @@ public function testTableNames() { 'deleted' => TRUE, )); $expected = 'field_deleted_data_' . substr(hash('sha256', $field->uuid), 0, 10); - $this->assertEqual(DatabaseStorageController::_fieldTableName($field), $expected); + $this->assertEqual(FieldableDatabaseStorageController::_fieldTableName($field), $expected); $expected = 'field_deleted_revision_' . substr(hash('sha256', $field->uuid), 0, 10); - $this->assertEqual(DatabaseStorageController::_fieldRevisionTableName($field), $expected); + $this->assertEqual(FieldableDatabaseStorageController::_fieldRevisionTableName($field), $expected); } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php index d615512..4c3757a 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUpgradePathTest.php @@ -7,7 +7,7 @@ namespace Drupal\system\Tests\Upgrade; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\field\Entity\Field; /** @@ -278,7 +278,7 @@ function testFieldUpgradeToConfig() { // Check that pre-existing deleted field table is renamed correctly. $field_entity = new Field($deleted_field); - $table_name = DatabaseStorageController::_fieldTableName($field_entity); + $table_name = FieldableDatabaseStorageController::_fieldTableName($field_entity); $this->assertEqual("field_deleted_data_" . substr(hash('sha256', $deleted_field['uuid']), 0, 10), $table_name); $this->assertTrue(db_table_exists($table_name)); diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php index bb8d390..a348fc6 100644 --- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php +++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestStorageController.php @@ -7,7 +7,7 @@ namespace Drupal\entity_test; -use Drupal\Core\Entity\DatabaseStorageControllerNG; +use Drupal\Core\Entity\FieldableDatabaseStorageController; /** * Defines the controller class for the test entity. @@ -15,7 +15,7 @@ * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding * required special handling for test entities. */ -class EntityTestStorageController extends DatabaseStorageControllerNG { +class EntityTestStorageController extends FieldableDatabaseStorageController { /** * {@inheritdoc} diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php index f77b1b5..1a47334 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermStorageController.php @@ -9,12 +9,12 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Query\QueryInterface; -use Drupal\Core\Entity\DatabaseStorageControllerNG; +use Drupal\Core\Entity\FieldableDatabaseStorageController; /** * Defines a Controller class for taxonomy terms. */ -class TermStorageController extends DatabaseStorageControllerNG implements TermStorageControllerInterface { +class TermStorageController extends FieldableDatabaseStorageController implements TermStorageControllerInterface { /** * Overrides Drupal\Core\Entity\DatabaseStorageController::create(). diff --git a/core/modules/taxonomy/taxonomy.install b/core/modules/taxonomy/taxonomy.install index 775527d..7e03b90 100644 --- a/core/modules/taxonomy/taxonomy.install +++ b/core/modules/taxonomy/taxonomy.install @@ -6,7 +6,7 @@ */ use Drupal\Component\Uuid\Uuid; -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\field\Entity\Field; /** @@ -354,10 +354,10 @@ function taxonomy_update_8007() { if ($field_config->get('type') == 'taxonomy_term_reference') { $field = new Field($field_config->get()); - if (db_table_exists(DatabaseStorageController::_fieldTableName($field))) { + if (db_table_exists(FieldableDatabaseStorageController::_fieldTableName($field))) { $tables = array( - DatabaseStorageController::_fieldTableName($field), - DatabaseStorageController::_fieldRevisionTableName($field), + FieldableDatabaseStorageController::_fieldTableName($field), + FieldableDatabaseStorageController::_fieldRevisionTableName($field), ); foreach ($tables as $table_name) { diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 81537b6..a5aa1cd 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -5,7 +5,7 @@ * Enables the organization of content into categories. */ -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Field\FieldDefinitionInterface; use Drupal\node\Entity\Node; @@ -1099,7 +1099,7 @@ function taxonomy_node_insert(EntityInterface $node) { function taxonomy_build_node_index($node) { // We maintain a denormalized table of term/node relationships, containing // only data for current, published nodes. - if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !(\Drupal::entityManager()->getStorageController('node') instanceof DatabaseStorageController)) { + if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !(\Drupal::entityManager()->getStorageController('node') instanceof FieldableDatabaseStorageController)) { return; } diff --git a/core/modules/taxonomy/taxonomy.views.inc b/core/modules/taxonomy/taxonomy.views.inc index 4e9f27c..727d2a6 100644 --- a/core/modules/taxonomy/taxonomy.views.inc +++ b/core/modules/taxonomy/taxonomy.views.inc @@ -7,7 +7,7 @@ * @ingroup views_module_handlers */ -use Drupal\Core\Entity\DatabaseStorageController; +use Drupal\Core\Entity\FieldableDatabaseStorageController; use Drupal\field\FieldInterface; /** @@ -448,7 +448,7 @@ function taxonomy_field_views_data_views_data_alter(array &$data, FieldInterface 'id' => 'entity_reverse', 'field_name' => $field['field_name'], 'entity_type' => $field['entity_type'], - 'field table' => DatabaseStorageController::_fieldTableName($field), + 'field table' => FieldableDatabaseStorageController::_fieldTableName($field), 'field field' => $field['field_name'] . '_target_id', 'base' => $entity_info['base_table'], 'base field' => $entity_info['entity_keys']['id'], diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php index 9cbcf0e..cc6b152 100644 --- a/core/modules/user/lib/Drupal/user/UserStorageController.php +++ b/core/modules/user/lib/Drupal/user/UserStorageController.php @@ -13,7 +13,7 @@ use Drupal\field\FieldInfo; use Drupal\user\UserDataInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\Entity\DatabaseStorageControllerNG; +use Drupal\Core\Entity\FieldableDatabaseStorageController; /** * Controller class for users. @@ -21,7 +21,7 @@ * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding * required special handling for user objects. */ -class UserStorageController extends DatabaseStorageControllerNG implements UserStorageControllerInterface { +class UserStorageController extends FieldableDatabaseStorageController implements UserStorageControllerInterface { /** * Provides the password hashing service object. diff --git a/core/modules/views/lib/Drupal/views/Tests/QueryGroupByTest.php b/core/modules/views/lib/Drupal/views/Tests/QueryGroupByTest.php index edb6737..7c09bbf 100644 --- a/core/modules/views/lib/Drupal/views/Tests/QueryGroupByTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/QueryGroupByTest.php @@ -29,7 +29,7 @@ class QueryGroupByTest extends ViewUnitTestBase { /** * The storage controller for the test entity type. * - * @var \Drupal\Core\Entity\DatabaseStorageController + * @var \Drupal\Core\Entity\FieldableDatabaseStorageController */ public $storageController;