symfony/event-dispatcher-contracts
Defines lightweight, version-stable contracts for Symfony’s EventDispatcher: interfaces and abstractions shared across components. Use it to type-hint and build compatible event dispatching integrations with proven Symfony semantics without pulling full implementations.
Install the Package:
composer require symfony/event-dispatcher-contracts
No configuration is needed—this package only provides interfaces and traits.
Define a PSR-14 Event:
Create a class extending Symfony\Contracts\EventDispatcher\Event:
namespace App\Events;
use Symfony\Contracts\EventDispatcher\Event;
class UserRegistered extends Event
{
public function __construct(public readonly string $userId) {}
}
Dispatch the Event (Laravel Hybrid):
Use Laravel’s native event() helper (works with PSR-14 events):
event(new UserRegistered('123'));
Listen to the Event (Laravel):
Register a listener in EventServiceProvider:
protected $listen = [
UserRegistered::class => [
\App\Listeners\UserRegisteredListener::class,
],
];
Or use closures:
event(new UserRegistered('123'))->listen(function (UserRegistered $event) {
// Handle event
});
Verify Compatibility:
Ensure your event class adheres to EventInterface (automatically satisfied by extending Event).
If building a library for Laravel and Symfony:
// src/Events/UserRegistered.php
namespace App\Events;
use Symfony\Contracts\EventDispatcher\Event;
final class UserRegistered extends Event
{
public function __construct(public readonly string $userId) {}
}
event(); in Symfony, use symfony/event-dispatcher.EventInterface, EventDispatcherInterface.spatie/laravel-psr-event-dispatcher (for full PSR-14 dispatching).Define Events as Value Objects:
Symfony\Contracts\EventDispatcher\Event or implement EventInterface.readonly properties (PHP 8.1+) for immutability.class OrderPlaced extends Event
{
public function __construct(
public readonly string $orderId,
public readonly float $total,
) {}
}
Dispatch Events:
event() helper (works with PSR-14 events).
event(new OrderPlaced('ORD-123', 99.99));
EventDispatcherInterface (requires bridge like spatie/laravel-psr-event-dispatcher).
$dispatcher = app(\Spatie\LaravelPsrEventDispatcher\EventDispatcher::class);
$dispatcher->dispatch(new OrderPlaced('ORD-123', 99.99));
Listen to Events:
EventServiceProvider or use closures.
OrderPlaced::listen(function (OrderPlaced $event) {
// Handle order placement
});
__invoke() (for Symfony compatibility).
class SendOrderConfirmation implements \Symfony\Contracts\EventDispatcher\EventSubscriberInterface
{
public function __invoke(OrderPlaced $event): void
{
// Handle event
}
}
Subscribe to Events (Optional):
EventSubscriberInterface for bulk event handling:
class OrderSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
OrderPlaced::class => 'handleOrderPlaced',
];
}
public function handleOrderPlaced(OrderPlaced $event): void
{
// Logic
}
}
Laravel + PSR-14 Bridge:
spatie/laravel-psr-event-dispatcher to use Symfony’s EventDispatcher in Laravel.config/app.php:
'dispatcher' => \Spatie\LaravelPsrEventDispatcher\EventDispatcher::class,
Domain-Driven Design (DDD):
Domain/Events namespace, decoupled from infrastructure./src
/Domain
/Events
- UserRegistered.php
/Infrastructure
- EventServiceProvider.php
Testing:
EventDispatcherInterface in unit tests:
$dispatcher = $this->createMock(EventDispatcherInterface::class);
$dispatcher->expects($this->once())
->method('dispatch')
->with($this->isInstanceOf(UserRegistered::class));
Event::fake() for integration tests (if not using PSR-14 dispatcher).Cross-Framework Events:
composer.json dependency:
{
"require": {
"my-shared-events": "^1.0"
}
}
Performance:
Hybrid Events:
Event class and implement PSR-14 contracts:
use Illuminate\Queue\SerializesModels;
use Symfony\Contracts\EventDispatcher\Event;
class UserRegistered extends Event
{
use SerializesModels; // For Laravel queues
public function __construct(public readonly User $user) {}
}
Event Broadcasting:
ShouldBroadcast:
use Illuminate\Broadcasting\ShouldBroadcast;
class UserRegistered extends Event implements ShouldBroadcast
{
// ...
}
Service Provider Binding:
EventServiceProvider:
public function boot()
{
$this->app->bind(EventDispatcherInterface::class, function ($app) {
return new \Symfony\Component\EventDispatcher\EventDispatcher();
});
}
Dispatcher Mismatch:
event() helper doesn’t support PSR-14’s EventDispatcherInterface directly.spatie/laravel-psr-event-dispatcher or stick to Laravel’s native dispatcher for hybrid setups.Listener Signature Changes:
__invoke() instead of Laravel’s handle().class UserRegisteredListener
{
public function __invoke(UserRegistered $event): void
{
$this->handle($event);
}
public function handle(UserRegistered $event): void
{
// Laravel-compatible logic
}
}
Immutable Properties:
readonly properties (PHP 8.1+), which may conflict with Laravel’s SerializesModels trait.readonly:
class OrderPlaced extends Event
{
public function __construct(
public readonly string $orderId,
public readonly float $total,
) {}
}
Circular Dependencies:
Illuminate classes, breaking Symfony compatibility.use Illuminate\Support\Facades\Log).Testing Quirks:
Event::fake() won’t work with PSR-14 dispatchers.EventDispatcherInterface directlyHow can I help you explore Laravel packages today?