boson-php/event-listener-contracts
Lightweight PHP contracts for event listener components in the Boson ecosystem. Defines interfaces and shared types to standardize registering, dispatching, and handling events, helping packages stay decoupled while remaining interoperable across implementations.
Installation
composer require boson-php/event-listener-contracts
No additional configuration is required—this is a contracts-only package, meaning it defines interfaces and base classes without runtime dependencies.
First Use Case: Defining a Listener
Create a class implementing Boson\EventListenerContracts\Listener:
use Boson\EventListenerContracts\Listener;
use Boson\EventListenerContracts\Event;
class UserRegisteredListener implements Listener
{
public function handle(Event $event): void
{
// Handle the event (e.g., send welcome email)
}
}
Key Contracts to Explore
Listener: Core interface for event handlers.Event: Base event contract (extend for domain-specific events).ListenerPriority: Constants for priority-based dispatching (e.g., ListenerPriority::HIGH).$event = new UserRegisteredEvent($user);
$dispatcher->dispatch($event); // Assume a DI-bound dispatcher
class HighPriorityListener implements Listener
{
public function getPriority(): int
{
return ListenerPriority::HIGH;
}
}
$this->app->bind(
Listener::class,
fn($container) => new UserRegisteredListener()
);
Event facade with custom contracts:
event(new UserRegisteredEvent($user)); // If Event implements `Boson\EventListenerContracts\Event`
Extend Event for type safety:
class UserRegisteredEvent implements Event
{
public function __construct(public User $user) {}
}
Mock the Event contract in unit tests:
$event = $this->createMock(Event::class);
$listener = new UserRegisteredListener();
$listener->handle($event);
No Runtime Implementation:
This package defines only contracts. You must implement the dispatcher logic (e.g., using Laravel’s Event or a custom solution like symfony/event-dispatcher).
Priority Collisions:
Ensure getPriority() returns unique values (e.g., ListenerPriority::LOW, ListenerPriority::NORMAL) to avoid undefined behavior.
Event Contract Coupling:
If extending Event, ensure all listeners expect the same event structure to avoid runtime errors.
Listener Not Triggering? Verify the dispatcher is bound and the listener is registered (e.g., via tags or manual binding).
Priority Issues? Log priorities during dispatch:
$listeners = $dispatcher->getListenersFor($event);
foreach ($listeners as $listener) {
logger()->debug("Priority: {$listener->getPriority()}");
}
Custom Priorities:
Extend ListenerPriority with domain-specific constants:
final class CustomPriority extends ListenerPriority
{
public const CRITICAL = 1000;
}
Async Support: Decorate listeners to support queues:
class AsyncListenerDecorator implements Listener
{
public function __construct(private Listener $listener) {}
public function handle(Event $event): void
{
dispatch(fn() => $this->listener->handle($event));
}
}
Middleware for Events:
Use Laravel’s EventServiceProvider to filter events:
protected $listen = [
UserRegisteredEvent::class => [
'UserRegisteredListener',
],
];
How can I help you explore Laravel packages today?