Model Events in Eloquent: A Comprehensive Guide

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

Introduction

Eloquent, the ORM included with Laravel, provides a simple and elegant way to work with your database. But its power isn’t limited to just creating, retrieving, updating, and deleting records; it also boasts a feature called model events, which allows you to hook into various points of a model’s lifecycle. In this comprehensive guide, we’ll delve into the world of Eloquent model events, providing you with the understanding you need to harness this feature to its full potential.

Understanding Model Events

Model events are triggered at specific moments in the lifecycle of a model instance. These include events like ‘creating’, ‘created’, ‘updating’, ‘updated’, ‘saving’, ‘saved’, ‘deleting’, ‘deleted’, ‘restoring’, and ‘restored’. You can set up listeners for these events to execute code at any of these points.

For instance, imagine you want to clear a cache whenever a Post is updated. You could hook into the ‘updated’ event for your Post model to do this automatically.

use App\Models\Post; // Make sure to include the appropriate namespace
use Illuminate\Support\Facades\Cache;

Post::updated(function ($post) {
    Cache::forget("posts_cache");
});

Registering Event Listeners

To listen for model events, you can either define them inside your model or within an event service provider. Inside your model, you may use the boot method to attach your event listeners.

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;

class Post extends Model
{
    protected static function boot()
    {
        parent::boot();

        static::created(function ($post) {
            Log::info('Post created: ' . $post->title);
        });
    }
}

Alternatively, you can use an EventServiceProvider to clean up your model’s code. This is where you can define listeners for your model events.

use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        'App\Events\SomeEvent' => [
            'App\Listeners\SomeListener',
        ],
        'eloquent.created:App\Post' => [
            'App\Listeners\EmailPostCreatedNotification',
        ],
    ];
}

Event Observers

For those who prefer to keep their models lean and focused, Eloquent provides observers. An observer class can hold listener methods for multiple event types. Below is an example of an observer class for our Post model.

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;

class PostObserver
{
    public function created(Post $post)
    {
        // Handle the "created" event.
        Log::info('Post created: ' . $post->title);
    }

    public function updated(Post $post)
    {
        // Handle the "updated" event.
        Cache::forget("posts_cache");
    }
}

After defining your observer, you need to register it within the boot method of a service provider, preferably EventServiceProvider.

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

Cancelling Events

Sometimes you may wish to abort an event operation, such as preventing a model from being saved or deleted. To do this, you can return false from your event’s listener.

Post::deleting(function ($post) {
    if ($post->is_locked) {
        return false;
    }
});

Using Model Dispatch Methods

Laravel 5.5 introduced the dispatch methods for model events, which simplifies the process of firing custom events for your models. You can call these methods directly on your model instances when you need to trigger events manually.

$post->dispatchesEvents = [
    'saving' => PostSaving::class,
    'saved'  => PostSaved::class,
];

$post->save();

Custom Events

You are not limited to the default Eloquent events. Eloquent’s model has a method called fireModelEvent that allows you to create and handle custom events.

protected function fireCustomEvent()
{
    if ($this->fireModelEvent('customEvent') === false) {
        return false;
    }
    
    // Custom logic here
}

Events and Queues

Intensive tasks triggered through model events, like sending emails, can be queued up to improve your application’s performance. You can do this easily by implementing the ShouldQueue interface in your event listener.

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class SomeIntensiveTaskListener implements ShouldQueue
{
    use InteractsWithQueue;

    public function handle()
    {
        // Implement handle() with your logic.
    }
}

See also:

Conclusion

Model events in Eloquent are powerful tools for maintaining clean code and reactivity within your application. By efficiently utilizing these events, you can keep your controllers slim and models clean, leading to an organized codebase. Don’t shy away from using these events; they can greatly improve your workflow and application logic.