Master Laravel's event system to decouple logic, improve testability, and scale your application with event listeners, subscribers, and broadcasting.
Laravel’s event system allows you to build highly decoupled applications where logic can be neatly separated, extended, and scaled. This approach shines when triggering multiple reactions from a single action - like sending emails, logging activity, and queuing background jobs after a purchase.
Why Use Events?
Event-driven design:
- Decouples logic – keeps core actions lean
- Improves testability – listeners can be tested in isolation
- Enhances scalability – listeners can run synchronously or via queues
- Encourages SRP – each listener handles a single job
Basic Event + Listener
Generate both:
php artisan make:event OrderPlaced
php artisan make:listener SendOrderConfirmation --event=OrderPlaced
Event
<?php
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class OrderPlaced implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(public Order $order)
{
}
}
Listener
class SendOrderConfirmation
{
public function handle(OrderPlaced $event)
{
Mail::to($event->order->user)->send(new OrderConfirmation($event->order));
}
}
Register in EventServiceProvider.php:
protected $listen = [
OrderPlaced::class => [
SendOrderConfirmation::class,
LogOrderActivity::class,
QueueAnalyticsEvent::class,
],
];
Dispatching Events
Anywhere in your app:
OrderPlaced::dispatch($order);
Or use the helper:
event(new OrderPlaced($order));
Listener Queues for Performance
Use queued listeners:
class QueueAnalyticsEvent implements ShouldQueue
{
public function handle(OrderPlaced $event)
{
Analytics::track('order_placed', [
'order_id' => $event->order->id,
'user_id' => $event->order->user_id,
]);
}
}
Queue config lives in config/queue.php. Monitor it with Horizon.
Event Subscribers for Clean Grouping
Subscribers let you group multiple listeners in one class:
class UserEventSubscriber
{
public function onLogin($event)
{
// log or notify
}
public function onLogout($event)
{
// track session end
}
public function subscribe(Dispatcher $events)
{
$events->listen(Login::class, [self::class, 'onLogin']);
$events->listen(Logout::class, [self::class, 'onLogout']);
}
}
Register in EventServiceProvider.php:
protected $subscribe = [
UserEventSubscriber::class,
];
Broadcasting Events
Broadcast events via Pusher, Ably, or Redis:
class OrderPlaced implements ShouldBroadcast
{
public function broadcastOn()
{
return new PrivateChannel('orders.'.$this->order->id);
}
}
Enable broadcasting in config/broadcasting.php, set up a frontend listener with Laravel Echo:
Echo.private(`orders.${orderId}`)
.listen('OrderPlaced', (e) => {
console.log('New order broadcast received', e);
});
Best Practices
- Use event names that reflect domain actions (e.g.
OrderShipped,InvoiceGenerated) - Keep listeners focused and lean
- Queue heavy work like notifications, analytics, or third-party calls
- Test events and listeners in isolation
- Monitor your queues with Horizon or Telescope
Real-World Application
In the high-performance Laravel ecommerce project, we used events to:
- Queue order processing steps
- Broadcast inventory updates
- Log user activity asynchronously