diff --git a/CHANGELOG.md b/CHANGELOG.md
index a1f72379..2954b213 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,7 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
#### Changed
* [#450](https://github.com/shlinkio/shlink/issues/450) Added PHP 7.4 to the build matrix, as an allowed-to-fail env.
-* [#443](https://github.com/shlinkio/shlink/issues/443) Split some logic into independent modules.
+* [#441](https://github.com/shlinkio/shlink/issues/441) and [#443](https://github.com/shlinkio/shlink/issues/443) Split some logic into independent modules.
* [#451](https://github.com/shlinkio/shlink/issues/451) Updated to infection 0.13.
#### Deprecated
diff --git a/composer.json b/composer.json
index c1ed913e..994febcc 100644
--- a/composer.json
+++ b/composer.json
@@ -34,6 +34,7 @@
"phly/phly-event-dispatcher": "^1.0",
"predis/predis": "^1.1",
"shlinkio/shlink-common": "^1.0",
+ "shlinkio/shlink-event-dispatcher": "^1.0",
"shlinkio/shlink-installer": "^1.2.1",
"shlinkio/shlink-ip-geolocation": "^1.0",
"symfony/console": "^4.3",
@@ -76,12 +77,8 @@
"Shlinkio\\Shlink\\CLI\\": "module/CLI/src",
"Shlinkio\\Shlink\\Rest\\": "module/Rest/src",
"Shlinkio\\Shlink\\Core\\": "module/Core/src",
- "Shlinkio\\Shlink\\EventDispatcher\\": "module/EventDispatcher/src",
"Shlinkio\\Shlink\\PreviewGenerator\\": "module/PreviewGenerator/src/"
- },
- "files": [
- "module/EventDispatcher/functions/functions.php"
- ]
+ }
},
"autoload-dev": {
"psr-4": {
@@ -92,7 +89,6 @@
"module/Core/test",
"module/Core/test-db"
],
- "ShlinkioTest\\Shlink\\EventDispatcher\\": "module/EventDispatcher/test",
"ShlinkioTest\\Shlink\\PreviewGenerator\\": "module/PreviewGenerator/test"
}
},
diff --git a/module/EventDispatcher/LICENSE b/module/EventDispatcher/LICENSE
deleted file mode 100644
index 31778387..00000000
--- a/module/EventDispatcher/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2019 Alejandro Celaya
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/module/EventDispatcher/README.md b/module/EventDispatcher/README.md
deleted file mode 100644
index 47938c12..00000000
--- a/module/EventDispatcher/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Shlink Event Dispatcher
-
-This library provides a PSR-14 EventDispatcher which is capable of dispatching both regular listeners and async listeners which are run using [swoole]'s task system.
-
-Most of the elements it provides require a [PSR-11] container, and it's easy to integrate on [expressive] applications thanks to the `ConfigProvider` it includes.
-
-## Install
-
-Install this library using composer:
-
- composer require shlinkio/shlink-event-dispatcher
-
-> This library is also an expressive module which provides its own `ConfigProvider`. Add it to your configuration to get everything automatically set up.
diff --git a/module/EventDispatcher/config/event_dispatcher.config.php b/module/EventDispatcher/config/event_dispatcher.config.php
deleted file mode 100644
index 8941443f..00000000
--- a/module/EventDispatcher/config/event_dispatcher.config.php
+++ /dev/null
@@ -1,39 +0,0 @@
- [
- 'regular' => [],
- 'async' => [],
- ],
-
- 'dependencies' => [
- 'factories' => [
- Phly\EventDispatcher::class => Phly\EventDispatcherFactory::class,
- Psr\ListenerProviderInterface::class => Listener\ListenerProviderFactory::class,
- ],
- 'aliases' => [
- Psr\EventDispatcherInterface::class => Phly\EventDispatcher::class,
- ],
- 'delegators' => [
- // The listener provider has to be lazy, because it uses the Swoole server to generate AsyncEventListeners
- // Without making this lazy, CLI commands which depend on the EventDispatcher fail
- Psr\ListenerProviderInterface::class => [
- LazyServiceFactory::class,
- ],
- ],
- 'lazy_services' => [
- 'class_map' => [
- Psr\ListenerProviderInterface::class => Psr\ListenerProviderInterface::class,
- ],
- ],
- ],
-
-];
diff --git a/module/EventDispatcher/config/task_runner.config.php b/module/EventDispatcher/config/task_runner.config.php
deleted file mode 100644
index a0a23db5..00000000
--- a/module/EventDispatcher/config/task_runner.config.php
+++ /dev/null
@@ -1,21 +0,0 @@
- [
- 'factories' => [
- Async\TaskRunner::class => Async\TaskRunnerFactory::class,
- ],
- 'delegators' => [
- HttpServer::class => [
- Async\TaskRunnerDelegator::class,
- ],
- ],
- ],
-
-];
diff --git a/module/EventDispatcher/functions/functions.php b/module/EventDispatcher/functions/functions.php
deleted file mode 100644
index a1c93231..00000000
--- a/module/EventDispatcher/functions/functions.php
+++ /dev/null
@@ -1,11 +0,0 @@
-logger = $logger;
- $this->container = $container;
- }
-
- public function __invoke(HttpServer $server, int $taskId, int $fromId, $task): void
- {
- if (! $task instanceof TaskInterface) {
- $this->logger->warning('Invalid task provided to task worker: {type}. Task ignored', [
- 'type' => is_object($task) ? get_class($task) : gettype($task),
- ]);
- $server->finish('');
- return;
- }
-
- $this->logger->notice('Starting work on task {taskId}: {task}', [
- 'taskId' => $taskId,
- 'task' => $task->toString(),
- ]);
-
- try {
- $task->run($this->container);
- } catch (Throwable $e) {
- $this->logger->error('Error processing task {taskId}: {e}', [
- 'taskId' => $taskId,
- 'e' => $e,
- ]);
- } finally {
- $server->finish('');
- }
- }
-}
diff --git a/module/EventDispatcher/src/Async/TaskRunnerDelegator.php b/module/EventDispatcher/src/Async/TaskRunnerDelegator.php
deleted file mode 100644
index 7c87826b..00000000
--- a/module/EventDispatcher/src/Async/TaskRunnerDelegator.php
+++ /dev/null
@@ -1,25 +0,0 @@
-get(LoggerInterface::class);
-
- $server->on('task', $container->get(TaskRunner::class));
- $server->on('finish', function (HttpServer $server, int $taskId) use ($logger) {
- $logger->notice('Task #{taskId} has finished processing', ['taskId' => $taskId]);
- });
-
- return $server;
- }
-}
diff --git a/module/EventDispatcher/src/Async/TaskRunnerFactory.php b/module/EventDispatcher/src/Async/TaskRunnerFactory.php
deleted file mode 100644
index cacfefc5..00000000
--- a/module/EventDispatcher/src/Async/TaskRunnerFactory.php
+++ /dev/null
@@ -1,16 +0,0 @@
-get(LoggerInterface::class);
- return new TaskRunner($logger, $container);
- }
-}
diff --git a/module/EventDispatcher/src/ConfigProvider.php b/module/EventDispatcher/src/ConfigProvider.php
deleted file mode 100644
index 88f2045e..00000000
--- a/module/EventDispatcher/src/ConfigProvider.php
+++ /dev/null
@@ -1,14 +0,0 @@
-regularListenerName = $regularListenerName;
- $this->server = $server;
- }
-
- public function __invoke(object $event): void
- {
- $this->server->task(new EventListenerTask($this->regularListenerName, $event));
- }
-}
diff --git a/module/EventDispatcher/src/Listener/EventListenerTask.php b/module/EventDispatcher/src/Listener/EventListenerTask.php
deleted file mode 100644
index bc1e3689..00000000
--- a/module/EventDispatcher/src/Listener/EventListenerTask.php
+++ /dev/null
@@ -1,34 +0,0 @@
-listenerName = $listenerName;
- $this->event = $event;
- }
-
- public function run(ContainerInterface $container): void
- {
- ($container->get($this->listenerName))($this->event);
- }
-
- public function toString(): string
- {
- return sprintf('Listener -> "%s", Event -> "%s"', $this->listenerName, get_class($this->event));
- }
-}
diff --git a/module/EventDispatcher/src/Listener/ListenerProviderFactory.php b/module/EventDispatcher/src/Listener/ListenerProviderFactory.php
deleted file mode 100644
index 7e9198a8..00000000
--- a/module/EventDispatcher/src/Listener/ListenerProviderFactory.php
+++ /dev/null
@@ -1,52 +0,0 @@
-has('config') ? $container->get('config') : [];
- $events = $config['events'] ?? [];
- $provider = new AttachableListenerProvider();
-
- $this->registerListeners($events['regular'] ?? [], $container, $provider);
- $this->registerListeners($events['async'] ?? [], $container, $provider, true);
-
- return $provider;
- }
-
- private function registerListeners(
- array $events,
- ContainerInterface $container,
- AttachableListenerProvider $provider,
- bool $isAsync = false
- ): void {
- if (empty($events)) {
- return;
- }
-
- // Avoid registering async event listeners when the swoole server is not registered
- if ($isAsync && ! $container->has(HttpServer::class)) {
- return;
- }
-
- foreach ($events as $eventName => $listeners) {
- foreach ($listeners as $listenerName) {
- $eventListener = $isAsync
- ? asyncListener($container->get(HttpServer::class), $listenerName)
- : lazyListener($container, $listenerName);
-
- $provider->listen($eventName, $eventListener);
- }
- }
- }
-}
diff --git a/module/EventDispatcher/test/Async/TaskRunnerDelegatorTest.php b/module/EventDispatcher/test/Async/TaskRunnerDelegatorTest.php
deleted file mode 100644
index ad0978e7..00000000
--- a/module/EventDispatcher/test/Async/TaskRunnerDelegatorTest.php
+++ /dev/null
@@ -1,46 +0,0 @@
-delegator = new TaskRunnerDelegator();
- }
-
- /** @test */
- public function serverIsFetchedFromCallbackAndDecorated(): void
- {
- $server = $this->createMock(HttpServer::class);
- $server
- ->expects($this->exactly(2))
- ->method('on');
- $callback = function () use ($server) {
- return $server;
- };
-
- $container = $this->prophesize(ContainerInterface::class);
- $getTaskRunner = $container->get(TaskRunner::class)->willReturn($this->prophesize(TaskRunner::class)->reveal());
- $getLogger = $container->get(LoggerInterface::class)->willReturn(
- $this->prophesize(LoggerInterface::class)->reveal()
- );
-
- $result = ($this->delegator)($container->reveal(), '', $callback);
-
- $this->assertSame($server, $result);
- $getTaskRunner->shouldHaveBeenCalledOnce();
- $getLogger->shouldHaveBeenCalledOnce();
- }
-}
diff --git a/module/EventDispatcher/test/Async/TaskRunnerFactoryTest.php b/module/EventDispatcher/test/Async/TaskRunnerFactoryTest.php
deleted file mode 100644
index cf139b62..00000000
--- a/module/EventDispatcher/test/Async/TaskRunnerFactoryTest.php
+++ /dev/null
@@ -1,48 +0,0 @@
-factory = new TaskRunnerFactory();
- }
-
- /** @test */
- public function properlyCreatesService(): void
- {
- $loggerMock = $this->prophesize(LoggerInterface::class);
- $logger = $loggerMock->reveal();
- $containerMock = $this->prophesize(ContainerInterface::class);
- $getLogger = $containerMock->get(LoggerInterface::class)->willReturn($logger);
- $container = $containerMock->reveal();
-
- $taskRunner = ($this->factory)($container, '');
- $loggerProp = $this->getPropertyFromTaskRunner($taskRunner, 'logger');
- $containerProp = $this->getPropertyFromTaskRunner($taskRunner, 'container');
-
- $this->assertSame($container, $containerProp);
- $this->assertSame($logger, $loggerProp);
- $getLogger->shouldHaveBeenCalledOnce();
- }
-
- private function getPropertyFromTaskRunner(TaskRunner $taskRunner, string $propertyName)
- {
- $ref = new ReflectionObject($taskRunner);
- $prop = $ref->getProperty($propertyName);
- $prop->setAccessible(true);
- return $prop->getValue($taskRunner);
- }
-}
diff --git a/module/EventDispatcher/test/Async/TaskRunnerTest.php b/module/EventDispatcher/test/Async/TaskRunnerTest.php
deleted file mode 100644
index 0bf56d7c..00000000
--- a/module/EventDispatcher/test/Async/TaskRunnerTest.php
+++ /dev/null
@@ -1,107 +0,0 @@
-logger = $this->prophesize(LoggerInterface::class);
- $this->container = $this->prophesize(ContainerInterface::class);
- $this->task = $this->prophesize(TaskInterface::class);
-
- $this->server = $this->createMock(HttpServer::class);
- $this->server
- ->expects($this->once())
- ->method('finish')
- ->with('');
-
- $this->taskRunner = new TaskRunner($this->logger->reveal(), $this->container->reveal());
- }
-
- /** @test */
- public function warningIsLoggedWhenProvidedTaskIsInvalid(): void
- {
- $logWarning = $this->logger->warning('Invalid task provided to task worker: {type}. Task ignored', [
- 'type' => 'string',
- ]);
- $logInfo = $this->logger->info(Argument::cetera());
- $logError = $this->logger->error(Argument::cetera());
-
- ($this->taskRunner)($this->server, 1, 1, 'invalid_task');
-
- $logWarning->shouldHaveBeenCalledOnce();
- $logInfo->shouldNotHaveBeenCalled();
- $logError->shouldNotHaveBeenCalled();
- }
-
- /** @test */
- public function properTasksAreRun(): void
- {
- $logWarning = $this->logger->warning(Argument::cetera());
- $logInfo = $this->logger->notice('Starting work on task {taskId}: {task}', [
- 'taskId' => 1,
- 'task' => 'The task',
- ]);
- $logError = $this->logger->error(Argument::cetera());
- $taskToString = $this->task->toString()->willReturn('The task');
- $taskRun = $this->task->run($this->container->reveal())->will(function () {
- });
-
- ($this->taskRunner)($this->server, 1, 1, $this->task->reveal());
-
- $logWarning->shouldNotHaveBeenCalled();
- $logInfo->shouldHaveBeenCalledOnce();
- $logError->shouldNotHaveBeenCalled();
- $taskToString->shouldHaveBeenCalledOnce();
- $taskRun->shouldHaveBeenCalledOnce();
- }
-
- /** @test */
- public function errorIsLoggedWhenTasksFail(): void
- {
- $e = new Exception('Error');
-
- $logWarning = $this->logger->warning(Argument::cetera());
- $logInfo = $this->logger->notice('Starting work on task {taskId}: {task}', [
- 'taskId' => 1,
- 'task' => 'The task',
- ]);
- $logError = $this->logger->error('Error processing task {taskId}: {e}', [
- 'taskId' => 1,
- 'e' => $e,
- ]);
- $taskToString = $this->task->toString()->willReturn('The task');
- $taskRun = $this->task->run($this->container->reveal())->willThrow($e);
-
- ($this->taskRunner)($this->server, 1, 1, $this->task->reveal());
-
- $logWarning->shouldNotHaveBeenCalled();
- $logInfo->shouldHaveBeenCalledOnce();
- $logError->shouldHaveBeenCalledOnce();
- $taskToString->shouldHaveBeenCalledOnce();
- $taskRun->shouldHaveBeenCalledOnce();
- }
-}
diff --git a/module/EventDispatcher/test/ConfigProviderTest.php b/module/EventDispatcher/test/ConfigProviderTest.php
deleted file mode 100644
index 8c344467..00000000
--- a/module/EventDispatcher/test/ConfigProviderTest.php
+++ /dev/null
@@ -1,27 +0,0 @@
-configProvider = new ConfigProvider();
- }
-
- /** @test */
- public function configIsReturned(): void
- {
- $config = $this->configProvider->__invoke();
-
- $this->assertArrayHasKey('dependencies', $config);
- $this->assertArrayHasKey('events', $config);
- }
-}
diff --git a/module/EventDispatcher/test/Listener/AsyncEventListenerTest.php b/module/EventDispatcher/test/Listener/AsyncEventListenerTest.php
deleted file mode 100644
index 554528cd..00000000
--- a/module/EventDispatcher/test/Listener/AsyncEventListenerTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-regularListenerName = 'the_regular_listener';
- $this->server = $this->createMock(HttpServer::class);
-
- $this->eventListener = new AsyncEventListener($this->server, $this->regularListenerName);
- }
-
- /** @test */
- public function enqueuesTaskWhenInvoked(): void
- {
- $event = new stdClass();
-
- $this->server
- ->expects($this->once())
- ->method('task')
- ->with(new EventListenerTask($this->regularListenerName, $event));
-
- ($this->eventListener)($event);
- }
-}
diff --git a/module/EventDispatcher/test/Listener/EventListenerTaskTest.php b/module/EventDispatcher/test/Listener/EventListenerTaskTest.php
deleted file mode 100644
index 5cc6d5a9..00000000
--- a/module/EventDispatcher/test/Listener/EventListenerTaskTest.php
+++ /dev/null
@@ -1,58 +0,0 @@
-event = new stdClass();
- $this->listenerName = 'the_listener';
-
- $this->task = new EventListenerTask($this->listenerName, $this->event);
- }
-
- /** @test */
- public function toStringReturnsTheStringRepresentation(): void
- {
- $this->assertEquals(
- sprintf('Listener -> "%s", Event -> "%s"', $this->listenerName, get_class($this->event)),
- $this->task->toString()
- );
- }
-
- /** @test */
- public function runInvokesContainerAndListenerWithEvent(): void
- {
- $invoked = false;
- $container = $this->prophesize(ContainerInterface::class);
- $listener = function (object $event) use (&$invoked) {
- $invoked = true;
- Assert::assertSame($event, $this->event);
- };
-
- $getListener = $container->get($this->listenerName)->willReturn($listener);
-
- $this->task->run($container->reveal());
-
- $this->assertTrue($invoked);
- $getListener->shouldHaveBeenCalledOnce();
- }
-}
diff --git a/module/EventDispatcher/test/Listener/ListenerProviderFactoryTest.php b/module/EventDispatcher/test/Listener/ListenerProviderFactoryTest.php
deleted file mode 100644
index 493940a3..00000000
--- a/module/EventDispatcher/test/Listener/ListenerProviderFactoryTest.php
+++ /dev/null
@@ -1,176 +0,0 @@
-factory = new ListenerProviderFactory();
- }
-
- /**
- * @test
- * @dataProvider provideContainersWithoutEvents
- */
- public function noListenersAreAttachedWhenNoConfigOrEventsAreRegistered(ContainerInterface $container): void
- {
- $provider = ($this->factory)($container, '');
- $listeners = $this->getListenersFromProvider($provider);
-
- $this->assertInstanceOf(AttachableListenerProvider::class, $provider);
- $this->assertEmpty($listeners);
- }
-
- public function provideContainersWithoutEvents(): iterable
- {
- yield 'no config' => [(function () {
- $container = $this->prophesize(ContainerInterface::class);
- $container->has('config')->willReturn(false);
-
- return $container->reveal();
- })()];
- yield 'no events' => [(function () {
- $container = $this->prophesize(ContainerInterface::class);
- $container->has('config')->willReturn(true);
- $container->get('config')->willReturn([]);
-
- return $container->reveal();
- })()];
- }
-
- /** @test */
- public function configuredRegularEventsAreProperlyAttached(): void
- {
- $containerMock = $this->prophesize(ContainerInterface::class);
- $containerMock->has('config')->willReturn(true);
- $containerMock->get('config')->willReturn([
- 'events' => [
- 'regular' => [
- 'foo' => [
- 'bar',
- 'baz',
- ],
- 'something' => [
- 'some_listener',
- 'another_listener',
- 'foobar',
- ],
- ],
- ],
- ]);
- $container = $containerMock->reveal();
-
- $provider = ($this->factory)($container, '');
- $listeners = $this->getListenersFromProvider($provider);
-
- $this->assertInstanceOf(AttachableListenerProvider::class, $provider);
- $this->assertEquals([
- 'foo' => [
- lazyListener($container, 'bar'),
- lazyListener($container, 'baz'),
- ],
- 'something' => [
- lazyListener($container, 'some_listener'),
- lazyListener($container, 'another_listener'),
- lazyListener($container, 'foobar'),
- ],
- ], $listeners);
- }
-
- /** @test */
- public function configuredAsyncEventsAreProperlyAttached(): void
- {
- $server = $this->createMock(HttpServer::class); // Some weird errors are thrown if prophesize is used
-
- $containerMock = $this->prophesize(ContainerInterface::class);
- $containerMock->has('config')->willReturn(true);
- $containerMock->get('config')->willReturn([
- 'events' => [
- 'async' => [
- 'foo' => [
- 'bar',
- 'baz',
- ],
- 'something' => [
- 'some_listener',
- 'another_listener',
- 'foobar',
- ],
- ],
- ],
- ]);
- $containerMock->has(HttpServer::class)->willReturn(true);
- $containerMock->get(HttpServer::class)->willReturn($server);
- $container = $containerMock->reveal();
-
- $provider = ($this->factory)($container, '');
- $listeners = $this->getListenersFromProvider($provider);
-
- $this->assertInstanceOf(AttachableListenerProvider::class, $provider);
- $this->assertEquals([
- 'foo' => [
- asyncListener($server, 'bar'),
- asyncListener($server, 'baz'),
- ],
- 'something' => [
- asyncListener($server, 'some_listener'),
- asyncListener($server, 'another_listener'),
- asyncListener($server, 'foobar'),
- ],
- ], $listeners);
- }
-
- /** @test */
- public function ignoresAsyncEventsWhenServerIsNotRegistered(): void
- {
- $containerMock = $this->prophesize(ContainerInterface::class);
- $containerMock->has('config')->willReturn(true);
- $containerMock->get('config')->willReturn([
- 'events' => [
- 'async' => [
- 'foo' => [
- 'bar',
- 'baz',
- ],
- 'something' => [
- 'some_listener',
- 'another_listener',
- 'foobar',
- ],
- ],
- ],
- ]);
- $containerMock->has(HttpServer::class)->willReturn(false);
- $container = $containerMock->reveal();
-
- $provider = ($this->factory)($container, '');
- $listeners = $this->getListenersFromProvider($provider);
-
- $this->assertInstanceOf(AttachableListenerProvider::class, $provider);
- $this->assertEmpty($listeners);
- }
-
- private function getListenersFromProvider($provider): array
- {
- $ref = new ReflectionObject($provider);
- $prop = $ref->getProperty('listeners');
- $prop->setAccessible(true);
-
- return $prop->getValue($provider);
- }
-}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index bb78e85b..1ae25124 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -15,9 +15,6 @@
./module/CLI/test
-
- ./module/EventDispatcher/test
-
./module/PreviewGenerator/test