Home About Skills Products Work
Projects Services Experience
Learn
Tutorials Courses Blogs Resources
Contact
Blog · Laravel

Laravel Events and Listeners: Decoupling Your Application Logic

Laravel Events and Listeners: Decoupling Your Application Logic
Advertisement

Events and listeners let different parts of a Laravel application react to something happening without directly calling each other — the moment "when a user registers, send a welcome email AND notify Slack AND update analytics" starts piling unrelated logic into one controller method, events are the fix.

Defining an Event

php artisan make:event UserRegistered
class UserRegistered
{
    use Dispatchable, SerializesModels;

    public function __construct(public User $user) {}
}

An event is just a plain data-carrying class — it describes something that happened, nothing more.

Creating a Listener

php artisan make:listener SendWelcomeEmail --event=UserRegistered
class SendWelcomeEmail
{
    public function handle(UserRegistered $event): void
    {
        Mail::to($event->user)->send(new WelcomeMail($event->user));
    }
}

Registering the Mapping

// AppServiceProvider or a dedicated EventServiceProvider
Event::listen(UserRegistered::class, SendWelcomeEmail::class);
Event::listen(UserRegistered::class, NotifySlackChannel::class);
Event::listen(UserRegistered::class, UpdateAnalytics::class);

One event, three independent listeners — none of them know the others exist. Adding a fourth reaction to registration means writing one new listener class and one new registration line, never touching the registration controller itself.

Dispatching the Event

class RegisterController extends Controller
{
    public function store(Request $request)
    {
        $user = User::create($request->validated());
        event(new UserRegistered($user));
        return redirect('/dashboard');
    }
}

The controller stays entirely focused on "create the user, dispatch the event" — it has zero knowledge of email, Slack, or analytics.

Queueing Listeners

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        Mail::to($event->user)->send(new WelcomeMail($event->user));
    }
}

Implementing ShouldQueue on a listener is all it takes — Laravel automatically pushes that listener's execution onto a queue instead of running it synchronously during the request, so a slow SMTP provider never delays the actual HTTP response.

Testing Without Firing Real Listeners

Event::fake();

$this->post('/register', [...]);

Event::assertDispatched(UserRegistered::class);

Event::fake() intercepts every dispatched event during a test, letting you assert the RIGHT event fired without actually sending real emails or hitting a real Slack webhook — decoupled code is also, not coincidentally, much easier code to test.

Laravel for Beginners: Setting Up Your First Project

Laravel for Beginners: Setting Up Your First Project

A complete first-day guide to Laravel — installation, folder structure, your first route, and your first migration.

Building a REST API with Laravel: A Complete Guide

Building a REST API with Laravel: A Complete Guide

API routes, resources, Form Request validation, correct status codes, and Sanctum auth — a real, production-reasonable Laravel API.

Laravel Eloquent Relationships Explained with Real Examples

Laravel Eloquent Relationships Explained with Real Examples

One-to-many, many-to-many, polymorphic, and the N+1 query trap that catches almost every Laravel developer at least once.

Esc