A PSR-14 implementation which uses a Resolver to inject dependencies from a container when resolving EventListeners.
A SortingAlgorithm prioritizes event->listener Subscriptions at execution time. Priortization occurs in ListenerProvider and observes priority from highest to lowest.
This means a ListenerProvider can already have multiple Subscriptions but could add another at run time whose priority facilitates the EventListener being handled first:
<?php
$provider->add(new Subscription(Event::class, EventListener::class, 999);
Via Composer
composer require nathanburkett/event-dispatcher
Events are paired with EventListeners through Subscriptions. Subscriptions take an Event class, a Listener class, and an optional priority assignment of where the Listener should be called in relation to other Listeners for the same Event in a ListenerProvider.
ListenerProviders hold Subscriptions and are also responsible for prioritizing and resolving Listeners so their callable is consumable.
An EventDispatcher contains multiple ListenerProviders and can attach new ones before or during execution. The EventDispatcher facilitates an Event moving through the EventListener invocation pipeline and will halt further EventListener calls if the Event's propagation should be stopped.
An EventEmitter simply acts as a courier for Events making their way to an EventDispatcher.
<?php
// ContainerReflectionResolver will instantiate an EventListener by resolving any dependencies from a ContainerInterface
$resolver = new ContainerReflectionResolver($container);
// DescendingSubscriptionComparator ensures proper ordering of Subscriptions inside a SortingAlgorithm
$comparator = new DescendingSubscriptionComparator();
$sorter = new SortingAlgorithm($comparator);
$provider = new ListenerProvider($resolver, $sorter);
Then a ListenerProvider can track Subscriptions:
<?php
// SendValidateEmailMail could have a Mailer already existing in the container as a dependency in
// its constructor
$sendValidateEmail = new Subscription(NewUserRegistered::class, SendValidateEmailMail::class);
// CompleteNewUserProfile could have a ProfileRepository already existing in the container as a
// dependency in its constructor
$completeUserProfile = new Subscription(NewUserRegistered::class, CompleteNewUserProfile::class);
$provider->addSubscription($sendValidateEmail);
$provider->addSubscription($completeUserProfile);
An EventDispatcher must be made aware of the new ListenerProvider
<?php
$dispatcher = new EventDispatcher();
// or resolve an EventDispatcher singleton from container
// $dispatcher = $this->container->get(EventDispatcherInterface::class);
$dispatcher->addListenerProvider($provider);
And finally an EventEmitter needs to consume the EventDispatcher and is ready to send Events
<?php
$emitter = new EventEmitter($dispatcher);
// ...
$user = new User('Nathan Burkett', 'someemail@foobarbaz.com');
$event = new NewUserRegistered($user);
$emitter->emit($event);