Events
After registration you need to send an email, award a bonus, record statistics. If all of that goes into the controller, it balloons. An event announces "a user registered", and listeners decide what to do about it. The main code knows nothing about them.
An event
An event is a simple class holding data:
php artisan make:event OrderPlacednamespace App\Events;
use App\Models\Order;
use Illuminate\Foundation\Events\Dispatchable;
class OrderPlaced
{
use Dispatchable;
public function __construct(public Order $order) {}
}A listener
A listener performs one action in response to an event:
php artisan make:listener SendOrderConfirmation --event=OrderPlacednamespace App\Listeners;
use App\Events\OrderPlaced;
use App\Mail\OrderConfirmation;
use Illuminate\Support\Facades\Mail;
class SendOrderConfirmation
{
public function handle(OrderPlaced $event): void
{
Mail::to($event->order->user)->queue(new OrderConfirmation($event->order));
}
}Laravel finds listeners in the app/Listeners folder by itself and ties them to an event by the parameter type of the handle() method.
Dispatching an event
use App\Events\OrderPlaced;
public function store(Request $request)
{
$order = Order::create([...]);
OrderPlaced::dispatch($order);
return redirect()->route('orders.show', $order);
}The controller only reports what happened. To add a new action you write one more listener — the controller stays untouched.
Several listeners
Any number of listeners can respond to one event:
| Listener | What it does |
|---|---|
SendOrderConfirmation | Emails the customer |
NotifyWarehouse | Tells the warehouse |
UpdateSalesStatistics | Updates the statistics |
A queued listener
A slow listener runs in the background — just add the interface:
use Illuminate\Contracts\Queue\ShouldQueue;
class NotifyWarehouse implements ShouldQueue
{
public function handle(OrderPlaced $event): void
{
// a request to the warehouse system
}
}Built-in events
Laravel fires events of its own at important moments: Registered after registration, Login on login, PasswordReset when a password changes. You subscribe to them the same way as to your own:
use Illuminate\Auth\Events\Login;
class RecordLastLogin
{
public function handle(Login $event): void
{
$event->user->update(['last_login_at' => now()]);
}
}The list of events
php artisan event:listThe command shows every event and its listeners.
Common mistake
Events make the connections in code implicit: the controller does not show that three emails go out after an order. Use them for side effects without which the main operation would still have happened. If an order cannot exist without deducting stock, that is part of the main logic — it belongs in the checkout code, not in a listener.