shlinkio / shlink-event-dispatcher
Simplifies registering async and regular PSR-14 event listeners while using RoadRunner.
Installs: 43 258
Dependents: 1
Suggesters: 0
Security: 0
Stars: 4
Watchers: 3
Forks: 1
Open Issues: 0
Requires
- php: ^8.2
- league/event: ^3.0
- psr/event-dispatcher: ^1.0
- psr/log: ^3.0
- shlinkio/shlink-config: ^3.0 || ^2.5
- shlinkio/shlink-json: ^1.0
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpstan/phpstan-phpunit: ^1.3
- phpunit/phpunit: ^11.0
- roave/security-advisories: dev-master
- shlinkio/php-coding-standard: ~2.3.0
- spiral/roadrunner-jobs: ^4.3
- symfony/var-dumper: ^7.0
Suggests
- spiral/roadrunner-jobs: To be able to run async event dispatchers as roadrunner job tasks
README
This library simplifies registering async and regular PSR-14 event listeners while using RoadRunner.
Async ones are executed using RoadRunner jobs. This library takes care of the boilerplate of registering events as async tasks/jobs, and you just interact with plain PSR-14 listeners and events.
Most of the elements it provides require a PSR-11 container, and it's easy to integrate on mezzio applications thanks to the ConfigProvider
it includes.
Install
Install this library using composer:
composer require shlinkio/shlink-event-dispatcher
This library is also a mezzio module which provides its own
ConfigProvider
. Add it to your configuration to get everything automatically set up.
Usage
This module allows to register both regular and asynchronous event listeners on a PSR-14 EventDispatcher.
Regular listeners are executed on the same process, blocking the dispatching of the HTTP request, while asynchronous listeners are delegated to a RoadRunner job, making the request to resolve immediately.
If RoadRunner is not found, async listeners are ignored by default, but you can choose to make them to be registered as regular listeners instead.
Note In order to be able to integrate with RoadRunner jobs, you need to install
spiral/roadrunner-jobs
.
In order to register listeners you have to use a configuration like this:
<?php declare(strict_types=1); return [ 'events' => [ 'regular' => [ 'foo_event' => [ App\EventListener\FooRegularListener::class, App\EventListener\AnotherFooListener::class, ], 'bar_event' => [ App\EventListener\FooRegularListener::class, ], ], 'async' => [ 'foo_event' => [ App\EventListener\FooAsyncListener::class, ], ], ], ];
The events
config entry has these blocks.
regular
: A list of events with all the listeners tha should be dispatched synchronously for each one of them.async
: A list of events with all the listeners that should be executed as RoadRunner jobs for each one of them.
In both cases, listeners are identified by their service name, making the services to be lazily resolved only when their corresponding event gets dispatched.
Dynamically skip registering listeners
Sometimes you want to provide a base list of listeners for an event, but you may want to skip them from being actually registered based on some logic known only at runtime.
For example, if you have a listener to send events to RabbitMQ, but the feature is optional and a user could have disabled it. In that case you could check at runtime if the feature is disabled, and skip the listener registration.
This module allows a Shlinkio\Shlink\EventDispatcher\Listener\EnabledListenerCheckerInterface
service to be registered, and if it resolves an instance opf that same type, it will be used to decide if listeners should be registered or not.
The service registered there has to implement this method:
public function shouldRegisterListener(string $event, string $listener, ContainerInterface $container): bool { // Do some logic to determine if $service should be registered for $event // You have access to the service container, in case external resources need to be queried // Then return `true` or `false` }
If the service is not found, or it resolves an instance of the wrong type, a default implementation is used, which registers all listeners.
public function shouldRegisterListener(string $event, string $listener, ContainerInterface $container): bool { return true; }