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 Laravel Package

symfony/event-dispatcher

Symfony EventDispatcher lets application parts communicate via dispatched events and listeners/subscribers. It provides a flexible event system for decoupled architecture, supporting priority-based listeners and a consistent dispatching API for PHP apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require symfony/event-dispatcher
    

    Laravel already bundles this component, so no additional installation is needed if using Laravel’s built-in event system.

  2. First Use Case:

    • Create a simple event:
      namespace App\Events;
      
      class UserRegistered
      {
          public function __construct(public string $userId) {}
      }
      
    • Create a listener:
      namespace App\Listeners;
      
      use App\Events\UserRegistered;
      
      class SendWelcomeEmail
      {
          public function handle(UserRegistered $event): void
          {
              // Logic to send email
              info("Welcome email sent to user {$event->userId}");
          }
      }
      
    • Register the listener in EventServiceProvider (Laravel):
      protected $listen = [
          UserRegistered::class => [
              SendWelcomeEmail::class,
          ],
      ];
      
    • Dispatch the event:
      use App\Events\UserRegistered;
      use Illuminate\Support\Facades\Event;
      
      Event::dispatch(new UserRegistered('user-123'));
      
  3. Where to Look First:


Implementation Patterns

Core Workflows

  1. Event-Driven Architecture (EDA):

    • Use events to decouple components (e.g., OrderCreated triggers InventoryUpdate and NotificationSent).
    • Example:
      // Dispatch an event
      Event::dispatch(new OrderCreated($orderId));
      
      // Listen to it
      class UpdateInventory {
          public function handle(OrderCreated $event) {
              Inventory::reduceStock($event->orderId);
          }
      }
      
  2. Priority-Based Execution:

    • Control listener order with priorities (higher numbers execute first):
      protected $listen = [
          OrderCreated::class => [
              [UpdateInventory::class, 10], // Low priority
              [LogOrder::class, 20],       // High priority
          ],
      ];
      
  3. Stopping Event Propagation:

    • Halt further listeners for an event:
      class ValidateOrder {
          public function handle(OrderCreated $event) {
              if (!$event->isValid()) {
                  $event->stopPropagation(); // Stops other listeners
              }
          }
      }
      
  4. Event Subscribers:

    • Group related listeners in a subscriber class:
      class OrderSubscriber implements ShouldRegister {
          public static function getSubscribedEvents(): array
          {
              return [
                  OrderCreated::class => 'handleOrderCreated',
                  OrderCancelled::class => 'handleOrderCancelled',
              ];
          }
      
          public function handleOrderCreated(OrderCreated $event) { /* ... */ }
      }
      
  5. Dynamic Registration:

    • Register listeners at runtime (e.g., for plugins or modular apps):
      $dispatcher = app(EventDispatcher::class);
      $dispatcher->addListener(OrderCreated::class, function ($event) {
          // Dynamic logic
      });
      

Laravel Integration Tips

  • Use Laravel’s Artisan Commands:
    php artisan make:event UserRegistered
    php artisan make:listener SendWelcomeEmail --event=UserRegistered
    
  • Service Provider Binding: Bind Symfony’s EventDispatcher to Laravel’s container in AppServiceProvider:
    public function register(): void
    {
        $this->app->singleton(EventDispatcher::class, function () {
            return new EventDispatcher();
        });
    }
    
  • Leverage Laravel’s Event Facade:
    use Illuminate\Support\Facades\Event;
    
    Event::dispatch(new UserRegistered('user-123'));
    Event::listen(OrderCreated::class, UpdateInventory::class);
    

Advanced Patterns

  1. Event Filtering:

    • Use #[AsEventListener] (PHP 8+) for type-safe filtering:
      #[AsEventListener(event: UserRegistered::class, method: 'handle')]
      class SendWelcomeEmail { /* ... */ }
      
    • Filter by method parameters:
      #[AsEventListener(event: UserRegistered::class, method: 'handle', priority: 20)]
      class LogUserRegistration { /* ... */ }
      
  2. Event Decorators:

    • Wrap listeners to add cross-cutting concerns (e.g., logging, caching):
      $dispatcher->addSubscriber(new LoggingSubscriber());
      
  3. Async Event Handling:

    • Dispatch events to queues for background processing:
      Event::dispatchSync(new UserRegistered('user-123')); // Sync
      Event::dispatch(new UserRegistered('user-123'));     // Async (default in Laravel)
      

Gotchas and Tips

Pitfalls

  1. Memory Leaks:

    • Issue: Long-running processes (e.g., CLI scripts) may leak memory with TraceableEventDispatcher.
    • Fix: Use EventDispatcher (non-traceable) for CLI or reset the dispatcher periodically:
      $dispatcher->removeListener(OrderCreated::class, $listener);
      
    • Laravel Tip: Avoid TraceableEventDispatcher in queues/CLI unless debugging.
  2. Listener Order Chaos:

    • Issue: Unintended listener execution order due to missing priorities.
    • Fix: Always define priorities explicitly:
      protected $listen = [
          OrderCreated::class => [
              [UpdateInventory::class, 10], // Explicit priority
          ],
      ];
      
  3. Stopping Events Prematurely:

    • Issue: stopPropagation() halts all listeners, including critical ones.
    • Fix: Use stopPropagation() sparingly. Prefer conditional logic or separate events.
  4. Circular Dependencies:

    • Issue: Listeners dispatching events that trigger other listeners, creating loops.
    • Fix: Use TraceableEventDispatcher to debug or refactor into separate workflows.
  5. Performance Overhead:

    • Issue: Excessive listeners slow down event dispatching.
    • Fix: Profile with TraceableEventDispatcher and remove unused listeners.

Debugging Tips

  1. Enable Event Tracing:

    • Use TraceableEventDispatcher to log all dispatched events:
      $dispatcher = new TraceableEventDispatcher();
      $dispatcher->addListener(OrderCreated::class, function () {
          // Your logic
      });
      
    • Check traces with:
      $dispatcher->getTraces();
      
  2. Listener Not Firing:

    • Check:
      • Event class name matches exactly (case-sensitive).
      • Listener is registered in EventServiceProvider or via #[AsEventListener].
      • No typos in method names or class paths.
    • Debug:
      $dispatcher->hasListeners(OrderCreated::class); // Check if listeners exist
      $dispatcher->getListenersFor(OrderCreated::class); // List all listeners
      
  3. Priority Conflicts:

    • Debug:
      $listeners = $dispatcher->getListenersFor(OrderCreated::class);
      usort($listeners, fn ($a, $b) => $b['priority'] <=> $a['priority']);
      print_r($listeners); // Verify order
      

Configuration Quirks

  1. Laravel’s Event Dispatcher:

    • Laravel wraps Symfony’s EventDispatcher in its own Dispatcher class. Use Laravel’s facade (Event) for consistency:
      // Avoid direct Symfony calls in Laravel:
      // ❌ $dispatcher = app(EventDispatcher::class);
      // ✅ Event::dispatch(new UserRegistered());
      
  2. Service Provider Binding:

    • If extending Laravel’s event system, bind Symfony’s dispatcher after Laravel’s:
      $this->app->afterResolving(EventDispatcher::class, function ($dispatcher) {
          $dispatcher->addSubscriber(new CustomSubscriber());
      });
      
  3. PHP 8 Attributes:

    • For #[AsEventListener], ensure:
      • PHP 8.0+ is used.
      • The symfony/event-dispatcher version supports attributes (v6.0+).
      • Attributes are imported:
        use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
        

Extension Points

  1. Custom EventDispatcher:

    • Extend EventDispatcher to add features (e.g., rate limiting):
      class RateLimitedEventDispatcher extends EventDispatcher {
          public function dispatch($event, $propagationStopped = null) {
              if (!$this->isAllowed($event)) {
                  return;
              }
              parent::dispatch($event, $propagationStopped);
          }
      }
      
  2. Event Normalization:

    • Convert Laravel events to/from Symfony events for interoperability:
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/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
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