From 47e003070536a19e632bdbd4fcf3da2bbe811037 Mon Sep 17 00:00:00 2001 From: Nathaniel Catchpole Date: Fri, 17 Oct 2014 23:10:00 +0100 Subject: [PATCH] Issue #2332935 by plach, alexpott, dawehner: Allow code to respond to entity/field schema changes. --- core/core.services.yml | 4 +- .../lib/Drupal/Core/DrupalKernelInterface.php | 3 +- .../Entity/EntityDefinitionUpdateManager.php | 2 +- core/lib/Drupal/Core/Entity/EntityManager.php | 37 ++++- .../Drupal/Core/Entity/EntityTypeEvent.php | 63 +++++++++ .../Entity/EntityTypeEventSubscriberTrait.php | 76 ++++++++++ .../Drupal/Core/Entity/EntityTypeEvents.php | 36 +++++ .../Drupal/Core/Extension/ModuleHandler.php | 61 +++++--- .../Field/FieldStorageDefinitionEvent.php | 63 +++++++++ ...dStorageDefinitionEventSubscriberTrait.php | 76 ++++++++++ .../Field/FieldStorageDefinitionEvents.php | 36 +++++ .../Plugin/DefaultLazyPluginCollection.php | 2 + .../DefaultSingleLazyPluginCollection.php | 2 + .../Entity/EntityDefinitionUpdateTest.php | 35 +++++ .../src/Tests/Plugin/PluginTestBase.php | 2 +- .../entity_test/entity_test.services.yml | 6 + .../src/EntityTestDefinitionSubscriber.php | 131 ++++++++++++++++++ core/modules/update/src/UpdateManager.php | 2 + .../Tests/Core/Entity/EntityManagerTest.php | 11 +- .../Core/Extension/ModuleHandlerTest.php | 25 ++-- 20 files changed, 633 insertions(+), 40 deletions(-) create mode 100644 core/lib/Drupal/Core/Entity/EntityTypeEvent.php create mode 100644 core/lib/Drupal/Core/Entity/EntityTypeEventSubscriberTrait.php create mode 100644 core/lib/Drupal/Core/Entity/EntityTypeEvents.php create mode 100644 core/lib/Drupal/Core/Field/FieldStorageDefinitionEvent.php create mode 100644 core/lib/Drupal/Core/Field/FieldStorageDefinitionEventSubscriberTrait.php create mode 100644 core/lib/Drupal/Core/Field/FieldStorageDefinitionEvents.php create mode 100644 core/modules/system/tests/modules/entity_test/entity_test.services.yml create mode 100644 core/modules/system/tests/modules/entity_test/src/EntityTestDefinitionSubscriber.php diff --git a/core/core.services.yml b/core/core.services.yml index 72d7d42350bc..7f9ed9b1ec39 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -287,13 +287,13 @@ services: arguments: ['@container.namespaces', '@cache.discovery', '@module_handler'] module_handler: class: Drupal\Core\Extension\ModuleHandler - arguments: ['%container.modules%', '@cache.bootstrap'] + arguments: ['%container.modules%', '@kernel', '@cache.bootstrap'] theme_handler: class: Drupal\Core\Extension\ThemeHandler arguments: ['@config.factory', '@module_handler', '@state', '@info_parser', '@logger.channel.default', '@asset.css.collection_optimizer', '@config.installer', '@config.manager', '@router.builder_indicator'] entity.manager: class: Drupal\Core\Entity\EntityManager - arguments: ['@container.namespaces', '@module_handler', '@cache.discovery', '@language_manager', '@string_translation', '@class_resolver', '@typed_data_manager', '@entity.definitions.installed'] + arguments: ['@container.namespaces', '@module_handler', '@cache.discovery', '@language_manager', '@string_translation', '@class_resolver', '@typed_data_manager', '@entity.definitions.installed', '@event_dispatcher'] parent: container.trait tags: - { name: plugin_manager_cache_clear } diff --git a/core/lib/Drupal/Core/DrupalKernelInterface.php b/core/lib/Drupal/Core/DrupalKernelInterface.php index ca7af2bd8b38..a5eb3b96a727 100644 --- a/core/lib/Drupal/Core/DrupalKernelInterface.php +++ b/core/lib/Drupal/Core/DrupalKernelInterface.php @@ -52,7 +52,8 @@ interface DrupalKernelInterface extends HttpKernelInterface { /** * Gets the current container. * - * @return ContainerInterface A ContainerInterface instance + * @return \Symfony\Component\DependencyInjection\ContainerInterface + * A ContainerInterface instance. */ public function getContainer(); diff --git a/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.php b/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.php index 4f92c8a9c071..197e4a44ac09 100644 --- a/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.php +++ b/core/lib/Drupal/Core/Entity/EntityDefinitionUpdateManager.php @@ -7,8 +7,8 @@ namespace Drupal\Core\Entity; -use Drupal\Core\Entity\Schema\EntityStorageSchemaInterface; use Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface; +use Drupal\Core\Entity\Schema\EntityStorageSchemaInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 32262395c82d..128d21d0d623 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -10,25 +10,28 @@ namespace Drupal\Core\Entity; use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Component\Utility\String; -use Drupal\Core\DependencyInjection\ClassResolverInterface; -use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\DependencyInjection\ClassResolverInterface; use Drupal\Core\Entity\Exception\AmbiguousEntityClassException; use Drupal\Core\Entity\Exception\NoCorrespondingEntityClassException; use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Field\FieldStorageDefinitionEvent; +use Drupal\Core\Field\FieldStorageDefinitionEvents; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\FieldStorageDefinitionListenerInterface; -use Drupal\Core\Language\LanguageManagerInterface; -use Drupal\Core\Language\LanguageInterface; -use Drupal\Core\Plugin\DefaultPluginManager; use Drupal\Core\KeyValueStore\KeyValueStoreInterface; +use Drupal\Core\Language\LanguageInterface; +use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\Plugin\DefaultPluginManager; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\StringTranslation\TranslationInterface; use Drupal\Core\TypedData\TranslatableInterface; use Drupal\Core\TypedData\TypedDataManager; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareTrait; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Manages entity type plugin definitions. @@ -122,6 +125,13 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa */ protected $installedDefinitions; + /** + * The event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $eventDispatcher; + /** * Static cache of bundle information. * @@ -183,8 +193,10 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa * The typed data manager. * @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $installed_definitions * The keyvalue collection for tracking installed definitions. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * The event dispatcher. */ - public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, TranslationInterface $translation_manager, ClassResolverInterface $class_resolver, TypedDataManager $typed_data_manager, KeyValueStoreInterface $installed_definitions) { + public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, TranslationInterface $translation_manager, ClassResolverInterface $class_resolver, TypedDataManager $typed_data_manager, KeyValueStoreInterface $installed_definitions, EventDispatcherInterface $event_dispatcher) { parent::__construct('Entity', $namespaces, $module_handler, 'Drupal\Core\Entity\EntityInterface', 'Drupal\Core\Entity\Annotation\EntityType'); $this->setCacheBackend($cache, 'entity_type', array('entity_types')); @@ -195,6 +207,7 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa $this->classResolver = $class_resolver; $this->typedDataManager = $typed_data_manager; $this->installedDefinitions = $installed_definitions; + $this->eventDispatcher = $event_dispatcher; } /** @@ -986,6 +999,8 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa $storage->onEntityTypeCreate($entity_type); } + $this->eventDispatcher->dispatch(EntityTypeEvents::CREATE, new EntityTypeEvent($entity_type)); + $this->setLastInstalledDefinition($entity_type); if ($entity_type->isSubclassOf('\Drupal\Core\Entity\FieldableEntityInterface')) { $this->setLastInstalledFieldStorageDefinitions($entity_type_id, $this->getFieldStorageDefinitions($entity_type_id)); @@ -1005,6 +1020,8 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa $storage->onEntityTypeUpdate($entity_type, $original); } + $this->eventDispatcher->dispatch(EntityTypeEvents::UPDATE, new EntityTypeEvent($entity_type, $original)); + $this->setLastInstalledDefinition($entity_type); } @@ -1021,6 +1038,8 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa $storage->onEntityTypeDelete($entity_type); } + $this->eventDispatcher->dispatch(EntityTypeEvents::DELETE, new EntityTypeEvent($entity_type)); + $this->deleteLastInstalledDefinition($entity_type_id); } @@ -1037,6 +1056,8 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa $storage->onFieldStorageDefinitionCreate($storage_definition); } + $this->eventDispatcher->dispatch(FieldStorageDefinitionEvents::CREATE, new FieldStorageDefinitionEvent($storage_definition)); + $this->setLastInstalledFieldStorageDefinition($storage_definition); $this->clearCachedFieldDefinitions(); } @@ -1054,6 +1075,8 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa $storage->onFieldStorageDefinitionUpdate($storage_definition, $original); } + $this->eventDispatcher->dispatch(FieldStorageDefinitionEvents::UPDATE, new FieldStorageDefinitionEvent($storage_definition, $original)); + $this->setLastInstalledFieldStorageDefinition($storage_definition); $this->clearCachedFieldDefinitions(); } @@ -1071,6 +1094,8 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa $storage->onFieldStorageDefinitionDelete($storage_definition); } + $this->eventDispatcher->dispatch(FieldStorageDefinitionEvents::DELETE, new FieldStorageDefinitionEvent($storage_definition)); + $this->deleteLastInstalledFieldStorageDefinition($storage_definition); $this->clearCachedFieldDefinitions(); } diff --git a/core/lib/Drupal/Core/Entity/EntityTypeEvent.php b/core/lib/Drupal/Core/Entity/EntityTypeEvent.php new file mode 100644 index 000000000000..baaffb59f53b --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityTypeEvent.php @@ -0,0 +1,63 @@ +entityType = $entity_type; + $this->original = $original; + } + + /** + * The entity type the event refers to. + * + * @return \Drupal\Core\Entity\EntityTypeInterface + */ + public function getEntityType() { + return $this->entityType; + } + + /** + * The original entity type. + * + * @return \Drupal\Core\Entity\EntityTypeInterface + */ + public function getOriginal() { + return $this->original; + } + +} diff --git a/core/lib/Drupal/Core/Entity/EntityTypeEventSubscriberTrait.php b/core/lib/Drupal/Core/Entity/EntityTypeEventSubscriberTrait.php new file mode 100644 index 000000000000..3b579a1176e4 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityTypeEventSubscriberTrait.php @@ -0,0 +1,76 @@ +onEntityTypeCreate($event->getEntityType()); + break; + + case EntityTypeEvents::UPDATE: + $this->onEntityTypeUpdate($event->getEntityType(), $event->getOriginal()); + break; + + case EntityTypeEvents::DELETE: + $this->onEntityTypeDelete($event->getEntityType()); + break; + } + } + + /** + * {@inheritdoc} + */ + abstract public function onEntityTypeCreate(EntityTypeInterface $entity_type); + + /** + * {@inheritdoc} + */ + abstract public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeInterface $original); + + /** + * {@inheritdoc} + */ + abstract public function onEntityTypeDelete(EntityTypeInterface $entity_type); + +} diff --git a/core/lib/Drupal/Core/Entity/EntityTypeEvents.php b/core/lib/Drupal/Core/Entity/EntityTypeEvents.php new file mode 100644 index 000000000000..39dc08048491 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityTypeEvents.php @@ -0,0 +1,36 @@ +moduleList = array(); foreach ($module_list as $name => $module) { $this->moduleList[$name] = new Extension($module['type'], $module['pathname'], $module['filename']); } + $this->kernel = $kernel; $this->cacheBackend = $cache_backend; } @@ -792,14 +802,7 @@ class ModuleHandler implements ModuleHandlerInterface { drupal_static_reset('system_rebuild_module_data'); // Update the kernel to include it. - // This reboots the kernel to register the module's bundle and its - // services in the service container. The $module_filenames argument is - // taken over as %container.modules% parameter, which is passed to a - // fresh ModuleHandler instance upon first retrieval. - // @todo install_begin_request() creates a container without a kernel. - if ($kernel = \Drupal::service('kernel', ContainerInterface::NULL_ON_INVALID_REFERENCE)) { - $kernel->updateModules($module_filenames, $module_filenames); - } + $this->updateKernel($module_filenames); // Refresh the schema to include it. drupal_get_schema(NULL, TRUE); @@ -822,10 +825,10 @@ class ModuleHandler implements ModuleHandlerInterface { $version = max(max($versions), $version); } - // Notify the entity manager that this module's entity types are new, - // so that it can notify all interested handlers. For example, a - // SQL-based storage handler can use this as an opportunity to create - // the necessary database tables. + // Notify interested components that this module's entity types are new. + // For example, a SQL-based storage handler can use this as an + // opportunity to create the necessary database tables. + // @todo Clean this up in https://www.drupal.org/node/2350111. $entity_manager = \Drupal::entityManager(); foreach ($entity_manager->getDefinitions() as $entity_type) { if ($entity_type->getProvider() == $module) { @@ -950,6 +953,7 @@ class ModuleHandler implements ModuleHandlerInterface { // Clean up all entity bundles (including fields) of every entity type // provided by the module that is being uninstalled. + // @todo Clean this up in https://www.drupal.org/node/2350111. foreach ($entity_manager->getDefinitions() as $entity_type_id => $entity_type) { if ($entity_type->getProvider() == $module) { foreach (array_keys($entity_manager->getBundleInfo($entity_type_id)) as $bundle) { @@ -968,10 +972,10 @@ class ModuleHandler implements ModuleHandlerInterface { // Remove all configuration belonging to the module. \Drupal::service('config.manager')->uninstall('module', $module); - // Notify the entity manager that this module's entity types are being - // deleted, so that it can notify all interested handlers. For example, - // a SQL-based storage handler can use this as an opportunity to drop - // the corresponding database tables. + // Notify interested components that this module's entity types are being + // deleted. For example, a SQL-based storage handler can use this as an + // opportunity to drop the corresponding database tables. + // @todo Clean this up in https://www.drupal.org/node/2350111. foreach ($entity_manager->getDefinitions() as $entity_type) { if ($entity_type->getProvider() == $module) { $entity_manager->onEntityTypeDelete($entity_type); @@ -1004,7 +1008,7 @@ class ModuleHandler implements ModuleHandlerInterface { \Drupal::service('router.builder_indicator')->setRebuildNeeded(); // Update the kernel to exclude the uninstalled modules. - \Drupal::service('kernel')->updateModules($module_filenames, $module_filenames); + $this->updateKernel($module_filenames); // Update the theme registry to remove the newly uninstalled module. drupal_theme_rebuild(); @@ -1084,4 +1088,23 @@ class ModuleHandler implements ModuleHandlerInterface { $module_data = system_rebuild_module_data(); return $module_data[$module]->info['name']; } + + /** + * Updates the kernel module list. + * + * @param string $module_filenames + * The list of installed modules. + */ + protected function updateKernel($module_filenames) { + // This reboots the kernel to register the module's bundle and its services + // in the service container. The $module_filenames argument is taken over as + // %container.modules% parameter, which is passed to a fresh ModuleHandler + // instance upon first retrieval. + $this->kernel->updateModules($module_filenames, $module_filenames); + // After rebuilding the container we need to update the injected + // dependencies. + $container = $this->kernel->getContainer(); + $this->cacheBackend = $container->get('cache.bootstrap'); + } + } diff --git a/core/lib/Drupal/Core/Field/FieldStorageDefinitionEvent.php b/core/lib/Drupal/Core/Field/FieldStorageDefinitionEvent.php new file mode 100644 index 000000000000..325780cc7316 --- /dev/null +++ b/core/lib/Drupal/Core/Field/FieldStorageDefinitionEvent.php @@ -0,0 +1,63 @@ +fieldStorageDefinition = $field_storage_definition; + $this->original = $original; + } + + /** + * The field storage definition. + * + * @return \Drupal\Core\Field\FieldStorageDefinitionInterface + */ + public function getFieldStorageDefinition() { + return $this->fieldStorageDefinition; + } + + /** + * The original field storage definition. + * + * @return \Drupal\Core\Field\FieldStorageDefinitionInterface + */ + public function getOriginal() { + return $this->original; + } + +} diff --git a/core/lib/Drupal/Core/Field/FieldStorageDefinitionEventSubscriberTrait.php b/core/lib/Drupal/Core/Field/FieldStorageDefinitionEventSubscriberTrait.php new file mode 100644 index 000000000000..29475646fd84 --- /dev/null +++ b/core/lib/Drupal/Core/Field/FieldStorageDefinitionEventSubscriberTrait.php @@ -0,0 +1,76 @@ +onFieldStorageDefinitionCreate($event->getFieldStorageDefinition()); + break; + + case FieldStorageDefinitionEvents::UPDATE: + $this->onFieldStorageDefinitionUpdate($event->getFieldStorageDefinition(), $event->getOriginal()); + break; + + case FieldStorageDefinitionEvents::DELETE: + $this->onFieldStorageDefinitionDelete($event->getFieldStorageDefinition()); + break; + } + } + + /** + * {@inheritdoc} + */ + abstract public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $storage_definition); + + /** + * {@inheritdoc} + */ + abstract public function onFieldStorageDefinitionUpdate(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original); + + /** + * {@inheritdoc} + */ + abstract public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $storage_definition); + +} diff --git a/core/lib/Drupal/Core/Field/FieldStorageDefinitionEvents.php b/core/lib/Drupal/Core/Field/FieldStorageDefinitionEvents.php new file mode 100644 index 000000000000..ea17ec649e52 --- /dev/null +++ b/core/lib/Drupal/Core/Field/FieldStorageDefinitionEvents.php @@ -0,0 +1,36 @@ +container->get('entity_test.definition.subscriber'); + $event_subscriber->enableEventTracking(); + + // Test field storage definition events. + $storage_definition = current($this->entityManager->getFieldStorageDefinitions('entity_test_rev')); + $this->assertFalse($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::DELETE), 'Entity type delete was not dispatched yet.'); + $this->entityManager->onFieldStorageDefinitionDelete($storage_definition); + $this->assertTrue($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::DELETE), 'Entity type delete event successfully dispatched.'); + $this->assertFalse($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::CREATE), 'Entity type create was not dispatched yet.'); + $this->entityManager->onFieldStorageDefinitionCreate($storage_definition); + $this->assertTrue($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::CREATE), 'Entity type create event successfully dispatched.'); + $this->assertFalse($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::UPDATE), 'Entity type update was not dispatched yet.'); + $this->entityManager->onFieldStorageDefinitionUpdate($storage_definition, $storage_definition); + $this->assertTrue($event_subscriber->hasEventFired(FieldStorageDefinitionEvents::UPDATE), 'Entity type update event successfully dispatched.'); + + // Test entity type events. + $entity_type = $this->entityManager->getDefinition('entity_test_rev'); + $this->assertFalse($event_subscriber->hasEventFired(EntityTypeEvents::CREATE), 'Entity type create was not dispatched yet.'); + $this->entityManager->onEntityTypeCreate($entity_type); + $this->assertTrue($event_subscriber->hasEventFired(EntityTypeEvents::CREATE), 'Entity type create event successfully dispatched.'); + $this->assertFalse($event_subscriber->hasEventFired(EntityTypeEvents::UPDATE), 'Entity type update was not dispatched yet.'); + $this->entityManager->onEntityTypeUpdate($entity_type, $entity_type); + $this->assertTrue($event_subscriber->hasEventFired(EntityTypeEvents::UPDATE), 'Entity type update event successfully dispatched.'); + $this->assertFalse($event_subscriber->hasEventFired(EntityTypeEvents::DELETE), 'Entity type delete was not dispatched yet.'); + $this->entityManager->onEntityTypeDelete($entity_type); + $this->assertTrue($event_subscriber->hasEventFired(EntityTypeEvents::DELETE), 'Entity type delete event successfully dispatched.'); + } + /** * Updates the 'entity_test_update' entity type to revisionable. */ diff --git a/core/modules/system/src/Tests/Plugin/PluginTestBase.php b/core/modules/system/src/Tests/Plugin/PluginTestBase.php index 3391c7399dd9..0285312786b1 100644 --- a/core/modules/system/src/Tests/Plugin/PluginTestBase.php +++ b/core/modules/system/src/Tests/Plugin/PluginTestBase.php @@ -47,7 +47,7 @@ abstract class PluginTestBase extends KernelTestBase { // as derivatives and ReflectionFactory. $this->testPluginManager = new TestPluginManager(); $this->mockBlockManager = new MockBlockManager(); - $module_handler = new ModuleHandler(array(), new MemoryBackend('plugin')); + $module_handler = new ModuleHandler(array(), $this->container->get('kernel'), new MemoryBackend('plugin'), $this->container->get('event_dispatcher')); $this->defaultsTestPluginManager = new DefaultsTestPluginManager($module_handler); // The expected plugin definitions within each manager. Several tests assert 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 new file mode 100644 index 000000000000..8769fbca2dfb --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/entity_test.services.yml @@ -0,0 +1,6 @@ +services: + entity_test.definition.subscriber: + class: Drupal\entity_test\EntityTestDefinitionSubscriber + arguments: ['@state'] + tags: + - { name: event_subscriber } diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestDefinitionSubscriber.php b/core/modules/system/tests/modules/entity_test/src/EntityTestDefinitionSubscriber.php new file mode 100644 index 000000000000..298f5c389d23 --- /dev/null +++ b/core/modules/system/tests/modules/entity_test/src/EntityTestDefinitionSubscriber.php @@ -0,0 +1,131 @@ +state = $state; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + return static::getEntityTypeEvents() + static::getFieldStorageDefinitionEvents(); + } + + /** + * {@inheritdoc} + */ + public function onEntityTypeCreate(EntityTypeInterface $entity_type) { + $this->storeEvent(EntityTypeEvents::CREATE); + } + + /** + * {@inheritdoc} + */ + public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeInterface $original) { + $this->storeEvent(EntityTypeEvents::UPDATE); + } + + /** + * {@inheritdoc} + */ + public function onEntityTypeDelete(EntityTypeInterface $entity_type) { + $this->storeEvent(EntityTypeEvents::DELETE); + } + + /** + * {@inheritdoc} + */ + public function onFieldStorageDefinitionCreate(FieldStorageDefinitionInterface $storage_definition) { + $this->storeEvent(FieldStorageDefinitionEvents::CREATE); + } + + /** + * {@inheritdoc} + */ + public function onFieldStorageDefinitionUpdate(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original) { + $this->storeEvent(FieldStorageDefinitionEvents::UPDATE); + } + + /** + * {@inheritdoc} + */ + public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $storage_definition) { + $this->storeEvent(FieldStorageDefinitionEvents::DELETE); + } + + /** + * Enables event tracking. + */ + public function enableEventTracking() { + $this->trackEvents = TRUE; + } + + /** + * Checks whether an event has been dispatched. + * + * @param string $event_name + * The event name. + * + * @return bool + * TRUE if the event has been dispatched, FALSE otherwise. + */ + public function hasEventFired($event_name) { + return (bool) $this->state->get($event_name); + } + + /** + * Stores the specified event. + * + * @param string $event_name + * The event name. + */ + protected function storeEvent($event_name) { + if ($this->trackEvents) { + $this->state->set($event_name, TRUE); + } + } + +} diff --git a/core/modules/update/src/UpdateManager.php b/core/modules/update/src/UpdateManager.php index a1801fe0aedb..21cfe806fcbb 100644 --- a/core/modules/update/src/UpdateManager.php +++ b/core/modules/update/src/UpdateManager.php @@ -7,6 +7,7 @@ namespace Drupal\update; use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\DependencyInjection\DependencySerializationTrait; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; use Drupal\Core\StringTranslation\TranslationInterface; @@ -17,6 +18,7 @@ use Drupal\Core\Utility\ProjectInfo; * Default implementation of UpdateManagerInterface. */ class UpdateManager implements UpdateManagerInterface { + use DependencySerializationTrait; use StringTranslationTrait; /** diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php index b93313264197..3b17502edbf1 100644 --- a/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/EntityManagerTest.php @@ -100,6 +100,13 @@ class EntityManagerTest extends UnitTestCase { */ protected $installedDefinitions; + /** + * The event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $eventDispatcher; + /** * {@inheritdoc} */ @@ -140,6 +147,8 @@ class EntityManagerTest extends UnitTestCase { ->disableOriginalConstructor() ->getMock(); + $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + $this->installedDefinitions = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreInterface'); } @@ -171,7 +180,7 @@ class EntityManagerTest extends UnitTestCase { ->method('getDefinitions') ->will($this->returnValue($definitions)); - $this->entityManager = new TestEntityManager(new \ArrayObject(), $this->moduleHandler, $this->cache, $this->languageManager, $this->translationManager, $this->getClassResolverStub(), $this->typedDataManager, $this->installedDefinitions); + $this->entityManager = new TestEntityManager(new \ArrayObject(), $this->moduleHandler, $this->cache, $this->languageManager, $this->translationManager, $this->getClassResolverStub(), $this->typedDataManager, $this->installedDefinitions, $this->eventDispatcher); $this->entityManager->setContainer($this->container); $this->entityManager->setDiscovery($this->discovery); } diff --git a/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php b/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php index bc5da97a61cd..493e2014c2e3 100644 --- a/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php +++ b/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php @@ -17,6 +17,13 @@ use Drupal\Tests\UnitTestCase; */ class ModuleHandlerTest extends UnitTestCase { + /** + * The mocked drupal kernel. + * + * @var \Drupal\Core\DrupalKernelInterface + */ + protected $kernel; + /** * The mocked cache backend. * @@ -24,7 +31,6 @@ class ModuleHandlerTest extends UnitTestCase { */ protected $cacheBackend; - /** * The tested module handler. * @@ -38,6 +44,7 @@ class ModuleHandlerTest extends UnitTestCase { * @covers ::__construct */ protected function setUp() { + $this->kernel = $this->getMock('Drupal\Core\DrupalKernelInterface'); $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); $this->moduleHandler = new ModuleHandler(array( 'module_handler_test' => array( @@ -45,7 +52,7 @@ class ModuleHandlerTest extends UnitTestCase { 'pathname' => 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml', 'filename' => 'module_handler_test.module', ) - ), $this->cacheBackend); + ), $this->kernel, $this->cacheBackend); } /** @@ -96,7 +103,7 @@ class ModuleHandlerTest extends UnitTestCase { 'pathname' => 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml', 'filename' => 'module_handler_test.module', ) - ), $this->cacheBackend + ), $this->kernel, $this->cacheBackend )) ->setMethods(array('load')) ->getMock(); @@ -164,7 +171,7 @@ class ModuleHandlerTest extends UnitTestCase { public function testSetModuleList() { $module_handler = $this->getMockBuilder('Drupal\Core\Extension\ModuleHandler') ->setConstructorArgs(array( - array(), $this->cacheBackend + array(), $this->kernel, $this->cacheBackend )) ->setMethods(array('resetImplementations')) ->getMock(); @@ -192,7 +199,7 @@ class ModuleHandlerTest extends UnitTestCase { $module_handler = $this->getMockBuilder('Drupal\Core\Extension\ModuleHandler') ->setConstructorArgs(array( - array(), $this->cacheBackend + array(), $this->kernel, $this->cacheBackend )) ->setMethods(array('resetImplementations')) ->getMock(); @@ -214,7 +221,7 @@ class ModuleHandlerTest extends UnitTestCase { $module_handler = $this->getMockBuilder('Drupal\Core\Extension\ModuleHandler') ->setConstructorArgs(array( - array(), $this->cacheBackend + array(), $this->kernel, $this->cacheBackend )) ->setMethods(array('resetImplementations')) ->getMock(); @@ -250,7 +257,7 @@ class ModuleHandlerTest extends UnitTestCase { 'pathname' => 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml', 'filename' => 'module_handler_test.module', ) - ), $this->cacheBackend + ), $this->kernel, $this->cacheBackend )) ->setMethods(array('loadInclude')) ->getMock(); @@ -331,7 +338,7 @@ class ModuleHandlerTest extends UnitTestCase { 'pathname' => 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml', 'filename' => 'module_handler_test.module', ) - ), $this->cacheBackend + ), $this->kernel, $this->cacheBackend )) ->setMethods(array('buildImplementationInfo', 'loadInclude')) ->getMock(); @@ -366,7 +373,7 @@ class ModuleHandlerTest extends UnitTestCase { 'pathname' => 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml', 'filename' => 'module_handler_test.module', ) - ), $this->cacheBackend + ), $this->kernel, $this->cacheBackend )) ->setMethods(array('buildImplementationInfo')) ->getMock();