nathanburkett/event-dispatcher

PSR-14 Event Dispatcher implementation

0.2.0 2019-05-12 18:17 UTC

This package is auto-updated.

Last update: 2024-04-15 12:19:17 UTC


README

CircleCI codecov

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);

Installation

Via Composer

composer require nathanburkett/event-dispatcher

Usage

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.

Basic Implementation

<?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);