diff --git a/core/core.services.yml b/core/core.services.yml index 66a46c6603..4490d3263b 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -599,7 +599,7 @@ services: arguments: ['@entity_type.manager', '@event_dispatcher', '@entity.last_installed_schema.repository', '@entity_field.manager', '@entity_field.deleted_fields_repository'] field_definition.listener: class: Drupal\Core\Field\FieldDefinitionListener - arguments: ['@entity_type.manager', '@entity_field.manager', '@keyvalue', '@cache.discovery'] + arguments: ['@entity_type.manager', '@entity_field.manager', '@keyvalue', '@cache.discovery', '@entity_field.deleted_fields_repository'] entity.form_builder: class: Drupal\Core\Entity\EntityFormBuilder arguments: ['@entity_type.manager', '@form_builder'] diff --git a/core/lib/Drupal/Core/Field/FieldDefinitionListener.php b/core/lib/Drupal/Core/Field/FieldDefinitionListener.php index 7b181f0dd7..c9051859bd 100644 --- a/core/lib/Drupal/Core/Field/FieldDefinitionListener.php +++ b/core/lib/Drupal/Core/Field/FieldDefinitionListener.php @@ -40,6 +40,13 @@ class FieldDefinitionListener implements FieldDefinitionListenerInterface { */ protected $entityFieldManager; + /** + * The deleted fields repository. + * + * @var \Drupal\Core\Field\DeletedFieldsRepositoryInterface + */ + protected $deletedFieldsRepository; + /** * Constructs a new FieldDefinitionListener. * @@ -51,12 +58,15 @@ class FieldDefinitionListener implements FieldDefinitionListenerInterface { * The key-value factory. * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend * The cache backend. + * @param \Drupal\Core\Field\DeletedFieldsRepositoryInterface $deleted_fields_repository + * The deleted fields repository. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, KeyValueFactoryInterface $key_value_factory, CacheBackendInterface $cache_backend) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, KeyValueFactoryInterface $key_value_factory, CacheBackendInterface $cache_backend, DeletedFieldsRepositoryInterface $deleted_fields_repository) { $this->entityTypeManager = $entity_type_manager; $this->entityFieldManager = $entity_field_manager; $this->keyValueFactory = $key_value_factory; $this->cacheBackend = $cache_backend; + $this->deletedFieldsRepository = $deleted_fields_repository; } /** @@ -118,6 +128,11 @@ public function onFieldDefinitionDelete(FieldDefinitionInterface $field_definiti $bundle = $field_definition->getTargetBundle(); $field_name = $field_definition->getName(); + $deleted_field_definitions = $this->deletedFieldsRepository->getFieldDefinitions(); + if (!isset($deleted_field_definitions[$field_definition->getUniqueIdentifier()])) { + $this->deletedFieldsRepository->addFieldDefinition($field_definition); + } + // Notify the storage about the field deletion. $this->entityTypeManager->getStorage($entity_type_id)->onFieldDefinitionDelete($field_definition); @@ -127,6 +142,11 @@ public function onFieldDefinitionDelete(FieldDefinitionInterface $field_definiti if (empty($bundle_field_map[$field_name]['bundles'])) { // If there are no bundles left, remove the field from the map. unset($bundle_field_map[$field_name]); + + // Also delete the associated field storage definition since it is not + // used anymore. + $storage_definition = $field_definition->getFieldStorageDefinition(); + \Drupal::service('field_storage_definition.listener')->onFieldStorageDefinitionDelete($storage_definition); } $this->keyValueFactory->get('entity.definitions.bundle_field_map')->set($entity_type_id, $bundle_field_map); 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 6edfb32bee..1e0733e63a 100644 --- a/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php +++ b/core/modules/system/tests/src/Functional/Entity/Traits/EntityDefinitionTestTrait.php @@ -209,9 +209,11 @@ protected function addBundleField($type = 'string') { ->setLabel(t('A new bundle field')) ->setTargetEntityTypeId('entity_test_update'); $field_definitions['new_bundle_field'] = FieldDefinition::createFromFieldStorageDefinition($storage_definitions['new_bundle_field']) - ->setTargetBundle('test_bundle'); + ->setTargetBundle('entity_test_update'); $this->state->set('entity_test_update.additional_field_storage_definitions', $storage_definitions); - $this->state->set('entity_test_update.additional_bundle_field_definitions.test_bundle', $field_definitions); + $this->state->set('entity_test_update.additional_bundle_field_definitions.entity_test_update', $field_definitions); + + $this->entityManager->onFieldDefinitionCreate($field_definitions['new_bundle_field']); } /** @@ -225,8 +227,11 @@ protected function modifyBundleField() { * Removes the new bundle field from the 'entity_test_update' entity type. */ protected function removeBundleField() { + $field_definition = $this->entityManager->getFieldDefinitions('entity_test_update', 'entity_test_update')['new_bundle_field']; + $this->entityManager->onFieldDefinitionDelete($field_definition); + $this->state->delete('entity_test_update.additional_field_storage_definitions'); - $this->state->delete('entity_test_update.additional_bundle_field_definitions.test_bundle'); + $this->state->delete('entity_test_update.additional_bundle_field_definitions.entity_test_update'); } /** diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php index 686bc61514..a8e3c46d74 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php @@ -572,10 +572,11 @@ public function testBundleFieldDeleteWithExistingData() { // Add the bundle field and run the update. $this->addBundleField(); $this->entityDefinitionUpdateManager->applyUpdates(); + $field_definition = $this->entityManager->getFieldDefinitions('entity_test_update', 'entity_test_update')['new_bundle_field']; + $storage_definition = $field_definition->getFieldStorageDefinition(); /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */ $table_mapping = $storage->getTableMapping(); - $storage_definition = $this->entityManager->getLastInstalledFieldStorageDefinitions('entity_test_update')['new_bundle_field']; // Check that the bundle field has a dedicated table. $dedicated_table_name = $table_mapping->getDedicatedDataTableName($storage_definition); @@ -583,7 +584,7 @@ public function testBundleFieldDeleteWithExistingData() { // Save an entity with the bundle field populated. entity_test_create_bundle('custom'); - $entity = $storage->create(['type' => 'test_bundle', 'new_bundle_field' => 'foo']); + $entity = $storage->create(['type' => 'entity_test_update', 'new_bundle_field' => 'foo']); $entity->save(); // Remove the bundle field and apply updates. @@ -620,8 +621,7 @@ public function testBundleFieldDeleteWithExistingData() { // Check that the field definition is marked for purging. $deleted_field_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldDefinitions(); - $installed_field_definition = FieldDefinition::createFromFieldStorageDefinition($storage_definition)->setTargetBundle('test_bundle'); - $this->assertArrayHasKey($installed_field_definition->getUniqueIdentifier(), $deleted_field_definitions, 'The bundle field is marked for purging.'); + $this->assertArrayHasKey($field_definition->getUniqueIdentifier(), $deleted_field_definitions, 'The bundle field is marked for purging.'); // Check that the field storage definition is marked for purging. $deleted_storage_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldStorageDefinitions();