Overview
Description
Caldera Events is a PSR-14
event dispatcher implementation.
As with the other Caldera components it has been built to be swappable and modular.
Installation
The easisest way to install it is to use Composer:
composer require vecode/caldera-events
Requires
php: >=8.1
ext-mbstring: *
psr/container: ^2.0
psr/event-dispatcher: ^1.0
Basic usage
Getting started
Events are a handy way of connecting components in an application so that they can react to certain actions. For example, sending an email when a new user account is created.
To that end, PSR-14
defines a common interface to create an extendable event dispatcher and this component offers a simple implementation.
Its usage is very straightforward, but it revolves around three components, the ListenerProvider
, an EventDispatcher
and an Event class.
The ListenerProvider
implements ListenerProviderInterface
and it is used to keep track of the listeners and then retrieve them for an specific Event; creating one is simple:
use Caldera\Events\ListenerProvider;
$listener_provider = new ListenerProvider();
Now, to start adding listeners you must define your event class. Event classes aren't bound to an specific interface, so you can have as many members/methods as you want, for example:
class TestEvent {
protected string $value;
function __construct(string $value) {
$this->value = $value;
}
public function getValue(): string {
return $this->value;
}
}
Adding listeners
Once you've defined your Event class, you can add a listener to your ListenerProvider
instance:
use Caldera\Events\ListenerProvider;
$listener_provider = new ListenerProvider();
$listener_provider->add(TestEvent::class, function(TestEvent $event) {
// Do something with $event
});
A listener can be a simple Closure
that receives the $event
object; however internally they are bound using the CallableListener
class, as all listeners must implement ListenerInterface
.
You can also create your own ListenerInterface
implementations:
class TestListener implements ListenerInterface {
public function handle(object $event): void {
// Do something with $event
}
}
As you can see, the only difference is the $event
type, as the Closure
allows precise typing.
To use them just pass the class name:
use Caldera\Events\ListenerProvider;
$listener_provider = new ListenerProvider();
$listener_provider->add(TestEvent::class, TestListener::class);
Dispatching events
To dispatch events you will need an EventDispatcher
; creating one is simple and you just need your ListenerProvider
instance:
use Caldera\Events\ListenerProvider;
use Caldera\Events\EventDispatcher;
$listener_provider = new ListenerProvider();
$listener_provider->add(TestEvent::class, TestListener::class);
$dispatcher = new EventDispatcher($listener_provider);
These two objects (the ListenerProvider
and EventDispatcher
) are best kept inside a DI container, so we recommend using a PSR-11
implementation for this, as you will need to resolve your EventDispatcher
from the classes that trigger the events.
For example, to dispatch a TestEvent
you can do:
use Caldera\Events\EventDispatcher;
$dispatcher = resolve(EventDispatcher::class); // where resolve uses your DI container to resolve the service instance
$event = new TestEvent('foo');
$dispatcher->dispatch($event);
Or better yet, with dependency injection:
use Caldera\Events\EventDispatcher;
class ClassThatDispatchesTestEvent {
protected EventDispatcher $dispatcher;
public function __construct(EventDispatcher $dispatcher) {
$this->dispatcher = $dispatcher;
}
public function doSomething(string $value) {
$event = new TestEvent($value);
$this->dispatcher->dispatch($event);
}
}
That way the dependency is clear and handled automatically by the container, just make sure your container implementation supports dependency injection.
You can also create your own specialized EventDispatcher
and/or ListenerProvider
classes to handle specific events or provide specific listeners; just extend these classes or implement directly the interfaces.
Stoppable events
For example, the PSR-14
defines an special event type that can be stopped through the StoppableEventInterface
which StoppableEvent
implements.
To use it your events must extend that class:
use Caldera\Events\Event\StoppableEvent;
class TestEvent extends StoppableEvent {
// Event logic
}
And in your listeners just call the stopPropagation
method to stop any further propagation:
$listener_provider->add(TestEvent::class, function(TestEvent $event) {
$event->stopPropagation();
});
Remember that you can always create your own event types with custom logic, for example, one-time events or anything that you may need for your particular application.