diff --git a/modules/datastore/datastore.services.yml b/modules/datastore/datastore.services.yml index d8eccc4d80..e48d3bc7df 100644 --- a/modules/datastore/datastore.services.yml +++ b/modules/datastore/datastore.services.yml @@ -8,6 +8,7 @@ services: - '@dkan.datastore.import_job_store_factory' - '@dkan.datastore.service.resource_processor.dictionary_enforcer' - '@dkan.metastore.resource_mapper' + - '@event_dispatcher' dkan.datastore.service.post_import: class: \Drupal\datastore\Service\PostImport @@ -58,6 +59,7 @@ services: - '@dkan.datastore.import_job_store_factory' - '@dkan.datastore.database_table_factory' - '@dkan.datastore.logger_channel' + - '@event_dispatcher' dkan.datastore.logger_channel: parent: logger.channel_base diff --git a/modules/datastore/modules/datastore_mysql_import/datastore_mysql_import.services.yml b/modules/datastore/modules/datastore_mysql_import/datastore_mysql_import.services.yml index 8d918cb413..c9a0f88832 100644 --- a/modules/datastore/modules/datastore_mysql_import/datastore_mysql_import.services.yml +++ b/modules/datastore/modules/datastore_mysql_import/datastore_mysql_import.services.yml @@ -6,6 +6,7 @@ services: - '@dkan.datastore.import_job_store_factory' - '@dkan.datastore_mysql_import.database_table_factory' - '@dkan.datastore.logger_channel' + - '@event_dispatcher' dkan.datastore_mysql_import.database_table_factory: class: \Drupal\datastore_mysql_import\Storage\MySqlDatabaseTableFactory diff --git a/modules/datastore/modules/datastore_mysql_import/src/Factory/MysqlImportFactory.php b/modules/datastore/modules/datastore_mysql_import/src/Factory/MysqlImportFactory.php index 530cc06267..f06c90aac6 100644 --- a/modules/datastore/modules/datastore_mysql_import/src/Factory/MysqlImportFactory.php +++ b/modules/datastore/modules/datastore_mysql_import/src/Factory/MysqlImportFactory.php @@ -8,6 +8,7 @@ use Drupal\datastore_mysql_import\Service\MysqlImport; use Drupal\datastore_mysql_import\Storage\MySqlDatabaseTableFactory; use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Mysql importer factory. @@ -35,23 +36,30 @@ class MysqlImportFactory implements ImportFactoryInterface { */ private LoggerInterface $logger; + /** + * Event dispatcher service. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + private EventDispatcherInterface $eventDispatcher; + /** * Constructor. */ public function __construct( ImportJobStoreFactory $importJobStoreFactory, MySqlDatabaseTableFactory $databaseTableFactory, - LoggerInterface $loggerChannel + LoggerInterface $loggerChannel, + EventDispatcherInterface $eventDispatcher, ) { $this->importJobStoreFactory = $importJobStoreFactory; $this->databaseTableFactory = $databaseTableFactory; $this->logger = $loggerChannel; + $this->eventDispatcher = $eventDispatcher; } /** - * Inherited. - * - * @inheritdoc + * {@inheritDoc} */ public function getInstance(string $identifier, array $config = []) { $resource = $config['resource'] ?? FALSE; @@ -63,7 +71,8 @@ public function getInstance(string $identifier, array $config = []) { $resource, $this->importJobStoreFactory, $this->databaseTableFactory, - $this->logger + $this->logger, + $this->eventDispatcher ); $importer->setImporterClass(MysqlImport::class); return $importer; diff --git a/modules/datastore/src/DatastoreService.php b/modules/datastore/src/DatastoreService.php index a5e0c72934..9577789df1 100644 --- a/modules/datastore/src/DatastoreService.php +++ b/modules/datastore/src/DatastoreService.php @@ -2,9 +2,11 @@ namespace Drupal\datastore; -use Drupal\common\DataResource; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Queue\QueueFactory; +use Drupal\common\DataResource; +use Drupal\datastore\Events\DatastoreDroppedEvent; +use Drupal\datastore\Events\DatastorePreDropEvent; use Drupal\datastore\Service\Factory\ImportFactoryInterface; use Drupal\datastore\Service\ImportService; use Drupal\datastore\Service\ResourceLocalizer; @@ -12,12 +14,27 @@ use Drupal\datastore\Storage\ImportJobStoreFactory; use Drupal\metastore\ResourceMapper; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Main services for the datastore. */ class DatastoreService implements ContainerInjectionInterface { + /** + * This event is triggered when the datastore is about to be dropped. + * + * The event data is a keyed array, identifier and version. + */ + const EVENT_DATASTORE_PRE_DROP = 'dkan_datastore_pre_drop'; + + /** + * This event is triggered when the datastore is dropped. + * + * The event data is a keyed array, identifier and version. + */ + const EVENT_DATASTORE_DROPPED = 'dkan_datastore_dropped'; + /** * Resource localizer for handling remote resource URLs. * @@ -60,6 +77,13 @@ class DatastoreService implements ContainerInjectionInterface { */ private ImportJobStoreFactory $importJobStoreFactory; + /** + * Event dispatcher service. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + private EventDispatcherInterface $eventDispatcher; + /** * {@inheritdoc} */ @@ -70,7 +94,8 @@ public static function create(ContainerInterface $container) { $container->get('queue'), $container->get('dkan.datastore.import_job_store_factory'), $container->get('dkan.datastore.service.resource_processor.dictionary_enforcer'), - $container->get('dkan.metastore.resource_mapper') + $container->get('dkan.metastore.resource_mapper'), + $container->get('event_dispatcher') ); } @@ -89,6 +114,8 @@ public static function create(ContainerInterface $container) { * Dictionary Enforcer object. * @param \Drupal\metastore\ResourceMapper $resourceMapper * Resource mapper service. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher + * Event dispatcher service. */ public function __construct( ResourceLocalizer $resourceLocalizer, @@ -96,7 +123,8 @@ public function __construct( QueueFactory $queue, ImportJobStoreFactory $importJobStoreFactory, DictionaryEnforcer $dictionaryEnforcer, - ResourceMapper $resourceMapper + ResourceMapper $resourceMapper, + EventDispatcherInterface $eventDispatcher, ) { $this->resourceLocalizer = $resourceLocalizer; $this->importServiceFactory = $importServiceFactory; @@ -104,6 +132,7 @@ public function __construct( $this->importJobStoreFactory = $importJobStoreFactory; $this->dictionaryEnforcer = $dictionaryEnforcer; $this->resourceMapper = $resourceMapper; + $this->eventDispatcher = $eventDispatcher; } /** @@ -217,13 +246,13 @@ public function getImportService(DataResource $resource): ImportService { /** * Returns the Data Dictionary fields. * - * @param string $identifier + * @param string|null $identifier * A resource's identifier. Used when in reference mode. * * @return array|null * An array of dictionary fields or null if no dictionary is in use. */ - public function getDataDictionaryFields(string $identifier = NULL): ?array { + public function getDataDictionaryFields(?string $identifier = NULL): ?array { return $this->dictionaryEnforcer->returnDataDictionaryFields($identifier); } @@ -242,9 +271,17 @@ public function drop(string $identifier, ?string $version = NULL, bool $remove_l $resource = $this->resourceLocalizer->get($identifier, $version); if ($storage = $this->getStorage($identifier, $version)) { + $this->eventDispatcher->dispatch( + new DatastorePreDropEvent($identifier, $version), + self::EVENT_DATASTORE_PRE_DROP + ); $storage->destruct(); $this->importJobStoreFactory->getInstance() ->remove(md5($resource->getUniqueIdentifier())); + $this->eventDispatcher->dispatch( + new DatastoreDroppedEvent($identifier, $version), + self::EVENT_DATASTORE_DROPPED + ); } if ($remove_local_resource) { diff --git a/modules/datastore/src/EventSubscriber/DatastoreSubscriber.php b/modules/datastore/src/EventSubscriber/DatastoreSubscriber.php index ba06659e2c..a093e6c44c 100644 --- a/modules/datastore/src/EventSubscriber/DatastoreSubscriber.php +++ b/modules/datastore/src/EventSubscriber/DatastoreSubscriber.php @@ -167,6 +167,8 @@ public function drop(Event $event) { $resource = $event->getData(); $id = md5(str_replace(DataResource::DEFAULT_SOURCE_PERSPECTIVE, ResourceLocalizer::LOCAL_FILE_PERSPECTIVE, $resource->getUniqueIdentifier())); try { + // @todo Check if the datastore exists before dropping. Don't log an + // error if it wasn't there to begin with. $this->datastoreService->drop($resource->getIdentifier(), $resource->getVersion()); $this->logger->notice('Dropping datastore for @id', ['@id' => $id]); } diff --git a/modules/datastore/src/Events/DatastoreDroppedEvent.php b/modules/datastore/src/Events/DatastoreDroppedEvent.php new file mode 100644 index 0000000000..925ba7b5fa --- /dev/null +++ b/modules/datastore/src/Events/DatastoreDroppedEvent.php @@ -0,0 +1,12 @@ +identifier = $identifier; + $this->version = $version; + } + + /** + * {@inheritDoc} + */ + public function getIdentifier(): string { + return $this->identifier; + } + + /** + * {@inheritDoc} + */ + public function getVersion(): ?string { + return $this->version; + } + +} diff --git a/modules/datastore/src/Events/DatastoreEventInterface.php b/modules/datastore/src/Events/DatastoreEventInterface.php new file mode 100644 index 0000000000..16be03bc74 --- /dev/null +++ b/modules/datastore/src/Events/DatastoreEventInterface.php @@ -0,0 +1,26 @@ +importJobStoreFactory = $importJobStoreFactory; $this->databaseTableFactory = $databaseTableFactory; $this->logger = $loggerChannel; + $this->eventDispatcher = $eventDispatcher; } /** - * Inherited. - * - * @inheritdoc + * {@inheritDoc} */ public function getInstance(string $identifier, array $config = []) { if ($resource = $config['resource'] ?? FALSE) { @@ -57,7 +65,8 @@ public function getInstance(string $identifier, array $config = []) { $resource, $this->importJobStoreFactory, $this->databaseTableFactory, - $this->logger + $this->logger, + $this->eventDispatcher, ); } throw new \Exception("config['resource'] is required"); diff --git a/modules/datastore/src/Service/ImportService.php b/modules/datastore/src/Service/ImportService.php index a89c097c18..39ab3fca97 100644 --- a/modules/datastore/src/Service/ImportService.php +++ b/modules/datastore/src/Service/ImportService.php @@ -5,12 +5,14 @@ use CsvParser\Parser\Csv; use Drupal\common\DataResource; use Drupal\common\EventDispatcherTrait; +use Drupal\datastore\Events\DatastoreImportedEvent; use Drupal\datastore\Plugin\QueueWorker\ImportJob; use Drupal\datastore\Storage\DatabaseTable; use Drupal\datastore\Storage\DatabaseTableFactory; use Drupal\datastore\Storage\ImportJobStoreFactory; use Procrastinator\Result; use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Datastore importer. @@ -30,6 +32,12 @@ class ImportService { */ public const EVENT_CONFIGURE_PARSER = 'dkan_datastore_import_configure_parser'; + /** + * Event name for when the datastore has been successfully imported. + */ + public const EVENT_DATASTORE_IMPORTED = 'dkan_datastore_imported'; + + /** * Time-limit used for standard import service. * @@ -83,6 +91,13 @@ class ImportService { */ private LoggerInterface $logger; + /** + * Event dispatcher service. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + private EventDispatcherInterface $eventDispatcher; + /** * Create a resource service instance. * @@ -94,17 +109,21 @@ class ImportService { * Database Table factory. * @param \Psr\Log\LoggerInterface $loggerChannel * DKAN logger channel service. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher + * Event dispatcher service. */ public function __construct( DataResource $resource, ImportJobStoreFactory $importJobStoreFactory, DatabaseTableFactory $databaseTableFactory, - LoggerInterface $loggerChannel + LoggerInterface $loggerChannel, + EventDispatcherInterface $eventDispatcher, ) { $this->resource = $resource; $this->importJobStoreFactory = $importJobStoreFactory; $this->databaseTableFactory = $databaseTableFactory; $this->logger = $loggerChannel; + $this->eventDispatcher = $eventDispatcher; } /** @@ -129,9 +148,10 @@ protected function getResource(): DataResource { */ public function import() { $result = $this->getImporter()->run(); + $data_resource = $this->getResource(); if ($result->getStatus() === Result::ERROR) { - $datastore_resource = $this->getResource()->getDatastoreResource(); + $datastore_resource = $data_resource->getDatastoreResource(); $this->logger->error('Error importing resource id:%id path:%path message:%message', [ '%id' => $datastore_resource->getId(), '%path' => $datastore_resource->getFilePath(), @@ -139,12 +159,15 @@ public function import() { ]); } // If the import job finished successfully... - // @todo This should be an event that is emitted, and then processed - // elsewhere. elseif ($result->getStatus() === Result::DONE) { + // Dispatch the import event. + $this->eventDispatcher->dispatch( + new DatastoreImportedEvent($data_resource->getIdentifier(), $data_resource->getVersion()), + self::EVENT_DATASTORE_IMPORTED + ); // Queue the imported resource for post-import processing. $post_import_queue = \Drupal::service('queue')->get('post_import'); - $post_import_queue->createItem($this->getResource()); + $post_import_queue->createItem($data_resource); } } diff --git a/modules/datastore/tests/src/Kernel/DatastoreServiceEventsTest.php b/modules/datastore/tests/src/Kernel/DatastoreServiceEventsTest.php new file mode 100644 index 0000000000..0531502e64 --- /dev/null +++ b/modules/datastore/tests/src/Kernel/DatastoreServiceEventsTest.php @@ -0,0 +1,166 @@ + 'catchPreDropEvent', + DatastoreService::EVENT_DATASTORE_DROPPED => 'catchDroppedEvent', + ]; + } + + /** + * Event handler. + * + * @param \Drupal\common\Events\Event $event + * The event. + */ + public function catchPreDropEvent(DatastorePreDropEvent $event) { + $this->events[DatastoreService::EVENT_DATASTORE_PRE_DROP] = $event; + } + + /** + * Event handler. + * + * @param \Drupal\common\Events\Event $event + * The event. + */ + public function catchDroppedEvent(DatastoreDroppedEvent $event) { + $this->events[DatastoreService::EVENT_DATASTORE_DROPPED] = $event; + } + + /** + * {@inheritDoc} + */ + public function register(ContainerBuilder $container) { + parent::register($container); + $container->register('testing.datastore_drop_subscriber', self::class) + ->addTag('event_subscriber'); + $container->set('testing.datastore_drop_subscriber', $this); + } + + /** + * @covers ::drop + */ + public function testEvents() { + // Mock a data resource. + $data_resource = $this->getMockBuilder(DataResource::class) + ->disableOriginalConstructor() + ->onlyMethods(['getUniqueIdentifier']) + ->getMock(); + + // Mock the resource localizer. + $resource_localizer = $this->getMockBuilder(ResourceLocalizer::class) + ->disableOriginalConstructor() + ->onlyMethods(['get']) + ->getMock(); + $resource_localizer->expects($this->once()) + ->method('get') + ->willReturn($data_resource); + + // Mock the storage. + $storage = $this->getMockBuilder(DatabaseTable::class) + ->disableOriginalConstructor() + ->onlyMethods(['destruct']) + ->getMock(); + $storage->expects($this->once()) + ->method('destruct'); + + // Mock a database table so we don't need one. + $database_table = $this->getMockBuilder(DatabaseTableInterface::class) + ->onlyMethods(['remove']) + ->getMockForAbstractClass(); + $database_table->expects($this->once()) + ->method('remove'); + + // Mock a job store factory so we can avoid actually trying to drop an + // actual table. + $job_store_factory = $this->getMockBuilder(ImportJobStoreFactory::class) + ->disableOriginalConstructor() + ->onlyMethods(['getInstance']) + ->getMock(); + $job_store_factory->expects($this->once()) + ->method('getInstance') + ->willReturn($database_table); + + // Mock the datastore service so we can isolate the dispatched events. + $datastore_service = $this->getMockBuilder(DatastoreService::class) + // We only want to mock a few of the services. + ->setConstructorArgs([ + $resource_localizer, + $this->container->get('dkan.datastore.service.factory.import'), + $this->container->get('queue'), + $job_store_factory, + $this->container->get('dkan.datastore.service.resource_processor.dictionary_enforcer'), + $this->container->get('dkan.metastore.resource_mapper'), + $this->container->get('event_dispatcher'), + ]) + ->onlyMethods(['getStorage']) + ->getMock(); + $datastore_service->expects($this->once()) + ->method('getStorage') + ->willReturn($storage); + + // This test class, being an event subscriber, will load up $this->events + // with the events we generated. + $this->assertCount(0, $this->events); + $datastore_service->drop('id', 'ver', FALSE); + // 2 events happened because of drop(). + $this->assertCount(2, $this->events); + + // Pre-drop happened first. + $this->assertEquals( + ['dkan_datastore_pre_drop', 'dkan_datastore_dropped'], + array_keys($this->events) + ); + + // Both events will be DatastoreEventInterface, so we can use getters for + // our values. + /** @var \Drupal\datastore\Events\DatastoreEventInterface $event */ + foreach ($this->events as $event) { + $this->assertEquals('id', $event->getIdentifier()); + $this->assertEquals('ver', $event->getVersion()); + } + } + +} diff --git a/modules/datastore/tests/src/Kernel/Plugin/QueueWorker/ImportQueueWorkerTest.php b/modules/datastore/tests/src/Kernel/Plugin/QueueWorker/ImportQueueWorkerTest.php index 20c0c5d423..8d384d261a 100644 --- a/modules/datastore/tests/src/Kernel/Plugin/QueueWorker/ImportQueueWorkerTest.php +++ b/modules/datastore/tests/src/Kernel/Plugin/QueueWorker/ImportQueueWorkerTest.php @@ -47,6 +47,7 @@ public function testErrorPath() { $this->container->get('dkan.datastore.import_job_store_factory'), $this->container->get('dkan.datastore.service.resource_processor.dictionary_enforcer'), $this->container->get('dkan.metastore.resource_mapper'), + $this->container->get('event_dispatcher'), ]) ->onlyMethods(['import']) ->getMock(); @@ -93,6 +94,7 @@ public function testRequeue() { $this->container->get('dkan.datastore.import_job_store_factory'), $this->container->get('dkan.datastore.service.resource_processor.dictionary_enforcer'), $this->container->get('dkan.metastore.resource_mapper'), + $this->container->get('event_dispatcher'), ]) ->onlyMethods(['import']) ->getMock(); @@ -225,6 +227,7 @@ public function testAlreadyImported() { $this->container->get('dkan.datastore.import_job_store_factory'), $this->container->get('dkan.datastore.service.resource_processor.dictionary_enforcer'), $this->container->get('dkan.metastore.resource_mapper'), + $this->container->get('event_dispatcher'), ]) ->onlyMethods(['getStorage']) ->getMock(); diff --git a/modules/datastore/tests/src/Kernel/Service/ImportServiceEventsTest.php b/modules/datastore/tests/src/Kernel/Service/ImportServiceEventsTest.php new file mode 100644 index 0000000000..a581d78c72 --- /dev/null +++ b/modules/datastore/tests/src/Kernel/Service/ImportServiceEventsTest.php @@ -0,0 +1,115 @@ + 'catchImportEvent']; + } + + /** + * Our event handler. + * + * @param \Drupal\common\Events\Event $event + * The event. + */ + public function catchImportEvent(DatastoreImportedEvent $event) { + $this->events[] = $event; + } + + /** + * {@inheritDoc} + */ + public function register(ContainerBuilder $container) { + parent::register($container); + $container->register('testing.datastore_imported_subscriber', self::class) + ->addTag('event_subscriber'); + $container->set('testing.datastore_imported_subscriber', $this); + } + + /** + * @covers ::import + */ + public function testEvents() { + // Our result will be DONE. + $result = new Result(); + $result->setStatus(Result::DONE); + + // Our import job will return our result. + $import_job = $this->getMockBuilder(ImportJob::class) + ->disableOriginalConstructor() + ->onlyMethods(['run']) + ->getMock(); + $import_job->expects($this->once()) + ->method('run') + ->willReturn($result); + + // Mock an ImportService object to test. We'll mock a number of methods + // so that we can isolate the event dispatch. + $import_service = $this->getMockBuilder(ImportService::class) + ->setConstructorArgs([ + $this->createStub(DataResource::class), + $this->container->get('dkan.datastore.import_job_store_factory'), + $this->container->get('dkan.datastore.database_table_factory'), + $this->container->get('dkan.datastore.logger_channel'), + $this->container->get('event_dispatcher'), + ]) + ->onlyMethods(['getImporter', 'getResource']) + ->getMock(); + // getImporter returns the import job and thus the result. + $import_service->expects($this->once()) + ->method('getImporter') + ->willReturn($import_job); + // getResource will return a known data resource. + $import_service->expects($this->once()) + ->method('getResource') + ->willReturn(new DataResource('path', 'text/csv', 'local_file')); + + // This test class, being an event subscriber, will load up $this->events + // with the events we generated. + $this->assertCount(0, $this->events); + $import_service->import(); + $this->assertCount(1, $this->events); + /** @var \Drupal\datastore\Events\DatastoreImportedEvent $event */ + $event = reset($this->events); + $this->assertNotEmpty($event->getIdentifier()); + $this->assertNotEmpty($event->getVersion()); + } + +} diff --git a/modules/datastore/tests/src/Kernel/Service/ImportServiceTest.php b/modules/datastore/tests/src/Kernel/Service/ImportServiceTest.php index 763a352071..1e2dab4b81 100644 --- a/modules/datastore/tests/src/Kernel/Service/ImportServiceTest.php +++ b/modules/datastore/tests/src/Kernel/Service/ImportServiceTest.php @@ -52,7 +52,8 @@ public function testImport() { new DataResource('abc.txt', 'text/csv'), $this->container->get('dkan.datastore.import_job_store_factory'), $this->container->get('dkan.datastore.database_table_factory'), - $this->container->get('dkan.datastore.logger_channel') + $this->container->get('dkan.datastore.logger_channel'), + $this->container->get('event_dispatcher'), ]) ->getMock(); $import_service->method('getImporter') diff --git a/modules/datastore/tests/src/Unit/DatastoreServiceTest.php b/modules/datastore/tests/src/Unit/DatastoreServiceTest.php index f2a3bbaf24..64bd27381e 100644 --- a/modules/datastore/tests/src/Unit/DatastoreServiceTest.php +++ b/modules/datastore/tests/src/Unit/DatastoreServiceTest.php @@ -97,6 +97,7 @@ public function testGetDataDictionaryFields() { private function getCommonChain() { $options = (new Options()) + ->add('event_dispatcher', ContainerAwareEventDispatcher::class) ->add('dkan.metastore.resource_mapper', ResourceMapper::class) ->add('dkan.datastore.service.resource_localizer', ResourceLocalizer::class) ->add('dkan.datastore.service.factory.import', ImportServiceFactory::class) diff --git a/modules/datastore/tests/src/Unit/Service/DatastoreQueryTest.php b/modules/datastore/tests/src/Unit/Service/DatastoreQueryTest.php index 850f59419d..0aba0301d0 100644 --- a/modules/datastore/tests/src/Unit/Service/DatastoreQueryTest.php +++ b/modules/datastore/tests/src/Unit/Service/DatastoreQueryTest.php @@ -15,6 +15,7 @@ use Drupal\datastore\Service\Factory\ImportServiceFactory; use Drupal\datastore\Service\ResourceLocalizer; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Drupal\datastore\Service\DatastoreQuery; @@ -190,6 +191,7 @@ private function getDatastoreQueryFromJson($payloadName): DatastoreQuery { public function getCommonMockChain() { $options = (new Options()) + ->add('event_dispatcher', EventDispatcherInterface::class) ->add('dkan.metastore.resource_mapper', ResourceMapper::class) ->add("dkan.datastore.query", Query::class) ->add("dkan.datastore.service", DatastoreService::class) diff --git a/modules/datastore/tests/src/Unit/Service/Factory/ImportServiceFactoryTest.php b/modules/datastore/tests/src/Unit/Service/Factory/ImportServiceFactoryTest.php index 9b10f09940..65c0c66fc0 100644 --- a/modules/datastore/tests/src/Unit/Service/Factory/ImportServiceFactoryTest.php +++ b/modules/datastore/tests/src/Unit/Service/Factory/ImportServiceFactoryTest.php @@ -1,5 +1,7 @@ getMockBuilder(DatabaseTableFactory::class) ->disableOriginalConstructor() ->getMock(), - $this->createStub(LoggerInterface::class) + $this->createStub(LoggerInterface::class), + $this->createStub(EventDispatcherInterface::class) ); $this->expectException(\Exception::class);