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;
});
Back to course overview · Previous: Error Handling · Next: Facades