diff --git a/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.php b/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.php index 35b02ed05f..d8ef2a2297 100644 --- a/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.php +++ b/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.php @@ -172,33 +172,7 @@ public function getChangeSummary() { * {@inheritdoc} */ public function applyUpdates() { - $complete_change_list = $this->getChangeList(); - if ($complete_change_list) { - // self::getChangeList() only disables the cache and does not invalidate. - // In case there are changes, explicitly invalidate caches. - $this->clearCachedDefinitions(); - } - foreach ($complete_change_list as $entity_type_id => $change_list) { - // Process entity type definition changes before storage definitions ones - // this is necessary when you change an entity type from non-revisionable - // to revisionable and at the same time add revisionable fields to the - // entity type. - if (!empty($change_list['entity_type'])) { - $this->doEntityUpdate($change_list['entity_type'], $entity_type_id); - } - - // Process field storage definition changes. - if (!empty($change_list['field_storage_definitions'])) { - $storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type_id); - $original_storage_definitions = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entity_type_id); - - foreach ($change_list['field_storage_definitions'] as $field_name => $change) { - $storage_definition = isset($storage_definitions[$field_name]) ? $storage_definitions[$field_name] : NULL; - $original_storage_definition = isset($original_storage_definitions[$field_name]) ? $original_storage_definitions[$field_name] : NULL; - $this->doFieldUpdate($change, $storage_definition, $original_storage_definition); - } - } - } + @trigger_error('EntityDefinitionUpdateManagerInterface::applyUpdates() is deprecated in 8.7.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface::getChangeList() and execute each entity type and field storage update manually instead. See https://www.drupal.org/node/3034742.', E_USER_DEPRECATED); } /** @@ -298,69 +272,9 @@ public function uninstallFieldStorageDefinition(FieldStorageDefinitionInterface } /** - * Performs an entity type definition update. - * - * @param string $op - * The operation to perform, either static::DEFINITION_CREATED or - * static::DEFINITION_UPDATED. - * @param string $entity_type_id - * The entity type ID. - */ - protected function doEntityUpdate($op, $entity_type_id) { - $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); - switch ($op) { - case static::DEFINITION_CREATED: - $this->entityTypeListener->onEntityTypeCreate($entity_type); - break; - - case static::DEFINITION_UPDATED: - $original = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id); - $this->entityTypeListener->onEntityTypeUpdate($entity_type, $original); - break; - } - } - - /** - * Performs a field storage definition update. - * - * @param string $op - * The operation to perform, possible values are static::DEFINITION_CREATED, - * static::DEFINITION_UPDATED or static::DEFINITION_DELETED. - * @param array|null $storage_definition - * The new field storage definition. - * @param array|null $original_storage_definition - * The original field storage definition. - */ - protected function doFieldUpdate($op, $storage_definition = NULL, $original_storage_definition = NULL) { - switch ($op) { - case static::DEFINITION_CREATED: - $this->fieldStorageDefinitionListener->onFieldStorageDefinitionCreate($storage_definition); - break; - - case static::DEFINITION_UPDATED: - $this->fieldStorageDefinitionListener->onFieldStorageDefinitionUpdate($storage_definition, $original_storage_definition); - break; - - case static::DEFINITION_DELETED: - $this->fieldStorageDefinitionListener->onFieldStorageDefinitionDelete($original_storage_definition); - break; - } - } - - /** - * Gets a list of changes to entity type and field storage definitions. - * - * @return array - * An associative array keyed by entity type id of change descriptors. Every - * entry is an associative array with the following optional keys: - * - entity_type: a scalar having only the DEFINITION_UPDATED value. - * - field_storage_definitions: an associative array keyed by field name of - * scalars having one value among: - * - DEFINITION_CREATED - * - DEFINITION_UPDATED - * - DEFINITION_DELETED + * {@inheritdoc} */ - protected function getChangeList() { + public function getChangeList() { $this->entityTypeManager->useCaches(FALSE); $this->entityFieldManager->useCaches(FALSE); $change_list = []; diff --git a/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManagerInterface.php b/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManagerInterface.php index 02cbe2cf13..5d5f49f6e2 100644 --- a/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManagerInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManagerInterface.php @@ -79,6 +79,21 @@ public function needsUpdates(); */ public function getChangeSummary(); + /** + * Gets a list of changes to entity type and field storage definitions. + * + * @return array + * An associative array keyed by entity type id of change descriptors. Every + * entry is an associative array with the following optional keys: + * - entity_type: a scalar having only the DEFINITION_UPDATED value. + * - field_storage_definitions: an associative array keyed by field name of + * scalars having one value among: + * - DEFINITION_CREATED + * - DEFINITION_UPDATED + * - DEFINITION_DELETED + */ + public function getChangeList(); + /** * Applies all the detected valid changes. * @@ -90,6 +105,12 @@ public function getChangeSummary(); * unacceptable data loss. In such a case, the site administrator needs to * apply some other process, such as a custom update function or a * migration via the Migrate module. + * + * @deprecated in Drupal 8.7.0, will be removed before Drupal 9.0.0. Use + * \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface::getChangeList() + * and execute each entity type and field storage update manually instead. + * + * @see https://www.drupal.org/node/3034742 */ public function applyUpdates(); diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php index ce403352b1..3eed824de6 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php @@ -313,12 +313,6 @@ protected function getSchemaFromStorageDefinition(FieldStorageDefinitionInterfac * {@inheritdoc} */ public function requiresEntityDataMigration(EntityTypeInterface $entity_type, EntityTypeInterface $original) { - // Check if the entity type specifies that data migration is being handled - // elsewhere. - if ($entity_type->get('requires_data_migration') === FALSE) { - return FALSE; - } - // If the original storage has existing entities, or it is impossible to // determine if that is the case, require entity data to be migrated. $original_storage_class = $original->getStorageClass(); @@ -388,16 +382,14 @@ public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeI $this->checkEntityType($entity_type); $this->checkEntityType($original); - $this->entityType = $entity_type; - // If no schema changes are needed, we don't need to do anything. if (!$this->requiresEntityStorageSchemaChanges($entity_type, $original)) { return; } - // If a migration is required, we can't proceed. - if ($this->requiresEntityDataMigration($entity_type, $original)) { - throw new EntityStorageException('The SQL storage cannot change the schema for an existing entity type (' . $entity_type->id() . ') with data.'); + // If shared table schema changes are needed, we can't proceed. + if ($this->hasSharedTableStructureChange($entity_type, $original)) { + throw new EntityStorageException("The SQL storage cannot change the schema for an existing entity type: {$entity_type->id()}."); } // Drop original indexes and unique keys. diff --git a/core/modules/system/src/Tests/Entity/EntityDefinitionTestTrait.php b/core/modules/system/src/Tests/Entity/EntityDefinitionTestTrait.php index 0817aa7981..4822762105 100644 --- a/core/modules/system/src/Tests/Entity/EntityDefinitionTestTrait.php +++ b/core/modules/system/src/Tests/Entity/EntityDefinitionTestTrait.php @@ -23,7 +23,7 @@ protected function enableNewEntityType() { $this->state->set('entity_test_new', TRUE); $this->entityManager->clearCachedDefinitions(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); } /** @@ -32,7 +32,7 @@ protected function enableNewEntityType() { protected function resetEntityType() { $this->state->set('entity_test_update.entity_type', NULL); $this->entityManager->clearCachedDefinitions(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); } /** diff --git a/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php b/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php index 73fbf5be60..db37b95cd4 100644 --- a/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php +++ b/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\system\Functional\Entity\Traits; +use Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\entity_test\FieldStorageDefinition; @@ -11,12 +12,122 @@ */ trait EntityDefinitionTestTrait { + /** + * The service container. + * + * @var \Symfony\Component\DependencyInjection\ContainerInterface + */ + protected $container; + + /** + * The state service. + * + * @var \Drupal\Core\State\StateInterface + */ + protected $state; + + /** + * The entity definition update manager. + * + * @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface + */ + protected $entityDefinitionUpdateManager; + + /** + * Applies all the detected valid changes. + * + * Use this with care, as it will apply updates for any module, which will + * lead to unpredictable results. + */ + protected function applyEntityUpdates() { + $complete_change_list = $this->entityDefinitionUpdateManager->getChangeList(); + if ($complete_change_list) { + // In case there are changes, explicitly invalidate caches. + \Drupal::entityTypeManager()->clearCachedDefinitions(); + \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); + } + foreach ($complete_change_list as $entity_type_id => $change_list) { + // Process entity type definition changes before storage definitions ones + // this is necessary when you change an entity type from non-revisionable + // to revisionable and at the same time add revisionable fields to the + // entity type. + if (!empty($change_list['entity_type'])) { + $this->doEntityUpdate($change_list['entity_type'], $entity_type_id); + } + + // Process field storage definition changes. + if (!empty($change_list['field_storage_definitions'])) { + $storage_definitions = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($entity_type_id); + $original_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions($entity_type_id); + + foreach ($change_list['field_storage_definitions'] as $field_name => $change) { + $storage_definition = isset($storage_definitions[$field_name]) ? $storage_definitions[$field_name] : NULL; + $original_storage_definition = isset($original_storage_definitions[$field_name]) ? $original_storage_definitions[$field_name] : NULL; + $this->doFieldUpdate($change, $storage_definition, $original_storage_definition); + } + } + } + } + + /** + * Performs an entity type definition update. + * + * @param string $op + * The operation to perform, either static::DEFINITION_CREATED or + * static::DEFINITION_UPDATED. + * @param string $entity_type_id + * The entity type ID. + */ + protected function doEntityUpdate($op, $entity_type_id) { + $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id); + $field_storage_definitions = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions($entity_type_id); + switch ($op) { + case EntityDefinitionUpdateManagerInterface::DEFINITION_CREATED: + \Drupal::service('entity_type.listener')->onEntityTypeCreate($entity_type); + break; + + case EntityDefinitionUpdateManagerInterface::DEFINITION_UPDATED: + $original = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledDefinition($entity_type_id); + $original_field_storage_definitions = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledFieldStorageDefinitions($entity_type_id); + + \Drupal::service('entity_type.listener')->onFieldableEntityTypeUpdate($entity_type, $original, $field_storage_definitions, $original_field_storage_definitions); + break; + } + } + + /** + * Performs a field storage definition update. + * + * @param string $op + * The operation to perform, possible values are static::DEFINITION_CREATED, + * static::DEFINITION_UPDATED or static::DEFINITION_DELETED. + * @param array|null $storage_definition + * The new field storage definition. + * @param array|null $original_storage_definition + * The original field storage definition. + */ + protected function doFieldUpdate($op, $storage_definition = NULL, $original_storage_definition = NULL) { + switch ($op) { + case EntityDefinitionUpdateManagerInterface::DEFINITION_CREATED: + \Drupal::service('field_storage_definition.listener')->onFieldStorageDefinitionCreate($storage_definition); + break; + + case EntityDefinitionUpdateManagerInterface::DEFINITION_UPDATED: + \Drupal::service('field_storage_definition.listener')->onFieldStorageDefinitionUpdate($storage_definition, $original_storage_definition); + break; + + case EntityDefinitionUpdateManagerInterface::DEFINITION_DELETED: + \Drupal::service('field_storage_definition.listener')->onFieldStorageDefinitionDelete($original_storage_definition); + break; + } + } + /** * Enables a new entity type definition. */ protected function enableNewEntityType() { $this->state->set('entity_test_new', TRUE); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); } /** @@ -376,6 +487,7 @@ protected function getUpdatedEntityTypeDefinition($revisionable = FALSE, $transl * An array of field storage definition objects. */ protected function getUpdatedFieldStorageDefinitions($revisionable = FALSE, $translatable = FALSE) { + /** @var \Drupal\Core\Field\BaseFieldDefinition[] $field_storage_definitions */ $field_storage_definitions = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions('entity_test_update'); if ($revisionable) { diff --git a/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php b/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php index 8ef5ff8495..e17fbcdc89 100644 --- a/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php +++ b/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php @@ -127,7 +127,7 @@ public function testDeleteEntityType() { */ public function testBaseTableRename() { $this->renameBaseTable(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); /** @var \Drupal\views\Entity\View $view */ $entity_storage = $this->entityTypeManager->getStorage('view'); @@ -155,7 +155,7 @@ public function testDataTableRename() { $this->assertEqual('entity_test_update_data', $display['display_options']['fields']['name']['table']); $this->renameDataTable(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); /** @var \Drupal\views\Entity\View $view */ $entity_storage = $this->entityTypeManager->getStorage('view'); @@ -183,7 +183,7 @@ public function testRevisionBaseTableRename() { $this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['name']['table']); $this->renameRevisionBaseTable(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); /** @var \Drupal\views\Entity\View $view */ $entity_storage = $this->entityTypeManager->getStorage('view'); @@ -211,7 +211,7 @@ public function testRevisionDataTableRename() { $this->assertEqual('entity_test_update_revision_data', $display['display_options']['fields']['name']['table']); $this->renameRevisionDataTable(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); /** @var \Drupal\views\Entity\View $view */ $entity_storage = $this->entityTypeManager->getStorage('view'); diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php index b101313200..926ee62e68 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php @@ -15,6 +15,7 @@ use Drupal\Core\Field\FieldStorageDefinitionEvents; use Drupal\Core\Language\LanguageInterface; use Drupal\entity_test_update\Entity\EntityTestUpdate; +use Drupal\Tests\Core\Database\SchemaIntrospectionTestTrait; use Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait; /** @@ -27,6 +28,7 @@ class EntityDefinitionUpdateTest extends EntityKernelTestBase { use EntityDefinitionTestTrait; + use SchemaIntrospectionTestTrait; /** * The entity definition update manager. @@ -91,10 +93,7 @@ public function testNoUpdates() { // Ensure that the definition update manager reports no updates. $this->assertFalse($this->entityDefinitionUpdateManager->needsUpdates(), 'EntityDefinitionUpdateManager reports that no updates are needed.'); $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeSummary(), [], 'EntityDefinitionUpdateManager reports an empty change summary.'); - - // Ensure that applyUpdates() runs without error (it's not expected to do - // anything when there aren't updates). - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->assertIdentical($this->entityDefinitionUpdateManager->getChangeList(), [], 'EntityDefinitionUpdateManager reports an empty change list.'); } /** @@ -125,25 +124,6 @@ public function testEntityTypeUpdateWithoutData() { $this->assertTrue($this->database->schema()->tableExists('entity_test_update_revision'), 'Revision table created for entity_test_update.'); } - /** - * Tests updating entity schema when there are existing entities. - */ - public function testEntityTypeUpdateWithData() { - // Save an entity. - $this->entityManager->getStorage('entity_test_update')->create()->save(); - - // Update the entity type to be revisionable and try to apply the update. - // It's expected to throw an exception. - $this->updateEntityTypeToRevisionable(); - try { - $this->entityDefinitionUpdateManager->applyUpdates(); - $this->fail('EntityStorageException thrown when trying to apply an update that requires data migration.'); - } - catch (EntityStorageException $e) { - $this->pass('EntityStorageException thrown when trying to apply an update that requires data migration.'); - } - } - /** * Tests creating, updating, and deleting a base field if no entities exist. */ @@ -158,7 +138,7 @@ public function testBaseFieldCreateUpdateDeleteWithoutData() { ], ]; $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertTrue($this->database->schema()->fieldExists('entity_test_update', 'new_base_field'), 'Column created in shared table for new_base_field.'); // Add an index on the base field, ensure the update manager reports it, @@ -171,7 +151,7 @@ public function testBaseFieldCreateUpdateDeleteWithoutData() { ], ]; $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertTrue($this->database->schema()->indexExists('entity_test_update', 'entity_test_update_field__new_base_field'), 'Index created.'); // Remove the above index, ensure the update manager reports it, and the @@ -184,7 +164,7 @@ public function testBaseFieldCreateUpdateDeleteWithoutData() { ], ]; $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertFalse($this->database->schema()->indexExists('entity_test_update', 'entity_test_update_field__new_base_field'), 'Index deleted.'); // Update the type of the base field from 'string' to 'text', ensure the @@ -198,7 +178,7 @@ public function testBaseFieldCreateUpdateDeleteWithoutData() { ], ]; $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertFalse($this->database->schema()->fieldExists('entity_test_update', 'new_base_field'), 'Original column deleted in shared table for new_base_field.'); $this->assertTrue($this->database->schema()->fieldExists('entity_test_update', 'new_base_field__value'), 'Value column created in shared table for new_base_field.'); $this->assertTrue($this->database->schema()->fieldExists('entity_test_update', 'new_base_field__format'), 'Format column created in shared table for new_base_field.'); @@ -213,7 +193,7 @@ public function testBaseFieldCreateUpdateDeleteWithoutData() { ], ]; $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertFalse($this->database->schema()->fieldExists('entity_test_update', 'new_base_field_value'), 'Value column deleted from shared table for new_base_field.'); $this->assertFalse($this->database->schema()->fieldExists('entity_test_update', 'new_base_field_format'), 'Format column deleted from shared table for new_base_field.'); } @@ -232,7 +212,7 @@ public function testBundleFieldCreateUpdateDeleteWithoutData() { ], ]; $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertTrue($this->database->schema()->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table created for new_bundle_field.'); // Update the type of the base field from 'string' to 'text', ensure the @@ -246,7 +226,7 @@ public function testBundleFieldCreateUpdateDeleteWithoutData() { ], ]; $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertTrue($this->database->schema()->fieldExists('entity_test_update__new_bundle_field', 'new_bundle_field_format'), 'Format column created in dedicated table for new_base_field.'); // Remove the bundle field, ensure the update manager reports it, and the @@ -259,7 +239,7 @@ public function testBundleFieldCreateUpdateDeleteWithoutData() { ], ]; $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertFalse($this->database->schema()->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table deleted for new_bundle_field.'); } @@ -281,7 +261,7 @@ public function testBaseFieldCreateDeleteWithExistingEntities() { // Add a base field and run the update. Ensure the base field's column is // created and the prior saved entity data is still there. $this->addBaseField(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $schema_handler = $this->database->schema(); $this->assertTrue($schema_handler->fieldExists('entity_test_update', 'new_base_field'), 'Column created in shared table for new_base_field.'); $entity = $this->entityManager->getStorage('entity_test_update')->load($entity->id()); @@ -290,7 +270,7 @@ public function testBaseFieldCreateDeleteWithExistingEntities() { // Remove the base field and run the update. Ensure the base field's column // is deleted and the prior saved entity data is still there. $this->removeBaseField(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertFalse($schema_handler->fieldExists('entity_test_update', 'new_base_field'), 'Column deleted from shared table for new_base_field.'); $entity = $this->entityManager->getStorage('entity_test_update')->load($entity->id()); $this->assertIdentical($entity->name->value, $name, 'Entity data preserved during field deletion.'); @@ -298,7 +278,7 @@ public function testBaseFieldCreateDeleteWithExistingEntities() { // Add a base field with a required property and run the update. Ensure // 'not null' is not applied and thus no exception is thrown. $this->addBaseField('shape_required'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $assert = $schema_handler->fieldExists('entity_test_update', 'new_base_field__shape') && $schema_handler->fieldExists('entity_test_update', 'new_base_field__color'); $this->assertTrue($assert, 'Columns created in shared table for new_base_field.'); @@ -308,11 +288,11 @@ public function testBaseFieldCreateDeleteWithExistingEntities() { // definitions. See https://www.drupal.org/node/2390495. $entity->delete(); $this->removeBaseField(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $assert = !$schema_handler->fieldExists('entity_test_update', 'new_base_field__shape') && !$schema_handler->fieldExists('entity_test_update', 'new_base_field__color'); $this->assert($assert, 'Columns removed from the shared table for new_base_field.'); $this->addBaseField('shape_required'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $assert = $schema_handler->fieldExists('entity_test_update', 'new_base_field__shape') && $schema_handler->fieldExists('entity_test_update', 'new_base_field__color'); $this->assertTrue($assert, 'Columns created again in shared table for new_base_field.'); $entity = $storage->create(['name' => $name]); @@ -338,7 +318,7 @@ public function testBundleFieldCreateDeleteWithExistingEntities() { // Add a bundle field and run the update. Ensure the bundle field's table // is created and the prior saved entity data is still there. $this->addBundleField(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $schema_handler = $this->database->schema(); $this->assertTrue($schema_handler->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table created for new_bundle_field.'); $entity = $this->entityManager->getStorage('entity_test_update')->load($entity->id()); @@ -347,14 +327,14 @@ public function testBundleFieldCreateDeleteWithExistingEntities() { // Remove the base field and run the update. Ensure the bundle field's // table is deleted and the prior saved entity data is still there. $this->removeBundleField(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertFalse($schema_handler->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table deleted for new_bundle_field.'); $entity = $this->entityManager->getStorage('entity_test_update')->load($entity->id()); $this->assertIdentical($entity->name->value, $name, 'Entity data preserved during field deletion.'); // Test that required columns are created as 'not null'. $this->addBundleField('shape_required'); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $message = 'The new_bundle_field_shape column is not nullable.'; $values = [ 'bundle' => $entity->bundle(), @@ -407,7 +387,7 @@ public function testBaseFieldDeleteWithExistingData($entity_type_id, $create_ent // Add the base field and run the update. $this->addBaseField('string', $entity_type_id, $base_field_revisionable); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */ $table_mapping = $storage->getTableMapping(); @@ -425,7 +405,7 @@ public function testBaseFieldDeleteWithExistingData($entity_type_id, $create_ent // Remove the base field and apply updates. $this->removeBaseField($entity_type_id); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); // Check that the base field's column is deleted. $this->assertFalse($schema_handler->fieldExists($entity_type_id, 'new_base_field'), 'Column deleted from shared table for new_base_field.'); @@ -570,7 +550,7 @@ public function testBundleFieldDeleteWithExistingData() { // Add the bundle field and run the update. $this->addBundleField(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */ $table_mapping = $storage->getTableMapping(); @@ -587,7 +567,7 @@ public function testBundleFieldDeleteWithExistingData() { // Remove the bundle field and apply updates. $this->removeBundleField(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); // Check that the table of the bundle field has been renamed to use a // 'deleted' table name. @@ -641,7 +621,7 @@ public function testBundleFieldDeleteWithExistingData() { public function testBaseFieldUpdateWithExistingData() { // Add the base field and run the update. $this->addBaseField(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); // Save an entity with the base field populated. $this->entityManager->getStorage('entity_test_update')->create(['new_base_field' => 'foo'])->save(); @@ -650,7 +630,7 @@ public function testBaseFieldUpdateWithExistingData() { // throw an exception. $this->modifyBaseField(); try { - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->fail('FieldStorageDefinitionUpdateForbiddenException thrown when trying to update a field schema that has data.'); } catch (FieldStorageDefinitionUpdateForbiddenException $e) { @@ -664,7 +644,7 @@ public function testBaseFieldUpdateWithExistingData() { public function testBundleFieldUpdateWithExistingData() { // Add the bundle field and run the update. $this->addBundleField(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); // Save an entity with the bundle field populated. entity_test_create_bundle('custom'); @@ -674,7 +654,7 @@ public function testBundleFieldUpdateWithExistingData() { // throw an exception. $this->modifyBundleField(); try { - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->fail('FieldStorageDefinitionUpdateForbiddenException thrown when trying to update a field schema that has data.'); } catch (FieldStorageDefinitionUpdateForbiddenException $e) { @@ -698,7 +678,9 @@ public function testEntityIndexCreateDeleteWithoutData() { $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); // Run the update and ensure the new index is created. - $this->entityDefinitionUpdateManager->applyUpdates(); + $entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_update'); + $original = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledDefinition('entity_test_update'); + \Drupal::service('entity_type.listener')->onEntityTypeUpdate($entity_type, $original); $this->assertTrue($this->database->schema()->indexExists('entity_test_update', 'entity_test_update__new_index'), 'Index created.'); // Remove the index and ensure the update manager reports that as an @@ -713,13 +695,18 @@ public function testEntityIndexCreateDeleteWithoutData() { $this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.'); // Run the update and ensure the index is deleted. - $this->entityDefinitionUpdateManager->applyUpdates(); + $entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_update'); + $original = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledDefinition('entity_test_update'); + \Drupal::service('entity_type.listener')->onEntityTypeUpdate($entity_type, $original); $this->assertFalse($this->database->schema()->indexExists('entity_test_update', 'entity_test_update__new_index'), 'Index deleted.'); // Test that composite indexes are handled correctly when dropping and // re-creating one of their columns. $this->addEntityIndex(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_update'); + $original = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledDefinition('entity_test_update'); + \Drupal::service('entity_type.listener')->onEntityTypeUpdate($entity_type, $original); + $storage_definition = $this->entityDefinitionUpdateManager->getFieldStorageDefinition('name', 'entity_test_update'); $this->entityDefinitionUpdateManager->updateFieldStorageDefinition($storage_definition); $this->assertTrue($this->database->schema()->indexExists('entity_test_update', 'entity_test_update__new_index'), 'Index created.'); @@ -741,7 +728,9 @@ public function testEntityIndexCreateWithData() { // Add an entity index, run the update. Ensure that the index is created // despite having data. $this->addEntityIndex(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_update'); + $original = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledDefinition('entity_test_update'); + \Drupal::service('entity_type.listener')->onEntityTypeUpdate($entity_type, $original); $this->assertTrue($this->database->schema()->indexExists('entity_test_update', 'entity_test_update__new_index'), 'Index added.'); } @@ -862,7 +851,7 @@ public function testSingleActionCalls() { public function testCreateFieldAndIndexOnSharedTable() { $this->addBaseField(); $this->addBaseFieldIndex(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->assertTrue($this->database->schema()->fieldExists('entity_test_update', 'new_base_field'), "New field 'new_base_field' has been created on the 'entity_test_update' table."); $this->assertTrue($this->database->schema()->indexExists('entity_test_update', 'entity_test_update_field__new_base_field'), "New index 'entity_test_update_field__new_base_field' has been created on the 'entity_test_update' table."); // Check index size in for MySQL. @@ -889,7 +878,10 @@ public function testCreateIndexUsingEntityStorageSchemaWithData() { 'entity_test_update__type_index' => ['type'], ]; $this->state->set('entity_test_update.additional_entity_indexes', $indexes); - $this->entityDefinitionUpdateManager->applyUpdates(); + $entity_type = \Drupal::entityTypeManager()->getDefinition('entity_test_update'); + $original = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledDefinition('entity_test_update'); + \Drupal::service('entity_type.listener')->onEntityTypeUpdate($entity_type, $original); + $this->assertTrue($this->database->schema()->indexExists('entity_test_update', 'entity_test_update__type_index'), "New index 'entity_test_update__type_index' has been created on the 'entity_test_update' table."); // Check index size in for MySQL. if (Database::getConnection()->driver() == 'mysql') { @@ -904,7 +896,7 @@ public function testCreateIndexUsingEntityStorageSchemaWithData() { public function testBaseFieldEntityKeyUpdateWithExistingData() { // Add the base field and run the update. $this->addBaseField(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); // Save an entity with the base field populated. $this->entityManager->getStorage('entity_test_update')->create(['new_base_field' => $this->randomString()])->save(); @@ -926,7 +918,7 @@ public function testBaseFieldEntityKeyUpdateWithExistingData() { // Try to apply the update and verify they fail since we have a NULL value. $message = 'An error occurs when trying to enabling NOT NULL constraints with NULL data.'; try { - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->fail($message); } catch (EntityStorageException $e) { @@ -936,7 +928,7 @@ public function testBaseFieldEntityKeyUpdateWithExistingData() { // Check that the update is correctly applied when no NULL data is left. $entity->set('new_base_field', $this->randomString()); $entity->save(); - $this->entityDefinitionUpdateManager->applyUpdates(); + $this->applyEntityUpdates(); $this->pass('The update is correctly performed when no NULL data exists.'); // Check that the update actually applied a NOT NULL constraint.