0

Event::dispatch() and the EventServiceProvider

Intermediate5 min read·lv-18-003
laravel-src

Concept

Event subscribers group multiple event listeners for related events into a single class. Instead of creating separate listener classes for each event, a subscriber class defines a subscribe() method that registers which methods handle which events.

When to use subscribers: When multiple events are logically related and handled by the same "system". Example: an OrderEventSubscriber handling OrderPlaced, OrderShipped, OrderCancelled — all order lifecycle events.

Structure:

php
class OrderEventSubscriber
{
    public function handleOrderPlaced(OrderPlaced $event): void { ... }
    public function handleOrderShipped(OrderShipped $event): void { ... }

    public function subscribe(Dispatcher $events): void
    {
        $events->listen(OrderPlaced::class, [static::class, 'handleOrderPlaced']);
        $events->listen(OrderShipped::class, [static::class, 'handleOrderShipped']);
    }
}

Registering: Add to EventServiceProvider::$subscribe array.

Return array form: The subscribe() method can return an array mapping events to methods — a cleaner syntax:

php
public function subscribe(): array
{
    return [
        OrderPlaced::class => 'handleOrderPlaced',
        OrderShipped::class => 'handleOrderShipped',
    ];
}

Subscribers vs multiple listeners: Both work. Subscribers are cleaner when one class logically handles all events of a domain area. Multiple listeners are better when reactions are independent and may need different configurations (different queues, retries).

Code Example

php
<?php
namespace App\Listeners;

use App\Events\{OrderPlaced, OrderShipped, OrderCancelled, OrderRefunded};
use Illuminate\Events\Dispatcher;

class OrderEventSubscriber
{
    public function handleOrderPlaced(OrderPlaced $event): void
    {
        \Illuminate\Support\Facades\Log::info('Order placed', ['id' => $event->order->id]);
        // Send confirmation email, update CRM, etc.
    }

    public function handleOrderShipped(OrderShipped $event): void
    {
        \Illuminate\Support\Facades\Mail::to($event->order->customer)
            ->send(new \App\Mail\ShippingNotification($event->order, $event->trackingNumber));
    }

    public function handleOrderCancelled(OrderCancelled $event): void
    {
        // Restore inventory, notify warehouse
        foreach ($event->order->items as $item) {
            $item->product->increment('stock', $item->quantity);
        }
    }

    public function handleOrderRefunded(OrderRefunded $event): void
    {
        \Illuminate\Support\Facades\Log::info('Refund processed', [
            'order_id' => $event->order->id,
            'amount'   => $event->amount,
        ]);
    }

    // Register all handlers — return array form (Laravel 9+)
    public function subscribe(): array
    {
        return [
            OrderPlaced::class    => 'handleOrderPlaced',
            OrderShipped::class   => 'handleOrderShipped',
            OrderCancelled::class => 'handleOrderCancelled',
            OrderRefunded::class  => 'handleOrderRefunded',
        ];
    }

    // Alternatively — manual Dispatcher form
    // public function subscribe(Dispatcher $events): void
    // {
    //     $events->listen(OrderPlaced::class, [static::class, 'handleOrderPlaced']);
    //     $events->listen(OrderShipped::class, [static::class, 'handleOrderShipped']);
    // }
}

// EventServiceProvider
class EventServiceProvider extends \Illuminate\Foundation\Support\Providers\EventServiceProvider
{
    protected $subscribe = [
        \App\Listeners\OrderEventSubscriber::class,
        \App\Listeners\UserActivitySubscriber::class,
    ];
}