How to define and use observers in Eloquent

Updated: January 16, 2024 By: Guest Contributor Post a comment

Introduction

When working with Eloquent in Laravel, you often need to execute certain actions during various stages of the model’s lifecycle, such as creating, updating, or deleting records. The Eloquent Observer class provides a convenient method to hook into these lifecycle events, allowing you to keep your code clean and maintainable. In this tutorial, we’ll explore how to define and use observers in Eloquent through a series of examples, ranging from basic to advanced.

Eloquent Observer: The Basics

An Eloquent Observer is a class where you can define methods to listen to various Eloquent events. These events allow you to perform actions before or after operations such as creating, updating, saving, deleting, restoring, and more on a model. By harnessing these methods, you can refactor repetitive code out of your models and ensure a separation of concerns within your application’s architecture.

Defining an Eloquent Observer

<?php

namespace App\Observers;

use App\Models\User;

class UserObserver
{
    public function creating(User $user)
    {
        // Logic before a user record is created
    }

    public function created(User $user)
    {
        // Logic after a user record is created
    }

    // Other model events...
}

Registering an Eloquent Observer

To register an observer, you’ll typically do so within the boot method of one of your service providers, usually the AppServiceProvider. You’ll use the observe method on the model to attach the observer class.

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Models\User;
use App\Observers\UserObserver;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        User::observe(UserObserver::class);
    }
}

Observer Methods

Here are the methods you can define within an observer:

  • retrieved
  • creating
  • created
  • updating
  • updated
  • saving
  • saved
  • deleting
  • deleted
  • restoring
  • restored

Example: Automatic Timestamps

This example demonstrates how to automatically set a timestamp on a custom field whenever a record is saved or updated.

<?php

namespace App\Observers;

use App\Models\Post;

class PostObserver
{
    public function saving(Post $post)
    {
        $post->last_action_at = now();
    }
}

In your AppServiceProvider, you would attach this observer to the Post model:

<?php

namespace App\Providers;

use App\Models\Post;
use App\Observers\PostObserver;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Post::observe(PostObserver::class);
    }
}

Advanced Observer Usage

Dependency Injection

Observers can also receive dependencies through dependency injection. For instance, if you need to send an email after a user registers, you could inject a mailer service into your observer.

<?php

namespace App\Observers;

use App\Models\User;
use Illuminate\Mail\Mailer;

class UserObserver
{
    protected $mailer;

    public function __construct(Mailer $mailer)
    {
        $this->mailer = $mailer;
    }

    public function created(User $user)
    {
        // Send email...
    }
}

Using Observers with Queues

If you need to perform time-consuming tasks, like sending an email, you should queue those tasks to make your application more responsive. Here’s how you could queue a mail job within an observer method.

<?php

namespace App\Observers;

use App\Jobs\SendWelcomeEmail;
use App\Models\User;

class UserObserver
{
    public function created(User $user)
    {
        dispatch(new SendWelcomeEmail($user));
    }
}

Caveats and Considerations

While observers can improve code maintainability, they also introduce a level of indirection which can make code harder to trace. Be sure also to consider the implications of using observers, such as the potential for recursion when an observer triggers another event unintentionally.

Conclusion

Observers in Eloquent present an elegant way of handling model lifecycle events in a Laravel application. They are easy to implement, and when used appropriately, can lead to more maintainable and extensible code. As with any design pattern, it’s essential to use them judiciously to fully reap the benefits.