diff --git a/core/lib/Drupal/Core/Entity/EntityTypeListener.php b/core/lib/Drupal/Core/Entity/EntityTypeListener.php index 5f9a35e22b..4bf05404d9 100644 --- a/core/lib/Drupal/Core/Entity/EntityTypeListener.php +++ b/core/lib/Drupal/Core/Entity/EntityTypeListener.php @@ -116,9 +116,9 @@ public function onEntityTypeDelete(EntityTypeInterface $entity_type) { $storage->onEntityTypeDelete($entity_type); } - $this->eventDispatcher->dispatch(EntityTypeEvents::DELETE, new EntityTypeEvent($entity_type)); - $this->entityLastInstalledSchemaRepository->deleteLastInstalledDefinition($entity_type_id); + + $this->eventDispatcher->dispatch(EntityTypeEvents::DELETE, new EntityTypeEvent($entity_type)); } /** diff --git a/core/lib/Drupal/Core/Field/FieldStorageDefinitionListener.php b/core/lib/Drupal/Core/Field/FieldStorageDefinitionListener.php index 329a175cc0..9194880fa8 100644 --- a/core/lib/Drupal/Core/Field/FieldStorageDefinitionListener.php +++ b/core/lib/Drupal/Core/Field/FieldStorageDefinitionListener.php @@ -86,10 +86,9 @@ public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $ } $this->entityLastInstalledSchemaRepository->setLastInstalledFieldStorageDefinition($storage_definition); + $this->entityFieldManager->clearCachedFieldDefinitions(); $this->eventDispatcher->dispatch(FieldStorageDefinitionEvents::CREATE, new FieldStorageDefinitionEvent($storage_definition)); - - $this->entityFieldManager->clearCachedFieldDefinitions(); } /** @@ -106,10 +105,9 @@ public function onFieldStorageDefinitionUpdate(FieldStorageDefinitionInterface $ } $this->entityLastInstalledSchemaRepository->setLastInstalledFieldStorageDefinition($storage_definition); + $this->entityFieldManager->clearCachedFieldDefinitions(); $this->eventDispatcher->dispatch(FieldStorageDefinitionEvents::UPDATE, new FieldStorageDefinitionEvent($storage_definition, $original)); - - $this->entityFieldManager->clearCachedFieldDefinitions(); } /** @@ -135,10 +133,10 @@ public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $ $storage->onFieldStorageDefinitionDelete($storage_definition); } - $this->eventDispatcher->dispatch(FieldStorageDefinitionEvents::DELETE, new FieldStorageDefinitionEvent($storage_definition)); - $this->entityLastInstalledSchemaRepository->deleteLastInstalledFieldStorageDefinition($storage_definition); $this->entityFieldManager->clearCachedFieldDefinitions(); + + $this->eventDispatcher->dispatch(FieldStorageDefinitionEvents::DELETE, new FieldStorageDefinitionEvent($storage_definition)); } } diff --git a/core/modules/system/tests/modules/entity_test/entity_test.services.yml b/core/modules/system/tests/modules/entity_test/entity_test.services.yml index 75e1bf33ce..4e202ae8fd 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.services.yml +++ b/core/modules/system/tests/modules/entity_test/entity_test.services.yml @@ -1,7 +1,7 @@ services: entity_test.definition.subscriber: class: Drupal\entity_test\EntityTestDefinitionSubscriber - arguments: ['@state'] + arguments: ['@state', '@entity.last_installed_schema.repository'] tags: - { name: event_subscriber } cache_context.entity_test_view_grants: diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestDefinitionSubscriber.php b/core/modules/system/tests/modules/entity_test/src/EntityTestDefinitionSubscriber.php index 6cdceb6d9c..03e768fb3c 100644 --- a/core/modules/system/tests/modules/entity_test/src/EntityTestDefinitionSubscriber.php +++ b/core/modules/system/tests/modules/entity_test/src/EntityTestDefinitionSubscriber.php @@ -2,6 +2,7 @@ namespace Drupal\entity_test; +use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface; use Drupal\Core\Entity\EntityTypeEvents; use Drupal\Core\Entity\EntityTypeEventSubscriberTrait; use Drupal\Core\Entity\EntityTypeInterface; @@ -28,6 +29,13 @@ class EntityTestDefinitionSubscriber implements EventSubscriberInterface, Entity */ protected $state; + /** + * The last installed schema repository. + * + * @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface + */ + protected $entityLastInstalledSchemaRepository; + /** * Flag determining whether events should be tracked. * @@ -38,8 +46,9 @@ class EntityTestDefinitionSubscriber implements EventSubscriberInterface, Entity /** * {@inheritdoc} */ - public function __construct(StateInterface $state) { + public function __construct(StateInterface $state, EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_repository) { $this->state = $state; + $this->entityLastInstalledSchemaRepository = $entity_last_installed_schema_repository; } /** @@ -53,6 +62,9 @@ public static function getSubscribedEvents() { * {@inheritdoc} */ public function onEntityTypeCreate(EntityTypeInterface $entity_type) { + if ($this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type->id())) { + $this->storeDefinitionUpdate(EntityTypeEvents::CREATE); + } $this->storeEvent(EntityTypeEvents::CREATE); } @@ -60,6 +72,11 @@ public function onEntityTypeCreate(EntityTypeInterface $entity_type) { * {@inheritdoc} */ public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeInterface $original) { + $last_installed_definition = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type->id()); + if ((string) $last_installed_definition->getLabel() === 'Updated entity test rev') { + $this->storeDefinitionUpdate(EntityTypeEvents::UPDATE); + } + $this->storeEvent(EntityTypeEvents::UPDATE); } @@ -74,6 +91,9 @@ public function onFieldableEntityTypeUpdate(EntityTypeInterface $entity_type, En * {@inheritdoc} */ public function onEntityTypeDelete(EntityTypeInterface $entity_type) { + if (!$this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type->id())) { + $this->storeDefinitionUpdate(EntityTypeEvents::DELETE); + } $this->storeEvent(EntityTypeEvents::DELETE); } @@ -81,6 +101,9 @@ public function onEntityTypeDelete(EntityTypeInterface $entity_type) { * {@inheritdoc} */ public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $storage_definition) { + if (isset($this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($storage_definition->getTargetEntityTypeId())[$storage_definition->getName()])) { + $this->storeDefinitionUpdate(FieldStorageDefinitionEvents::CREATE); + } $this->storeEvent(FieldStorageDefinitionEvents::CREATE); } @@ -88,6 +111,10 @@ public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $ * {@inheritdoc} */ public function onFieldStorageDefinitionUpdate(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original) { + $last_installed_definition = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($storage_definition->getTargetEntityTypeId())[$storage_definition->getName()]; + if ((string) $last_installed_definition->getLabel() === 'Updated field storage test') { + $this->storeDefinitionUpdate(FieldStorageDefinitionEvents::UPDATE); + } $this->storeEvent(FieldStorageDefinitionEvents::UPDATE); } @@ -95,6 +122,9 @@ public function onFieldStorageDefinitionUpdate(FieldStorageDefinitionInterface $ * {@inheritdoc} */ public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $storage_definition) { + if (!isset($this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($storage_definition->getTargetEntityTypeId())[$storage_definition->getName()])) { + $this->storeDefinitionUpdate(FieldStorageDefinitionEvents::DELETE); + } $this->storeEvent(FieldStorageDefinitionEvents::DELETE); } @@ -130,4 +160,30 @@ protected function storeEvent($event_name) { } } + /** + * Checks whether the installed definitions were updated before the event. + * + * @param string $event_name + * The event name. + * + * @return bool + * TRUE if the last installed entity type of field storage definitions have + * been updated before the was fired, FALSE otherwise. + */ + public function hasDefinitionBeenUpdated($event_name) { + return (bool) $this->state->get($event_name . '_updated_definition'); + } + + /** + * Stores the installed definition state for the specified event. + * + * @param string $event_name + * The event name. + */ + protected function storeDefinitionUpdate($event_name) { + if ($this->trackEvents) { + $this->state->set($event_name . '_updated_definition', TRUE); + } + } + } diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php index 76b63efef1..afe5af6681 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php @@ -14,6 +14,8 @@ use Drupal\Core\Field\FieldException; use Drupal\Core\Field\FieldStorageDefinitionEvents; use Drupal\Core\Language\LanguageInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\entity_test\FieldStorageDefinition; use Drupal\entity_test_update\Entity\EntityTestUpdate; use Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait; @@ -835,28 +837,47 @@ public function testDefinitionEvents() { $event_subscriber->enableEventTracking(); // Test field storage definition events. - $storage_definition = current(\Drupal::service('entity_field.manager')->getFieldStorageDefinitions('entity_test_rev')); - $this->assertFalse($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::DELETE), 'Entity type delete was not dispatched yet.'); - \Drupal::service('field_storage_definition.listener')->onFieldStorageDefinitionDelete($storage_definition); - $this->assertTrue($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::DELETE), 'Entity type delete event successfully dispatched.'); + $storage_definition = FieldStorageDefinition::create('string') + ->setName('field_storage_test') + ->setLabel(new TranslatableMarkup('Field storage test')) + ->setTargetEntityTypeId('entity_test_rev'); + $this->assertFalse($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::CREATE), 'Entity type create was not dispatched yet.'); \Drupal::service('field_storage_definition.listener')->onFieldStorageDefinitionCreate($storage_definition); $this->assertTrue($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::CREATE), 'Entity type create event successfully dispatched.'); + $this->assertTrue($event_subscriber->hasDefinitionBeenUpdated(FieldStorageDefinitionEvents::CREATE), 'Last installed field storage definition was created before the event was fired.'); + + $updated_storage_definition = clone $storage_definition; + $updated_storage_definition->setLabel(new TranslatableMarkup('Updated field storage test')); $this->assertFalse($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::UPDATE), 'Entity type update was not dispatched yet.'); - \Drupal::service('field_storage_definition.listener')->onFieldStorageDefinitionUpdate($storage_definition, $storage_definition); + \Drupal::service('field_storage_definition.listener')->onFieldStorageDefinitionUpdate($updated_storage_definition, $storage_definition); $this->assertTrue($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::UPDATE), 'Entity type update event successfully dispatched.'); + $this->assertTrue($event_subscriber->hasDefinitionBeenUpdated(FieldStorageDefinitionEvents::UPDATE), 'Last installed field storage definition was updated before the event was fired.'); + + $this->assertFalse($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::DELETE), 'Entity type delete was not dispatched yet.'); + \Drupal::service('field_storage_definition.listener')->onFieldStorageDefinitionDelete($storage_definition); + $this->assertTrue($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::DELETE), 'Entity type delete event successfully dispatched.'); + $this->assertTrue($event_subscriber->hasDefinitionBeenUpdated(FieldStorageDefinitionEvents::DELETE), 'Last installed field storage definition was deleted before the event was fired.'); // Test entity type events. $entity_type = $this->entityTypeManager->getDefinition('entity_test_rev'); + $this->assertFalse($event_subscriber->hasEventFired(EntityTypeEvents::CREATE), 'Entity type create was not dispatched yet.'); \Drupal::service('entity_type.listener')->onEntityTypeCreate($entity_type); $this->assertTrue($event_subscriber->hasEventFired(EntityTypeEvents::CREATE), 'Entity type create event successfully dispatched.'); + $this->assertTrue($event_subscriber->hasDefinitionBeenUpdated(EntityTypeEvents::CREATE), 'Last installed entity type definition was created before the event was fired.'); + + $updated_entity_type = clone $entity_type; + $updated_entity_type->set('label', new TranslatableMarkup('Updated entity test rev')); $this->assertFalse($event_subscriber->hasEventFired(EntityTypeEvents::UPDATE), 'Entity type update was not dispatched yet.'); - \Drupal::service('entity_type.listener')->onEntityTypeUpdate($entity_type, $entity_type); + \Drupal::service('entity_type.listener')->onEntityTypeUpdate($updated_entity_type, $entity_type); $this->assertTrue($event_subscriber->hasEventFired(EntityTypeEvents::UPDATE), 'Entity type update event successfully dispatched.'); + $this->assertTrue($event_subscriber->hasDefinitionBeenUpdated(EntityTypeEvents::UPDATE), 'Last installed entity type definition was updated before the event was fired.'); + $this->assertFalse($event_subscriber->hasEventFired(EntityTypeEvents::DELETE), 'Entity type delete was not dispatched yet.'); \Drupal::service('entity_type.listener')->onEntityTypeDelete($entity_type); $this->assertTrue($event_subscriber->hasEventFired(EntityTypeEvents::DELETE), 'Entity type delete event successfully dispatched.'); + $this->assertTrue($event_subscriber->hasDefinitionBeenUpdated(EntityTypeEvents::DELETE), 'Last installed entity type definition was deleted before the event was fired.'); } /**