Commit 5d3322eb authored by plach's avatar plach

Issue #2554235 by amateescu, plach, Berdir, Sam152, joelpittet, mbaynton,...

Issue #2554235 by amateescu, plach, Berdir, Sam152, joelpittet, mbaynton, catch, jibran: Make the content entity storage and entity query use the last installed definitions instead of the ones living in code
parent 0b47db51
...@@ -552,7 +552,7 @@ services: ...@@ -552,7 +552,7 @@ services:
class: Drupal\Core\Cache\MemoryCache\MemoryCache class: Drupal\Core\Cache\MemoryCache\MemoryCache
entity_type.manager: entity_type.manager:
class: Drupal\Core\Entity\EntityTypeManager class: Drupal\Core\Entity\EntityTypeManager
arguments: ['@container.namespaces', '@module_handler', '@cache.discovery', '@string_translation', '@class_resolver'] arguments: ['@container.namespaces', '@module_handler', '@cache.discovery', '@string_translation', '@class_resolver', '@entity.last_installed_schema.repository']
parent: container.trait parent: container.trait
tags: tags:
- { name: plugin_manager_cache_clear } - { name: plugin_manager_cache_clear }
......
...@@ -985,7 +985,7 @@ protected function populateAffectedRevisionTranslations(ContentEntityInterface $ ...@@ -985,7 +985,7 @@ protected function populateAffectedRevisionTranslations(ContentEntityInterface $
* The sanitized list of entity key values. * The sanitized list of entity key values.
*/ */
protected function cleanIds(array $ids, $entity_key = 'id') { protected function cleanIds(array $ids, $entity_key = 'id') {
$definitions = $this->entityFieldManager->getBaseFieldDefinitions($this->entityTypeId); $definitions = $this->entityFieldManager->getActiveFieldStorageDefinitions($this->entityTypeId);
$field_name = $this->entityType->getKey($entity_key); $field_name = $this->entityType->getKey($entity_key);
if ($field_name && $definitions[$field_name]->getType() == 'integer') { if ($field_name && $definitions[$field_name]->getType() == 'integer') {
$ids = array_filter($ids, function ($id) { $ids = array_filter($ids, function ($id) {
......
...@@ -227,6 +227,7 @@ public function updateFieldableEntityType(EntityTypeInterface $entity_type, arra ...@@ -227,6 +227,7 @@ public function updateFieldableEntityType(EntityTypeInterface $entity_type, arra
$original_field_storage_definitions = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entity_type->id()); $original_field_storage_definitions = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entity_type->id());
$this->entityTypeListener->onFieldableEntityTypeUpdate($entity_type, $original, $field_storage_definitions, $original_field_storage_definitions, $sandbox); $this->entityTypeListener->onFieldableEntityTypeUpdate($entity_type, $original, $field_storage_definitions, $original_field_storage_definitions, $sandbox);
$this->clearCachedDefinitions();
} }
/** /**
......
...@@ -55,6 +55,13 @@ class EntityFieldManager implements EntityFieldManagerInterface { ...@@ -55,6 +55,13 @@ class EntityFieldManager implements EntityFieldManagerInterface {
*/ */
protected $fieldStorageDefinitions; protected $fieldStorageDefinitions;
/**
* Static cache of active field storage definitions per entity type.
*
* @var array
*/
protected $activeFieldStorageDefinitions;
/** /**
* An array keyed by entity type. Each value is an array whose keys are * An array keyed by entity type. Each value is an array whose keys are
* field names and whose value is an array with two entries: * field names and whose value is an array with two entries:
...@@ -445,6 +452,25 @@ public function getFieldStorageDefinitions($entity_type_id) { ...@@ -445,6 +452,25 @@ public function getFieldStorageDefinitions($entity_type_id) {
return $this->fieldStorageDefinitions[$entity_type_id]; return $this->fieldStorageDefinitions[$entity_type_id];
} }
/**
* Gets the active field storage definitions for a content entity type.
*
* @param string $entity_type_id
* The entity type ID. Only content entities are supported.
*
* @return \Drupal\Core\Field\FieldStorageDefinitionInterface[]
* An array of field storage definitions that are active in the current
* request, keyed by field name.
*
* @internal
*/
public function getActiveFieldStorageDefinitions($entity_type_id) {
if (!isset($this->activeFieldStorageDefinitions[$entity_type_id])) {
$this->activeFieldStorageDefinitions[$entity_type_id] = $this->keyValueFactory->get('entity.definitions.installed')->get($entity_type_id . '.field_storage_definitions', []);
}
return $this->activeFieldStorageDefinitions[$entity_type_id] ?: $this->getFieldStorageDefinitions($entity_type_id);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -569,6 +595,7 @@ public function clearCachedFieldDefinitions() { ...@@ -569,6 +595,7 @@ public function clearCachedFieldDefinitions() {
$this->baseFieldDefinitions = []; $this->baseFieldDefinitions = [];
$this->fieldDefinitions = []; $this->fieldDefinitions = [];
$this->fieldStorageDefinitions = []; $this->fieldStorageDefinitions = [];
$this->activeFieldStorageDefinitions = [];
$this->fieldMap = []; $this->fieldMap = [];
$this->fieldMapByFieldType = []; $this->fieldMapByFieldType = [];
$this->entityDisplayRepository->clearDisplayModeInfo(); $this->entityDisplayRepository->clearDisplayModeInfo();
...@@ -588,6 +615,7 @@ public function useCaches($use_caches = FALSE) { ...@@ -588,6 +615,7 @@ public function useCaches($use_caches = FALSE) {
$this->fieldDefinitions = []; $this->fieldDefinitions = [];
$this->baseFieldDefinitions = []; $this->baseFieldDefinitions = [];
$this->fieldStorageDefinitions = []; $this->fieldStorageDefinitions = [];
$this->activeFieldStorageDefinitions = [];
} }
} }
......
...@@ -209,6 +209,20 @@ public function getFieldStorageDefinitions($entity_type_id) { ...@@ -209,6 +209,20 @@ public function getFieldStorageDefinitions($entity_type_id) {
return $this->container->get('entity_field.manager')->getFieldStorageDefinitions($entity_type_id); return $this->container->get('entity_field.manager')->getFieldStorageDefinitions($entity_type_id);
} }
/**
* {@inheritdoc}
*
* @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\Entity\EntityFieldManagerInterface::getActiveFieldStorageDefinitions()
* instead.
*
* @see https://www.drupal.org/node/3040966
*/
public function getActiveFieldStorageDefinitions($entity_type_id) {
@trigger_error('EntityManagerInterface::getActiveFieldStorageDefinitions() is deprecated in 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\Entity\EntityFieldManagerInterface::getActiveFieldStorageDefinitions() instead. See https://www.drupal.org/node/3040966.', E_USER_DEPRECATED);
return $this->container->get('entity_field.manager')->getActiveFieldStorageDefinitions($entity_type_id);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
* *
...@@ -795,6 +809,20 @@ public function hasDefinition($plugin_id) { ...@@ -795,6 +809,20 @@ public function hasDefinition($plugin_id) {
return $this->container->get('entity_type.manager')->hasDefinition($plugin_id); return $this->container->get('entity_type.manager')->hasDefinition($plugin_id);
} }
/**
* {@inheritdoc}
*
* @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.
* Use \Drupal\Core\Entity\EntityTypeManagerInterface::getActiveDefinition()
* instead.
*
* @see https://www.drupal.org/node/3040966
*/
public function getActiveDefinition($entity_type_id) {
@trigger_error('EntityManagerInterface::getActiveDefinition() is deprecated in 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\Entity\EntityTypeManagerInterface::getActiveDefinition() instead. See https://www.drupal.org/node/3040966.', E_USER_DEPRECATED);
return $this->container->get('entity_type.manager')->getActiveDefinition($entity_type_id);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
* *
......
...@@ -58,6 +58,20 @@ class EntityTypeManager extends DefaultPluginManager implements EntityTypeManage ...@@ -58,6 +58,20 @@ class EntityTypeManager extends DefaultPluginManager implements EntityTypeManage
*/ */
protected $classResolver; protected $classResolver;
/**
* The entity last installed schema repository.
*
* @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface
*/
protected $entityLastInstalledSchemaRepository;
/**
* A list of entity type definitions that are active for the current request.
*
* @var \Drupal\Core\Entity\EntityTypeInterface[]
*/
protected $activeDefinitions;
/** /**
* Constructs a new Entity plugin manager. * Constructs a new Entity plugin manager.
* *
...@@ -72,8 +86,10 @@ class EntityTypeManager extends DefaultPluginManager implements EntityTypeManage ...@@ -72,8 +86,10 @@ class EntityTypeManager extends DefaultPluginManager implements EntityTypeManage
* The string translation. * The string translation.
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
* The class resolver. * The class resolver.
* @param \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_repository
* The entity last installed schema repository.
*/ */
public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, TranslationInterface $string_translation, ClassResolverInterface $class_resolver) { public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, TranslationInterface $string_translation, ClassResolverInterface $class_resolver, EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_repository) {
parent::__construct('Entity', $namespaces, $module_handler, 'Drupal\Core\Entity\EntityInterface'); parent::__construct('Entity', $namespaces, $module_handler, 'Drupal\Core\Entity\EntityInterface');
$this->setCacheBackend($cache, 'entity_type', ['entity_types']); $this->setCacheBackend($cache, 'entity_type', ['entity_types']);
...@@ -82,6 +98,7 @@ public function __construct(\Traversable $namespaces, ModuleHandlerInterface $mo ...@@ -82,6 +98,7 @@ public function __construct(\Traversable $namespaces, ModuleHandlerInterface $mo
$this->discovery = new AnnotatedClassDiscovery('Entity', $namespaces, 'Drupal\Core\Entity\Annotation\EntityType'); $this->discovery = new AnnotatedClassDiscovery('Entity', $namespaces, 'Drupal\Core\Entity\Annotation\EntityType');
$this->stringTranslation = $string_translation; $this->stringTranslation = $string_translation;
$this->classResolver = $class_resolver; $this->classResolver = $class_resolver;
$this->entityLastInstalledSchemaRepository = $entity_last_installed_schema_repository;
} }
/** /**
...@@ -133,11 +150,31 @@ public function getDefinition($entity_type_id, $exception_on_invalid = TRUE) { ...@@ -133,11 +150,31 @@ public function getDefinition($entity_type_id, $exception_on_invalid = TRUE) {
throw new PluginNotFoundException($entity_type_id, sprintf('The "%s" entity type does not exist.', $entity_type_id)); throw new PluginNotFoundException($entity_type_id, sprintf('The "%s" entity type does not exist.', $entity_type_id));
} }
/**
* Gets the active definition for a content entity type.
*
* @param string $entity_type_id
* The entity type ID.
*
* @return \Drupal\Core\Entity\EntityTypeInterface
* The active entity type definition.
*
* @internal
*/
public function getActiveDefinition($entity_type_id) {
if (!isset($this->activeDefinitions[$entity_type_id])) {
$this->activeDefinitions[$entity_type_id] = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id);
}
return $this->activeDefinitions[$entity_type_id] ?: $this->getDefinition($entity_type_id);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function clearCachedDefinitions() { public function clearCachedDefinitions() {
parent::clearCachedDefinitions(); parent::clearCachedDefinitions();
$this->activeDefinitions = [];
$this->handlers = []; $this->handlers = [];
} }
...@@ -147,6 +184,7 @@ public function clearCachedDefinitions() { ...@@ -147,6 +184,7 @@ public function clearCachedDefinitions() {
public function useCaches($use_caches = FALSE) { public function useCaches($use_caches = FALSE) {
parent::useCaches($use_caches); parent::useCaches($use_caches);
if (!$use_caches) { if (!$use_caches) {
$this->activeDefinitions = [];
$this->handlers = []; $this->handlers = [];
$this->container->get('entity.memory_cache')->reset(); $this->container->get('entity.memory_cache')->reset();
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace Drupal\Core\Entity\Query\Sql; namespace Drupal\Core\Entity\Query\Sql;
use Drupal\Core\Database\Query\SelectInterface; use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
use Drupal\Core\Entity\EntityType; use Drupal\Core\Entity\EntityType;
use Drupal\Core\Entity\Query\QueryException; use Drupal\Core\Entity\Query\QueryException;
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface; use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
...@@ -16,6 +17,13 @@ ...@@ -16,6 +17,13 @@
*/ */
class Tables implements TablesInterface { class Tables implements TablesInterface {
use DeprecatedServicePropertyTrait;
/**
* {@inheritdoc}
*/
protected $deprecatedProperties = ['entityManager' => 'entity.manager'];
/** /**
* @var \Drupal\Core\Database\Query\SelectInterface * @var \Drupal\Core\Database\Query\SelectInterface
*/ */
...@@ -44,11 +52,18 @@ class Tables implements TablesInterface { ...@@ -44,11 +52,18 @@ class Tables implements TablesInterface {
protected $fieldTables = []; protected $fieldTables = [];
/** /**
* The entity manager. * The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The entity field manager.
* *
* @var \Drupal\Core\Entity\EntityManager * @var \Drupal\Core\Entity\EntityFieldManagerInterface
*/ */
protected $entityManager; protected $entityFieldManager;
/** /**
* List of case sensitive fields. * List of case sensitive fields.
...@@ -62,7 +77,8 @@ class Tables implements TablesInterface { ...@@ -62,7 +77,8 @@ class Tables implements TablesInterface {
*/ */
public function __construct(SelectInterface $sql_query) { public function __construct(SelectInterface $sql_query) {
$this->sqlQuery = $sql_query; $this->sqlQuery = $sql_query;
$this->entityManager = \Drupal::entityManager(); $this->entityTypeManager = \Drupal::entityTypeManager();
$this->entityFieldManager = \Drupal::service('entity_field.manager');
} }
/** /**
...@@ -85,9 +101,9 @@ public function addField($field, $type, $langcode) { ...@@ -85,9 +101,9 @@ public function addField($field, $type, $langcode) {
// This will contain the definitions of the last specifier seen by the // This will contain the definitions of the last specifier seen by the
// system. // system.
$propertyDefinitions = []; $propertyDefinitions = [];
$entity_type = $this->entityManager->getDefinition($entity_type_id); $entity_type = $this->entityTypeManager->getActiveDefinition($entity_type_id);
$field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); $field_storage_definitions = $this->entityFieldManager->getActiveFieldStorageDefinitions($entity_type_id);
for ($key = 0; $key <= $count; $key++) { for ($key = 0; $key <= $count; $key++) {
// This can either be the name of an entity base field or a configurable // This can either be the name of an entity base field or a configurable
// field. // field.
...@@ -118,7 +134,7 @@ public function addField($field, $type, $langcode) { ...@@ -118,7 +134,7 @@ public function addField($field, $type, $langcode) {
} }
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */ /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $this->entityManager->getStorage($entity_type_id)->getTableMapping(); $table_mapping = $this->entityTypeManager->getStorage($entity_type_id)->getTableMapping();
// Check whether this field is stored in a dedicated table. // Check whether this field is stored in a dedicated table.
if ($field_storage && $table_mapping->requiresDedicatedTableStorage($field_storage)) { if ($field_storage && $table_mapping->requiresDedicatedTableStorage($field_storage)) {
...@@ -277,8 +293,8 @@ public function addField($field, $type, $langcode) { ...@@ -277,8 +293,8 @@ public function addField($field, $type, $langcode) {
if (!$entity_type_id && $target_definition instanceof EntityDataDefinitionInterface) { if (!$entity_type_id && $target_definition instanceof EntityDataDefinitionInterface) {
$entity_type_id = $target_definition->getEntityTypeId(); $entity_type_id = $target_definition->getEntityTypeId();
} }
$entity_type = $this->entityManager->getDefinition($entity_type_id); $entity_type = $this->entityTypeManager->getActiveDefinition($entity_type_id);
$field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); $field_storage_definitions = $this->entityFieldManager->getActiveFieldStorageDefinitions($entity_type_id);
// Add the new entity base table using the table and sql column. // Add the new entity base table using the table and sql column.
$base_table = $this->addNextBaseTable($entity_type, $table, $sql_column, $field_storage); $base_table = $this->addNextBaseTable($entity_type, $table, $sql_column, $field_storage);
$propertyDefinitions = []; $propertyDefinitions = [];
...@@ -364,7 +380,7 @@ protected function ensureFieldTable($index_prefix, &$field, $type, $langcode, $b ...@@ -364,7 +380,7 @@ protected function ensureFieldTable($index_prefix, &$field, $type, $langcode, $b
if (!isset($this->fieldTables[$index_prefix . $field_name])) { if (!isset($this->fieldTables[$index_prefix . $field_name])) {
$entity_type_id = $this->sqlQuery->getMetaData('entity_type'); $entity_type_id = $this->sqlQuery->getMetaData('entity_type');
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */ /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $this->entityManager->getStorage($entity_type_id)->getTableMapping(); $table_mapping = $this->entityTypeManager->getStorage($entity_type_id)->getTableMapping();
$table = !$this->sqlQuery->getMetaData('all_revisions') ? $table_mapping->getDedicatedDataTableName($field) : $table_mapping->getDedicatedRevisionTableName($field); $table = !$this->sqlQuery->getMetaData('all_revisions') ? $table_mapping->getDedicatedDataTableName($field) : $table_mapping->getDedicatedRevisionTableName($field);
if ($field->getCardinality() != 1) { if ($field->getCardinality() != 1) {
$this->sqlQuery->addMetaData('simple_query', FALSE); $this->sqlQuery->addMetaData('simple_query', FALSE);
...@@ -395,7 +411,7 @@ protected function addJoin($type, $table, $join_condition, $langcode, $delta = N ...@@ -395,7 +411,7 @@ protected function addJoin($type, $table, $join_condition, $langcode, $delta = N
$arguments = []; $arguments = [];
if ($langcode) { if ($langcode) {
$entity_type_id = $this->sqlQuery->getMetaData('entity_type'); $entity_type_id = $this->sqlQuery->getMetaData('entity_type');
$entity_type = $this->entityManager->getDefinition($entity_type_id); $entity_type = $this->entityTypeManager->getActiveDefinition($entity_type_id);
// Only the data table follows the entity language key, dedicated field // Only the data table follows the entity language key, dedicated field
// tables have an hard-coded 'langcode' column. // tables have an hard-coded 'langcode' column.
$langcode_key = $entity_type->getDataTable() == $table ? $entity_type->getKey('langcode') : 'langcode'; $langcode_key = $entity_type->getDataTable() == $table ? $entity_type->getKey('langcode') : 'langcode';
...@@ -423,7 +439,7 @@ protected function addJoin($type, $table, $join_condition, $langcode, $delta = N ...@@ -423,7 +439,7 @@ protected function addJoin($type, $table, $join_condition, $langcode, $delta = N
* mapping is not available, FALSE is returned. * mapping is not available, FALSE is returned.
*/ */
protected function getTableMapping($table, $entity_type_id) { protected function getTableMapping($table, $entity_type_id) {
$storage = $this->entityManager->getStorage($entity_type_id); $storage = $this->entityTypeManager->getStorage($entity_type_id);
if ($storage instanceof SqlEntityStorageInterface) { if ($storage instanceof SqlEntityStorageInterface) {
$mapping = $storage->getTableMapping()->getAllColumns($table); $mapping = $storage->getTableMapping()->getAllColumns($table);
} }
......
...@@ -58,15 +58,12 @@ public function onFieldableEntityTypeUpdate(EntityTypeInterface $entity_type, En ...@@ -58,15 +58,12 @@ public function onFieldableEntityTypeUpdate(EntityTypeInterface $entity_type, En
throw new EntityStorageException('Missing revision_translation_affected field.'); throw new EntityStorageException('Missing revision_translation_affected field.');
} }
$sandbox['original_storage'] = $original_storage;
$sandbox['temporary_storage'] = $this->entityTypeManager->createHandlerInstance($entity_type->getStorageClass(), $entity_type);
$this->preUpdateEntityTypeSchema($entity_type, $original, $field_storage_definitions, $original_field_storage_definitions, $sandbox); $this->preUpdateEntityTypeSchema($entity_type, $original, $field_storage_definitions, $original_field_storage_definitions, $sandbox);
} }
// Copy data from the original storage to the temporary one. // Copy data from the original storage to the temporary one.
if ($has_data) { if ($has_data) {
$this->copyData($entity_type, $original, $sandbox); $this->copyData($entity_type, $original, $field_storage_definitions, $original_field_storage_definitions, $sandbox);
} }
else { else {
// If there is no existing data, we still need to run the // If there is no existing data, we still need to run the
...@@ -127,10 +124,14 @@ protected function postUpdateEntityTypeSchema(EntityTypeInterface $entity_type, ...@@ -127,10 +124,14 @@ protected function postUpdateEntityTypeSchema(EntityTypeInterface $entity_type,
* The updated entity type definition. * The updated entity type definition.
* @param \Drupal\Core\Entity\EntityTypeInterface $original * @param \Drupal\Core\Entity\EntityTypeInterface $original
* The original entity type definition. * The original entity type definition.
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $field_storage_definitions
* The updated field storage definitions, including possibly new ones.
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface[] $original_field_storage_definitions
* The original field storage definitions.
* @param array &$sandbox * @param array &$sandbox
* The sandbox array from a hook_update_N() implementation. * The sandbox array from a hook_update_N() implementation.
*/ */
protected function copyData(EntityTypeInterface $entity_type, EntityTypeInterface $original, array &$sandbox) { protected function copyData(EntityTypeInterface $entity_type, EntityTypeInterface $original, array $field_storage_definitions, array $original_field_storage_definitions, array &$sandbox) {
/** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */ /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */
$id_key = $entity_type->getKey('id'); $id_key = $entity_type->getKey('id');
$revision_id_key = $entity_type->getKey('revision'); $revision_id_key = $entity_type->getKey('revision');
...@@ -139,9 +140,6 @@ protected function copyData(EntityTypeInterface $entity_type, EntityTypeInterfac ...@@ -139,9 +140,6 @@ protected function copyData(EntityTypeInterface $entity_type, EntityTypeInterfac
$default_langcode_key = $entity_type->getKey('default_langcode'); $default_langcode_key = $entity_type->getKey('default_langcode');
$revision_translation_affected_key = $entity_type->getKey('revision_translation_affected'); $revision_translation_affected_key = $entity_type->getKey('revision_translation_affected');
$temporary_storage = $sandbox['temporary_storage'];
$original_storage = $sandbox['original_storage'];
// If 'progress' is not set, then this will be the first run of the batch. // If 'progress' is not set, then this will be the first run of the batch.
if (!isset($sandbox['progress'])) { if (!isset($sandbox['progress'])) {
$sandbox['progress'] = 0; $sandbox['progress'] = 0;
...@@ -174,7 +172,13 @@ protected function copyData(EntityTypeInterface $entity_type, EntityTypeInterfac ...@@ -174,7 +172,13 @@ protected function copyData(EntityTypeInterface $entity_type, EntityTypeInterfac
->fetchCol(); ->fetchCol();
/** @var \Drupal\Core\Entity\ContentEntityInterface[] $entities */ /** @var \Drupal\Core\Entity\ContentEntityInterface[] $entities */
$entities = $load_revisions ? $original_storage->loadMultipleRevisions($entity_identifiers) : $original_storage->loadMultiple($entity_identifiers); $entities = $load_revisions ? $this->storage->loadMultipleRevisions($entity_identifiers) : $this->storage->loadMultiple($entity_identifiers);
$temporary_storage = $this->entityTypeManager->createHandlerInstance($entity_type->getStorageClass(), $entity_type);
$temporary_storage->setEntityType($entity_type);
$temporary_storage->setFieldStorageDefinitions($field_storage_definitions);
$temporary_storage->setTableMapping($sandbox['temporary_table_mapping']);
foreach ($entities as $identifier => $entity) { foreach ($entities as $identifier => $entity) {
try { try {
if (!$original->isRevisionable() && $entity_type->isRevisionable()) { if (!$original->isRevisionable() && $entity_type->isRevisionable()) {
......
...@@ -2,12 +2,10 @@ ...@@ -2,12 +2,10 @@
namespace Drupal\Core\Field; namespace Drupal\Core\Field;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface; use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityStorageInterface; use Drupal\Core\Entity\FieldableEntityStorageInterface;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/** /**
...@@ -82,17 +80,7 @@ public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $ ...@@ -82,17 +80,7 @@ public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $
// @todo Forward this to all interested handlers, not only storage, once // @todo Forward this to all interested handlers, not only storage, once
// iterating handlers is possible: https://www.drupal.org/node/2332857. // iterating handlers is possible: https://www.drupal.org/node/2332857.
$storage = clone $this->entityTypeManager->getStorage($entity_type_id); $storage = $this->entityTypeManager->getStorage($entity_type_id);
// Entity type definition updates can change the schema by adding or
// removing entity tables (for example when switching an entity type from
// non-revisionable to revisionable), so CRUD operations on a field storage
// definition need to use the last installed entity type schema.
if ($storage instanceof SqlContentEntityStorage
&& ($last_installed_entity_type = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id))) {
$storage->setEntityType($last_installed_entity_type);
}
if ($storage instanceof FieldStorageDefinitionListenerInterface) { if ($storage instanceof FieldStorageDefinitionListenerInterface) {
$storage->onFieldStorageDefinitionCreate($storage_definition); $storage->onFieldStorageDefinitionCreate($storage_definition);
} }
...@@ -111,17 +99,7 @@ public function onFieldStorageDefinitionUpdate(FieldStorageDefinitionInterface $ ...@@ -111,17 +99,7 @@ public function onFieldStorageDefinitionUpdate(FieldStorageDefinitionInterface $
// @todo Forward this to all interested handlers, not only storage, once // @todo Forward this to all interested handlers, not only storage, once
// iterating handlers is possible: https://www.drupal.org/node/2332857. // iterating handlers is possible: https://www.drupal.org/node/2332857.
$storage = clone $this->entityTypeManager->getStorage($entity_type_id); $storage = $this->entityTypeManager->getStorage($entity_type_id);
// Entity type definition updates can change the schema by adding or
// removing entity tables (for example when switching an entity type from
// non-revisionable to revisionable), so CRUD operations on a field storage
// definition need to use the last installed entity type schema.
if ($storage instanceof SqlContentEntityStorage
&& ($last_installed_entity_type = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id))) {
$storage->setEntityType($last_installed_entity_type);
}
if ($storage instanceof FieldStorageDefinitionListenerInterface) { if ($storage instanceof FieldStorageDefinitionListenerInterface) {
$storage->onFieldStorageDefinitionUpdate($storage_definition, $original); $storage->onFieldStorageDefinitionUpdate($storage_definition, $original);
} }
...@@ -140,32 +118,15 @@ public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $ ...@@ -140,32 +118,15 @@ public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $
// @todo Forward this to all interested handlers, not only storage, once // @todo Forward this to all interested handlers, not only storage, once
// iterating handlers is possible: https://www.drupal.org/node/2332857. // iterating handlers is possible: https://www.drupal.org/node/2332857.
$storage = clone $this->entityTypeManager->getStorage($entity_type_id); $storage = $this->entityTypeManager->getStorage($entity_type_id);
// Entity type definition updates can change the schema by adding or
// removing entity tables (for example when switching an entity type from
// non-revisionable to revisionable), so CRUD operations on a field storage
// definition need to use the last installed entity type schema.
if ($storage instanceof SqlContentEntityStorage
&& ($last_installed_entity_type = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id))) {
$storage->setEntityType($last_installed_entity_type);
}
// Keep the field definition in the deleted fields repository so we can use // Keep the field definition in the deleted fields repository so we can use
// it later during field_purge_batch(), but only if the field has data. // it later during field_purge_batch(), but only if the field has data.
try { if ($storage_definition instanceof BaseFieldDefinition && $storage instanceof FieldableEntityStorageInterface && $storage->countFieldData($storage_definition, TRUE)) {
if ($storage_definition instanceof BaseFieldDefinition && $storage instanceof FieldableEntityStorageInterface && $storage->countFieldData($storage_definition, TRUE)) { $deleted_storage_definition = clone $storage_definition;
$deleted_storage_definition = clone $storage_definition; $deleted_storage_definition->setDeleted(TRUE);
$deleted_storage_definition->setDeleted(TRUE); $this->deletedFieldsRepository->addFieldDefinition($deleted_storage_definition);
$this->deletedFieldsRepository->addFieldDefinition($deleted_storage_definition); $this->deletedFieldsRepository->addFieldStorageDefinition($deleted_storage_definition);
$this->deletedFieldsRepository->addFieldStorageDefinition($deleted_storage_definition);
}
}
catch (DatabaseExceptionWrapper $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.
} }
if ($storage instanceof FieldStorageDefinitionListenerInterface) { if ($storage instanceof FieldStorageDefinitionListenerInterface) {
......
...@@ -531,7 +531,7 @@ public function testNonLangcodeEntityTypeModeration() { ...@@ -531,7 +531,7 @@ public function testNonLangcodeEntityTypeModeration() {
\Drupal::state()->set('entity_test_rev.entity_type', $entity_type); \Drupal::state()->set('entity_test_rev.entity_type', $entity_type);
// Update the entity type in order to remove the 'langcode' field. // Update the entity type in order to remove the 'langcode' field.
$this->applyEntityUpdates('entity_test_rev'); \Drupal::entityDefinitionUpdateManager()->updateFieldableEntityType($entity_type, \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($entity_type->id()));
$workflow = $this->createEditorialWorkflow(); $workflow = $this->createEditorialWorkflow();
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev'); $workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
......
...@@ -97,7 +97,7 @@ protected function addJoin($type, $table, $join_condition, $langcode, $delta = N ...@@ -97,7 +97,7 @@ protected function addJoin($type, $table, $join_condition, $langcode, $delta = N
if (isset($this->baseTablesEntityType[$base_table])) { if (isset($this->baseTablesEntityType[$base_table])) {
$entity_type_id = $this->baseTablesEntityType[$base_table]; $entity_type_id = $this->baseTablesEntityType[$base_table];
$revision_key = $this->entityManager->getDefinition($entity_type_id)->getKey('revision'); $revision_key = $this->entityTypeManager->getActiveDefinition($entity_type_id)->getKey('revision');
if ($id_field === $revision_key || $id_field === 'revision_id') { if ($id_field === $revision_key || $id_field === 'revision_id') {
$workspace_association_table = $this->contentWorkspaceTables[$base_table]; $workspace_association_table = $this->contentWorkspaceTables[$base_table];
...@@ -141,7 +141,7 @@ protected function addNextBaseTable(EntityType $entity_type, $table, $sql_column ...@@ -141,7 +141,7 @@ protected function addNextBaseTable(EntityType $entity_type, $table, $sql_column
*/ */
public function addWorkspaceAssociationJoin($entity_type_id, $base_table_alias, $active_workspace_id) { public function addWorkspaceAssociationJoin($entity_type_id, $base_table_alias, $active_workspace_id) {
if (!isset($this->contentWorkspaceTables[$base_table_alias])) { if (!isset($this->contentWorkspaceTables[$base_table_alias])) {
$entity_type = $this->entityManager->getDefinition($entity_type_id); $entity_type = $this->entityTypeManager->getActiveDefinition($entity_type_id);
$id_field = $entity_type->getKey('id'); $id_field = $entity_type->getKey('id');
// LEFT join the Workspace association entity's table so we can properly // LEFT join the Workspace association entity's table so we can properly
......
...@@ -4,14 +4,14 @@ ...@@ -4,14 +4,14 @@
use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface; use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityFieldManager;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface; use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface;
use Drupal\Core\Entity\EntityManager; use Drupal\Core\Entity\EntityManager;
use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityType; use Drupal\Core\Entity\EntityType;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\EntityTypeRepositoryInterface;