namespace Drupal\Core\Entity\Sql;
use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Database;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Database\SchemaException;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\ContentEntityStorageBase;
+use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityBundleListenerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
-use Drupal\field\FieldStorageConfigInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
$container->get('database'),
$container->get('entity.manager'),
$container->get('cache.entity'),
- $container->get('language_manager')
+ $container->get('language_manager'),
+ $container->get('entity.memory_cache')
);
}
* The cache backend to be used.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
+ * @param \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface|null $memory_cache
+ * The memory cache backend to be used.
*/
- public function __construct(EntityTypeInterface $entity_type, Connection $database, EntityManagerInterface $entity_manager, CacheBackendInterface $cache, LanguageManagerInterface $language_manager) {
- parent::__construct($entity_type, $entity_manager, $cache);
+ public function __construct(EntityTypeInterface $entity_type, Connection $database, EntityManagerInterface $entity_manager, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, MemoryCacheInterface $memory_cache = NULL) {
+ parent::__construct($entity_type, $entity_manager, $cache, $memory_cache);
$this->database = $database;
$this->languageManager = $language_manager;
$this->initTableLayout();
$this->dataTable = NULL;
$this->revisionDataTable = NULL;
- // @todo Remove table names from the entity type definition in
- // https://www.drupal.org/node/2232465.
- $this->baseTable = $this->entityType->getBaseTable() ?: $this->entityTypeId;
+ $table_mapping = $this->getTableMapping();
+ $this->baseTable = $table_mapping->getBaseTable();
$revisionable = $this->entityType->isRevisionable();
if ($revisionable) {
$this->revisionKey = $this->entityType->getKey('revision') ?: 'revision_id';
- $this->revisionTable = $this->entityType->getRevisionTable() ?: $this->entityTypeId . '_revision';
+ $this->revisionTable = $table_mapping->getRevisionTable();
}
$translatable = $this->entityType->isTranslatable();
if ($translatable) {
- $this->dataTable = $this->entityType->getDataTable() ?: $this->entityTypeId . '_field_data';
+ $this->dataTable = $table_mapping->getDataTable();
$this->langcodeKey = $this->entityType->getKey('langcode');
$this->defaultLangcodeKey = $this->entityType->getKey('default_langcode');
}
if ($revisionable && $translatable) {
- $this->revisionDataTable = $this->entityType->getRevisionDataTable() ?: $this->entityTypeId . '_field_revision';
+ $this->revisionDataTable = $table_mapping->getRevisionDataTable();
}
}
*/
public function setTableMapping(TableMappingInterface $table_mapping) {
$this->tableMapping = $table_mapping;
+
+ $this->baseTable = $table_mapping->getBaseTable();
+ $this->revisionTable = $table_mapping->getRevisionTable();
+ $this->dataTable = $table_mapping->getDataTable();
+ $this->revisionDataTable = $table_mapping->getRevisionDataTable();
}
/**
* {@inheritdoc}
*/
public function getTableMapping(array $storage_definitions = NULL) {
- $table_mapping = $this->tableMapping;
+ // If a new set of field storage definitions is passed, for instance when
+ // comparing old and new storage schema, we compute the table mapping
+ // without caching.
+ if ($storage_definitions) {
+ return $this->getCustomTableMapping($this->entityType, $storage_definitions);
+ }
// If we are using our internal storage definitions, which is our main use
- // case, we can statically cache the computed table mapping. If a new set
- // of field storage definitions is passed, for instance when comparing old
- // and new storage schema, we compute the table mapping without caching.
- // @todo Clean-up this in https://www.drupal.org/node/2274017 so we can
- // easily instantiate a new table mapping whenever needed.
- if (!isset($this->tableMapping) || $storage_definitions) {
- $table_mapping_class = $this->temporary ? TemporaryTableMapping::class : DefaultTableMapping::class;
- $definitions = $storage_definitions ?: $this->entityManager->getFieldStorageDefinitions($this->entityTypeId);
- /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping|\Drupal\Core\Entity\Sql\TemporaryTableMapping $table_mapping */
- $table_mapping = new $table_mapping_class($this->entityType, $definitions);
-
- $shared_table_definitions = array_filter($definitions, function (FieldStorageDefinitionInterface $definition) use ($table_mapping) {
- return $table_mapping->allowsSharedTableStorage($definition);
- });
-
- $key_fields = array_values(array_filter([$this->idKey, $this->revisionKey, $this->bundleKey, $this->uuidKey, $this->langcodeKey]));
- $all_fields = array_keys($shared_table_definitions);
- $revisionable_fields = array_keys(array_filter($shared_table_definitions, function (FieldStorageDefinitionInterface $definition) {
- return $definition->isRevisionable();
- }));
- // Make sure the key fields come first in the list of fields.
- $all_fields = array_merge($key_fields, array_diff($all_fields, $key_fields));
-
- // If the entity is revisionable, gather the fields that need to be put
- // in the revision table.
- $revisionable = $this->entityType->isRevisionable();
- $revision_metadata_fields = $revisionable ? array_values($this->entityType->getRevisionMetadataKeys()) : [];
-
- $translatable = $this->entityType->isTranslatable();
- if (!$revisionable && !$translatable) {
- // The base layout stores all the base field values in the base table.
- $table_mapping->setFieldNames($this->baseTable, $all_fields);
- }
- elseif ($revisionable && !$translatable) {
- // The revisionable layout stores all the base field values in the base
- // table, except for revision metadata fields. Revisionable fields
- // denormalized in the base table but also stored in the revision table
- // together with the entity ID and the revision ID as identifiers.
- $table_mapping->setFieldNames($this->baseTable, array_diff($all_fields, $revision_metadata_fields));
- $revision_key_fields = [$this->idKey, $this->revisionKey];
- $table_mapping->setFieldNames($this->revisionTable, array_merge($revision_key_fields, $revisionable_fields));
- }
- elseif (!$revisionable && $translatable) {
- // Multilingual layouts store key field values in the base table. The
- // other base field values are stored in the data table, no matter
- // whether they are translatable or not. The data table holds also a
- // denormalized copy of the bundle field value to allow for more
- // performant queries. This means that only the UUID is not stored on
- // the data table.
- $table_mapping
- ->setFieldNames($this->baseTable, $key_fields)
- ->setFieldNames($this->dataTable, array_values(array_diff($all_fields, [$this->uuidKey])));
- }
- elseif ($revisionable && $translatable) {
- // The revisionable multilingual layout stores key field values in the
- // base table, except for language, which is stored in the revision
- // table along with revision metadata. The revision data table holds
- // data field values for all the revisionable fields and the data table
- // holds the data field values for all non-revisionable fields. The data
- // field values of revisionable fields are denormalized in the data
- // table, as well.
- $table_mapping->setFieldNames($this->baseTable, array_values($key_fields));
-
- // Like in the multilingual, non-revisionable case the UUID is not
- // in the data table. Additionally, do not store revision metadata
- // fields in the data table.
- $data_fields = array_values(array_diff($all_fields, [$this->uuidKey], $revision_metadata_fields));
- $table_mapping->setFieldNames($this->dataTable, $data_fields);
-
- $revision_base_fields = array_merge([$this->idKey, $this->revisionKey, $this->langcodeKey], $revision_metadata_fields);
- $table_mapping->setFieldNames($this->revisionTable, $revision_base_fields);
-
- $revision_data_key_fields = [$this->idKey, $this->revisionKey, $this->langcodeKey];
- $revision_data_fields = array_diff($revisionable_fields, $revision_metadata_fields, [$this->langcodeKey]);
- $table_mapping->setFieldNames($this->revisionDataTable, array_merge($revision_data_key_fields, $revision_data_fields));
- }
-
- // Add dedicated tables.
- $dedicated_table_definitions = array_filter($definitions, function (FieldStorageDefinitionInterface $definition) use ($table_mapping) {
- return $table_mapping->requiresDedicatedTableStorage($definition);
- });
- $extra_columns = [
- 'bundle',
- 'deleted',
- 'entity_id',
- 'revision_id',
- 'langcode',
- 'delta',
- ];
- foreach ($dedicated_table_definitions as $field_name => $definition) {
- $tables = [$table_mapping->getDedicatedDataTableName($definition)];
- if ($revisionable && $definition->isRevisionable()) {
- $tables[] = $table_mapping->getDedicatedRevisionTableName($definition);
- }
- foreach ($tables as $table_name) {
- $table_mapping->setFieldNames($table_name, [$field_name]);
- $table_mapping->setExtraColumns($table_name, $extra_columns);
- }
- }
+ // case, we can statically cache the computed table mapping.
+ if (!isset($this->tableMapping)) {
+ $storage_definitions = $this->entityManager->getFieldStorageDefinitions($this->entityTypeId);
- // Cache the computed table mapping only if we are using our internal
- // storage definitions.
- if (!$storage_definitions) {
- $this->tableMapping = $table_mapping;
- }
+ $this->tableMapping = $this->getCustomTableMapping($this->entityType, $storage_definitions);
}
- return $table_mapping;
+ return $this->tableMapping;
+ }
+
+ /**
+ * Gets a table mapping for the specified entity type and storage definitions.
+ *
+ * @param \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type
+ * An entity type definition.
+ * @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $storage_definitions
+ * An array of field storage definitions to be used to compute the table
+ * mapping.
+ *
+ * @return \Drupal\Core\Entity\Sql\TableMappingInterface
+ * A table mapping object for the entity's tables.
+ *
+ * @internal
+ */
+ public function getCustomTableMapping(ContentEntityTypeInterface $entity_type, array $storage_definitions) {
+ $table_mapping_class = $this->temporary ? TemporaryTableMapping::class : DefaultTableMapping::class;
+ return $table_mapping_class::create($entity_type, $storage_definitions);
}
/**
* Maps from storage records to entity objects, and attaches fields.
*
* @param array $records
- * Associative array of query results, keyed on the entity ID.
+ * Associative array of query results, keyed on the entity ID or revision
+ * ID.
* @param bool $load_from_revision
- * Flag to indicate whether revisions should be loaded or not.
+ * (optional) Flag to indicate whether revisions should be loaded or not.
+ * Defaults to FALSE.
*
* @return array
* An array of entity objects implementing the EntityInterface.
return [];
}
+ // Get the names of the fields that are stored in the base table and, if
+ // applicable, the revision table. Other entity data will be loaded in
+ // loadFromSharedTables() and loadFromDedicatedTables().
+ $field_names = $this->tableMapping->getFieldNames($this->baseTable);
+ if ($this->revisionTable) {
+ $field_names = array_unique(array_merge($field_names, $this->tableMapping->getFieldNames($this->revisionTable)));
+ }
+
$values = [];
foreach ($records as $id => $record) {
$values[$id] = [];
// Skip the item delta and item value levels (if possible) but let the
// field assign the value as suiting. This avoids unnecessary array
// hierarchies and saves memory here.
- foreach ($record as $name => $value) {
- // Handle columns named [field_name]__[column_name] (e.g for field types
- // that store several properties).
- if ($field_name = strstr($name, '__', TRUE)) {
- $property_name = substr($name, strpos($name, '__') + 2);
- $values[$id][$field_name][LanguageInterface::LANGCODE_DEFAULT][$property_name] = $value;
+ foreach ($field_names as $field_name) {
+ $field_columns = $this->tableMapping->getColumnNames($field_name);
+ // Handle field types that store several properties.
+ if (count($field_columns) > 1) {
+ foreach ($field_columns as $property_name => $column_name) {
+ if (property_exists($record, $column_name)) {
+ $values[$id][$field_name][LanguageInterface::LANGCODE_DEFAULT][$property_name] = $record->{$column_name};
+ unset($record->{$column_name});
+ }
+ }
}
+ // Handle field types that store only one property.
else {
- // Handle columns named directly after the field (e.g if the field
- // type only stores one property).
- $values[$id][$name][LanguageInterface::LANGCODE_DEFAULT] = $value;
+ $column_name = reset($field_columns);
+ if (property_exists($record, $column_name)) {
+ $values[$id][$field_name][LanguageInterface::LANGCODE_DEFAULT] = $record->{$column_name};
+ unset($record->{$column_name});
+ }
}
}
+
+ // Handle additional record entries that are not provided by an entity
+ // field, such as 'isDefaultRevision'.
+ foreach ($record as $name => $value) {
+ $values[$id][$name][LanguageInterface::LANGCODE_DEFAULT] = $value;
+ }
}
// Initialize translations array.
$translations = array_fill_keys(array_keys($values), []);
// Load values from shared and dedicated tables.
- $this->loadFromSharedTables($values, $translations);
+ $this->loadFromSharedTables($values, $translations, $load_from_revision);
$this->loadFromDedicatedTables($values, $load_from_revision);
$entities = [];
* Loads values for fields stored in the shared data tables.
*
* @param array &$values
- * Associative array of entities values, keyed on the entity ID.
+ * Associative array of entities values, keyed on the entity ID or the
+ * revision ID.
* @param array &$translations
* List of translations, keyed on the entity ID.
+ * @param bool $load_from_revision
+ * Flag to indicate whether revisions should be loaded or not.
*/
- protected function loadFromSharedTables(array &$values, array &$translations) {
+ protected function loadFromSharedTables(array &$values, array &$translations, $load_from_revision) {
+ $record_key = !$load_from_revision ? $this->idKey : $this->revisionKey;
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.
$alias = $this->revisionDataTable ? 'revision' : 'data';
$query = $this->database->select($table, $alias, ['fetch' => \PDO::FETCH_ASSOC])
->fields($alias)
- ->condition($alias . '.' . $this->idKey, array_keys($values), 'IN')
- ->orderBy($alias . '.' . $this->idKey);
+ ->condition($alias . '.' . $record_key, array_keys($values), 'IN')
+ ->orderBy($alias . '.' . $record_key);
$table_mapping = $this->getTableMapping();
if ($this->revisionDataTable) {
// Some fields can have more then one columns in the data table so
// column names are needed.
foreach ($data_fields as $data_field) {
- // \Drupal\Core\Entity\Sql\TableMappingInterface:: getColumNames()
+ // \Drupal\Core\Entity\Sql\TableMappingInterface::getColumnNames()
// returns an array keyed by property names so remove the keys
// before array_merge() to avoid losing data with fields having the
// same columns i.e. value.
$result = $query->execute();
foreach ($result as $row) {
- $id = $row[$this->idKey];
+ $id = $row[$record_key];
// Field values in default language are stored with
// LanguageInterface::LANGCODE_DEFAULT as key.
* {@inheritdoc}
*/
protected function doLoadRevisionFieldItems($revision_id) {
- $revision = NULL;
+ @trigger_error('"\Drupal\Core\Entity\ContentEntityStorageBase::doLoadRevisionFieldItems()" is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. "\Drupal\Core\Entity\ContentEntityStorageBase::doLoadMultipleRevisionsFieldItems()" should be implemented instead. See https://www.drupal.org/node/2924915.', E_USER_DEPRECATED);
+
+ $revisions = $this->doLoadMultipleRevisionsFieldItems([$revision_id]);
+
+ return !empty($revisions) ? reset($revisions) : NULL;
+ }
- // Build and execute the query.
- $query_result = $this->buildQuery([], $revision_id)->execute();
- $records = $query_result->fetchAllAssoc($this->idKey);
+ /**
+ * {@inheritdoc}
+ */
+ protected function doLoadMultipleRevisionsFieldItems($revision_ids) {
+ $revisions = [];
+
+ // Sanitize IDs. Before feeding ID array into buildQuery, check whether
+ // it is empty as this would load all entity revisions.
+ $revision_ids = $this->cleanIds($revision_ids, 'revision');
- if (!empty($records)) {
- // Convert the raw records to entity objects.
- $entities = $this->mapFromStorageRecords($records, TRUE);
- $revision = reset($entities) ?: NULL;
+ if (!empty($revision_ids)) {
+ // Build and execute the query.
+ $query_result = $this->buildQuery(NULL, $revision_ids)->execute();
+ $records = $query_result->fetchAllAssoc($this->revisionKey);
+
+ // Map the loaded records into entity objects and according fields.
+ if ($records) {
+ $revisions = $this->mapFromStorageRecords($records, TRUE);
+ }
}
- return $revision;
+ return $revisions;
}
/**
*
* @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).
+ * @param array|bool $revision_ids
+ * The IDs of the revisions to load, or FALSE if this query is asking for
+ * the default revisions. Defaults to FALSE.
*
* @return \Drupal\Core\Database\Query\Select
* A SelectQuery object for loading the entity.
*/
- protected function buildQuery($ids, $revision_id = FALSE) {
- $query = $this->database->select($this->entityType->getBaseTable(), 'base');
+ protected function buildQuery($ids, $revision_ids = FALSE) {
+ $query = $this->database->select($this->baseTable, 'base');
$query->addTag($this->entityTypeId . '_load_multiple');
- if ($revision_id) {
- $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} = :revisionId", [':revisionId' => $revision_id]);
+ if ($revision_ids) {
+ if (!is_array($revision_ids)) {
+ @trigger_error('Passing a single revision ID to "\Drupal\Core\Entity\Sql\SqlContentEntityStorage::buildQuery()" is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. An array of revision IDs should be given instead. See https://www.drupal.org/node/2924915.', E_USER_DEPRECATED);
+ }
+ $query->join($this->revisionTable, 'revision', "revision.{$this->idKey} = base.{$this->idKey} AND revision.{$this->revisionKey} IN (:revisionIds[])", [':revisionIds[]' => (array) $revision_ids]);
}
elseif ($this->revisionTable) {
$query->join($this->revisionTable, 'revision', "revision.{$this->revisionKey} = base.{$this->revisionKey}");
protected function doDeleteFieldItems($entities) {
$ids = array_keys($entities);
- $this->database->delete($this->entityType->getBaseTable())
+ $this->database->delete($this->baseTable)
->condition($this->idKey, $ids, 'IN')
->execute();
if ($update) {
$default_revision = $entity->isDefaultRevision();
if ($default_revision) {
+ // Remove the ID from the record to enable updates on SQL variants
+ // that prevent updating serial columns, for example, mssql.
+ unset($record->{$this->idKey});
$this->database
->update($this->baseTable)
->fields((array) $record)
- ->condition($this->idKey, $record->{$this->idKey})
+ ->condition($this->idKey, $entity->get($this->idKey)->value)
->execute();
}
if ($this->revisionTable) {
}
else {
$record = $this->mapToStorageRecord($entity->getUntranslated(), $this->revisionTable);
+ // Remove the revision ID from the record to enable updates on SQL
+ // variants that prevent updating serial columns, for example,
+ // mssql.
+ unset($record->{$this->revisionKey});
$entity->preSaveRevision($this, $record);
$this->database
->update($this->revisionTable)
->fields((array) $record)
- ->condition($this->revisionKey, $record->{$this->revisionKey})
+ ->condition($this->revisionKey, $entity->getRevisionId())
->execute();
}
}
$record->{$this->revisionKey} = $insert_id;
}
if ($entity->isDefaultRevision()) {
- $this->database->update($this->entityType->getBaseTable())
+ $this->database->update($this->baseTable)
->fields([$this->revisionKey => $record->{$this->revisionKey}])
->condition($this->idKey, $record->{$this->idKey})
->execute();
}
+ // Make sure to update the new revision key for the entity.
+ $entity->{$this->revisionKey}->value = $record->{$this->revisionKey};
}
else {
+ // Remove the revision ID from the record to enable updates on SQL
+ // variants that prevent updating serial columns, for example,
+ // mssql.
+ unset($record->{$this->revisionKey});
$this->database
->update($this->revisionTable)
->fields((array) $record)
- ->condition($this->revisionKey, $record->{$this->revisionKey})
+ ->condition($this->revisionKey, $entity->getRevisionId())
->execute();
}
-
- // Make sure to update the new revision key for the entity.
- $entity->{$this->revisionKey}->value = $record->{$this->revisionKey};
-
- return $record->{$this->revisionKey};
+ return $entity->getRevisionId();
}
/**
* @param array &$values
* An array of values keyed by entity ID.
* @param bool $load_from_revision
- * (optional) Flag to indicate whether revisions should be loaded or not,
- * defaults to FALSE.
+ * Flag to indicate whether revisions should be loaded or not.
*/
protected function loadFromDedicatedTables(array &$values, $load_from_revision) {
if (empty($values)) {
foreach ($results as $row) {
$bundle = $row->bundle;
+ $value_key = !$load_from_revision ? $row->entity_id : $row->revision_id;
// Field values in default language are stored with
// LanguageInterface::LANGCODE_DEFAULT as key.
$langcode = LanguageInterface::LANGCODE_DEFAULT;
- if ($this->langcodeKey && isset($default_langcodes[$row->entity_id]) && $row->langcode != $default_langcodes[$row->entity_id]) {
+ if ($this->langcodeKey && isset($default_langcodes[$value_key]) && $row->langcode != $default_langcodes[$value_key]) {
$langcode = $row->langcode;
}
- if (!isset($values[$row->entity_id][$field_name][$langcode])) {
- $values[$row->entity_id][$field_name][$langcode] = [];
+ if (!isset($values[$value_key][$field_name][$langcode])) {
+ $values[$value_key][$field_name][$langcode] = [];
}
// Ensure that records for non-translatable fields having invalid
// languages are skipped.
if ($langcode == LanguageInterface::LANGCODE_DEFAULT || $definitions[$bundle][$field_name]->isTranslatable()) {
- if ($storage_definition->getCardinality() == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || count($values[$row->entity_id][$field_name][$langcode]) < $storage_definition->getCardinality()) {
+ if ($storage_definition->getCardinality() == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || count($values[$value_key][$field_name][$langcode]) < $storage_definition->getCardinality()) {
$item = [];
// For each column declared by the field, populate the item from the
// prefixed database column.
}
// Add the item to the field values for the entity.
- $values[$row->entity_id][$field_name][$langcode][] = $item;
+ $values[$value_key][$field_name][$langcode][] = $item;
}
}
}
* {@inheritdoc}
*/
public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $storage_definition) {
- // If we are adding a field stored in a shared table we need to recompute
- // the table mapping.
- // @todo This does not belong here. Remove it once we are able to generate a
- // fresh table mapping in the schema handler. See
- // https://www.drupal.org/node/2274017.
- if ($this->getTableMapping()->allowsSharedTableStorage($storage_definition)) {
- $this->tableMapping = NULL;
- }
$this->wrapSchemaException(function () use ($storage_definition) {
$this->getStorageSchema()->onFieldStorageDefinitionCreate($storage_definition);
});
$this->entityManager->getLastInstalledFieldStorageDefinitions($this->entityType->id())
);
- // @todo Remove the FieldStorageConfigInterface check when non-configurable
- // fields support purging: https://www.drupal.org/node/2282119.
- if ($storage_definition instanceof FieldStorageConfigInterface && $table_mapping->requiresDedicatedTableStorage($storage_definition)) {
+ if ($table_mapping->requiresDedicatedTableStorage($storage_definition)) {
// Mark all data associated with the field for deletion.
$table = $table_mapping->getDedicatedDataTableName($storage_definition);
$revision_table = $table_mapping->getDedicatedRevisionTableName($storage_definition);
// Check whether the whole field storage definition is gone, or just some
// bundle fields.
$storage_definition = $field_definition->getFieldStorageDefinition();
- $is_deleted = $this->storageDefinitionIsDeleted($storage_definition);
$table_mapping = $this->getTableMapping();
- $table_name = $table_mapping->getDedicatedDataTableName($storage_definition, $is_deleted);
+ $table_name = $table_mapping->getDedicatedDataTableName($storage_definition, $storage_definition->isDeleted());
// Get the entities which we want to purge first.
$entity_query = $this->database->select($table_name, 't', ['fetch' => \PDO::FETCH_ASSOC]);
*/
protected function purgeFieldItems(ContentEntityInterface $entity, FieldDefinitionInterface $field_definition) {
$storage_definition = $field_definition->getFieldStorageDefinition();
- $is_deleted = $this->storageDefinitionIsDeleted($storage_definition);
+ $is_deleted = $storage_definition->isDeleted();
$table_mapping = $this->getTableMapping();
$table_name = $table_mapping->getDedicatedDataTableName($storage_definition, $is_deleted);
$revision_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, $is_deleted);
$table_mapping = $this->getTableMapping($storage_definitions);
if ($table_mapping->requiresDedicatedTableStorage($storage_definition)) {
- $is_deleted = $this->storageDefinitionIsDeleted($storage_definition);
+ $is_deleted = $storage_definition->isDeleted();
if ($this->entityType->isRevisionable()) {
$table_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, $is_deleted);
}
elseif ($table_mapping->allowsSharedTableStorage($storage_definition)) {
// Ascertain the table this field is mapped too.
$field_name = $storage_definition->getName();
- try {
- $table_name = $table_mapping->getFieldTableName($field_name);
- }
- catch (SqlContentEntityStorageException $e) {
- // This may happen when changing field storage schema, since we are not
- // able to use a table mapping matching the passed storage definition.
- // @todo Revisit this once we are able to instantiate the table mapping
- // properly. See https://www.drupal.org/node/2274017.
- $table_name = $this->dataTable ?: $this->baseTable;
- }
+ $table_name = $table_mapping->getFieldTableName($field_name);
$query = $this->database->select($table_name, 't');
$or = $query->orConditionGroup();
foreach (array_keys($storage_definition->getColumns()) as $property_name) {
*
* @return bool
* Whether the field has been already deleted.
+ *
+ * @deprecated in Drupal 8.5.x, will be removed before Drupal 9.0.0. Use
+ * \Drupal\Core\Field\FieldStorageDefinitionInterface::isDeleted() instead.
+ *
+ * @see https://www.drupal.org/node/2907785
*/
protected function storageDefinitionIsDeleted(FieldStorageDefinitionInterface $storage_definition) {
- // Configurable fields are marked for deletion.
- if ($storage_definition instanceof FieldStorageConfigInterface) {
- return $storage_definition->isDeleted();
- }
- // For non configurable fields check whether they are still in the last
- // installed schema repository.
- return !array_key_exists($storage_definition->getName(), $this->entityManager->getLastInstalledFieldStorageDefinitions($this->entityTypeId));
+ return $storage_definition->isDeleted();
}
}