Skip to main content
Event Handling

Event Handling

Events decouple the action that happened from the work that follows. A controller can announce that an order was paid, and separate listeners can send receipts, update analytics, and notify a warehouse without the controller knowing about any of them.

Creating an event and listener

php artisan make:event OrderPaid
php artisan make:listener SendOrderReceipt --event=OrderPaid
namespace App\Events;

use App\Models\Order;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderPaid
{
    use Dispatchable, SerializesModels;

    public function __construct(public Order $order)
    {
    }
}
namespace App\Listeners;

use App\Events\OrderPaid;
use App\Mail\OrderReceipt;
use Illuminate\Support\Facades\Mail;

class SendOrderReceipt
{
    public function handle(OrderPaid $event): void
    {
        Mail::to($event->order->user)->queue(new OrderReceipt($event->order));
    }
}

Dispatching

use App\Events\OrderPaid;

event(new OrderPaid($order));

// or
OrderPaid::dispatch($order);

Registering listeners

Laravel discovers listeners automatically when event discovery is enabled. You can also map events to listeners explicitly, which is useful in larger applications.

use Illuminate\Support\Facades\Event;

Event::listen(OrderPaid::class, SendOrderReceipt::class);

Queued listeners

Listeners that call external services should implement ShouldQueue. The web request returns quickly, and retries are handled by the queue worker.

use Illuminate\Contracts\Queue\ShouldQueue;

class SyncOrderToErp implements ShouldQueue
{
    public int $tries = 3;

    public function handle(OrderPaid $event): void
    {
        // push to the ERP
    }
}

Subscribers

A subscriber groups several listeners in one class and maps each event explicitly.

class OrderSubscriber
{
    public function handleOrderPaid(OrderPaid $event): void { /* ... */ }

    public function handleOrderRefunded(OrderRefunded $event): void { /* ... */ }

    public function subscribe(Dispatcher $events): void
    {
        $events->listen(OrderPaid::class, [self::class, 'handleOrderPaid']);
        $events->listen(OrderRefunded::class, [self::class, 'handleOrderRefunded']);
    }
}

When to use events

Use events when several independent reactions follow one action, or when a package should be able to hook into your application. Do not replace direct method calls with events just for style; a controller calling a service method is easier to follow when there is only one reaction.

Testing events

Event::fake([OrderPaid::class]);

$this->post('/orders', $payload);

Event::assertDispatched(OrderPaid::class, function (OrderPaid $event) {
    return $event->order->total === 4999;
});