Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Event Dispatcher Contracts Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package:

    composer require symfony/event-dispatcher-contracts
    

    No configuration is needed—this package only provides interfaces and traits.

  2. 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) {}
    }
    
  3. Dispatch the Event (Laravel Hybrid): Use Laravel’s native event() helper (works with PSR-14 events):

    event(new UserRegistered('123'));
    
  4. 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
    });
    
  5. Verify Compatibility: Ensure your event class adheres to EventInterface (automatically satisfied by extending Event).


First Use Case: Shared Library

If building a library for Laravel and Symfony:

  1. Define events using only PSR-14 contracts (no Laravel-specific traits).
  2. Document that the library works with any PSR-14-compliant dispatcher.
  3. Example:
    // src/Events/UserRegistered.php
    namespace App\Events;
    
    use Symfony\Contracts\EventDispatcher\Event;
    
    final class UserRegistered extends Event
    {
        public function __construct(public readonly string $userId) {}
    }
    
  4. In Laravel, dispatch with event(); in Symfony, use symfony/event-dispatcher.

Where to Look First


Implementation Patterns

Core Workflow: Event-Driven Architecture

  1. Define Events as Value Objects:

    • Extend Symfony\Contracts\EventDispatcher\Event or implement EventInterface.
    • Use readonly properties (PHP 8.1+) for immutability.
    • Example:
      class OrderPlaced extends Event
      {
          public function __construct(
              public readonly string $orderId,
              public readonly float $total,
          ) {}
      }
      
  2. Dispatch Events:

    • Laravel Hybrid: Use event() helper (works with PSR-14 events).
      event(new OrderPlaced('ORD-123', 99.99));
      
    • PSR-14 Dispatcher: Use EventDispatcherInterface (requires bridge like spatie/laravel-psr-event-dispatcher).
      $dispatcher = app(\Spatie\LaravelPsrEventDispatcher\EventDispatcher::class);
      $dispatcher->dispatch(new OrderPlaced('ORD-123', 99.99));
      
  3. Listen to Events:

    • Laravel Listeners: Register in EventServiceProvider or use closures.
      OrderPlaced::listen(function (OrderPlaced $event) {
          // Handle order placement
      });
      
    • PSR-14 Listeners: Implement __invoke() (for Symfony compatibility).
      class SendOrderConfirmation implements \Symfony\Contracts\EventDispatcher\EventSubscriberInterface
      {
          public function __invoke(OrderPlaced $event): void
          {
              // Handle event
          }
      }
      
  4. Subscribe to Events (Optional):

    • Use 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
          }
      }
      

Integration Tips

  1. Laravel + PSR-14 Bridge:

    • Install spatie/laravel-psr-event-dispatcher to use Symfony’s EventDispatcher in Laravel.
    • Configure in config/app.php:
      'dispatcher' => \Spatie\LaravelPsrEventDispatcher\EventDispatcher::class,
      
  2. Domain-Driven Design (DDD):

    • Define events in a Domain/Events namespace, decoupled from infrastructure.
    • Example:
      /src
        /Domain
          /Events
            - UserRegistered.php
        /Infrastructure
          - EventServiceProvider.php
      
  3. Testing:

    • Mock EventDispatcherInterface in unit tests:
      $dispatcher = $this->createMock(EventDispatcherInterface::class);
      $dispatcher->expects($this->once())
          ->method('dispatch')
          ->with($this->isInstanceOf(UserRegistered::class));
      
    • Use Laravel’s Event::fake() for integration tests (if not using PSR-14 dispatcher).
  4. Cross-Framework Events:

    • Share event classes between Laravel and Symfony projects via Composer.
    • Example composer.json dependency:
      {
          "require": {
              "my-shared-events": "^1.0"
          }
      }
      
  5. Performance:

    • Avoid overusing events for simple workflows (e.g., use service methods instead).
    • Benchmark PSR-14 dispatchers vs. Laravel’s native system if performance is critical.

Laravel-Specific Patterns

  1. Hybrid Events:

    • Extend Laravel’s 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) {}
      }
      
  2. Event Broadcasting:

    • PSR-14 events can still use Laravel’s ShouldBroadcast:
      use Illuminate\Broadcasting\ShouldBroadcast;
      
      class UserRegistered extends Event implements ShouldBroadcast
      {
          // ...
      }
      
  3. Service Provider Binding:

    • Bind PSR-14 dispatchers in EventServiceProvider:
      public function boot()
      {
          $this->app->bind(EventDispatcherInterface::class, function ($app) {
              return new \Symfony\Component\EventDispatcher\EventDispatcher();
          });
      }
      

Gotchas and Tips

Pitfalls

  1. Dispatcher Mismatch:

    • Issue: Laravel’s event() helper doesn’t support PSR-14’s EventDispatcherInterface directly.
    • Fix: Use a bridge like spatie/laravel-psr-event-dispatcher or stick to Laravel’s native dispatcher for hybrid setups.
  2. Listener Signature Changes:

    • Issue: PSR-14 listeners use __invoke() instead of Laravel’s handle().
    • Fix: Update listeners to support both:
      class UserRegisteredListener
      {
          public function __invoke(UserRegistered $event): void
          {
              $this->handle($event);
          }
      
          public function handle(UserRegistered $event): void
          {
              // Laravel-compatible logic
          }
      }
      
  3. Immutable Properties:

    • Issue: PSR-14 events often use readonly properties (PHP 8.1+), which may conflict with Laravel’s SerializesModels trait.
    • Fix: Use constructor property promotion with readonly:
      class OrderPlaced extends Event
      {
          public function __construct(
              public readonly string $orderId,
              public readonly float $total,
          ) {}
      }
      
  4. Circular Dependencies:

    • Issue: Events may indirectly depend on Laravel’s Illuminate classes, breaking Symfony compatibility.
    • Fix: Keep event classes framework-agnostic (e.g., avoid use Illuminate\Support\Facades\Log).
  5. Testing Quirks:

    • Issue: Laravel’s Event::fake() won’t work with PSR-14 dispatchers.
    • Fix: Mock EventDispatcherInterface directly
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/entity-migrator
codraw/doctrine-extra
codraw/aws-tool-kit
codraw/validator
codraw/workflow
codraw/open-api
codraw/cron-job
codraw/process
codraw/log
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony