Laravel model observer
Laravel Observers are listeners for a model it's a listen-to event method like create, update and delete.
It can be used to modify the model or to modify any other models that are related to the model being saved or deleted, sometimes it can be used to do some actions related to the model.
Let's imagine we have a blog application, in this application, there was a post model and a comment model, and each model contains the following fields:
Post
user_id
title
slug
cover_image
content
published_at
timestamps(Laravel default)
Comment
user_id
post_id
content
timestamps(Laravel default)
And we want to do the following:
When a post is creating, we want to generate a slug for it.
When a post is updating, we want to update the slug if the title is changed.
When a post is updating, and the cover photo is changed, we want to delete the old image.
When a post is deleted, we want to delete all the comments related to it and delete the cover photo.
We can do this in the controller, but this will make the controller fat, and we will repeat the same code in the update and delete methods, so we can use the observer to do this.
To do this there were two methods:
Using the Observer class.
Using the Model Events - boot method.
Using the Observer class
Creating the observer
To create an observer we can use the following command:
php artisan make:observer PostObserver --model=Post
This will create a new observer class in the app/Observers
directory, and it will be need to registered in the EventServiceProvider
class.
<?php
namespace App\Providers;
use App\Models\Post;
use App\Observers\PostObserver;
class EventServiceProvider extends ServiceProvider
{
/**
* Register any events for your application.
*/
public function boot(): void
{
Post::observe(PostObserver::class);
}
}
Alternatively, you may list your observers within an $observers property of your applications EventServiceProvider class
namespace App\Providers;
use App\Models\Post;
use App\Observers\PostObserver;
class EventServiceProvider extends ServiceProvider
{
/**
* The model observers for your application.
*
* @var array
*/
protected $observers = [
Post::class => [PostObserver::class],
];
// ...
}
Creating the observer methods
In our generated observer class we will keep the following methods:
creating
updating
updated
deleted
<?php
namespace App\Observers;
use App\Models\Post;
class PostObserver
{
/**
* Handle the Post "creating" event.
*/
public function creating(Post $post): void
{
// ...
}
/**
* Handle the Post "updating" event.
*/
public function updating(Post $post): void
{
// ...
}
/**
* Handle the Post "updated" event.
*/
public function updated(Post $post): void
{
// ...
}
/**
* Handle the Post "deleted" event.
*/
public function deleted(Post $post): void
{
// ...
}
}
Add the logic to the observer methods
Now we can add the logic to the observer methods.
Creating the slug
To create the slug we can use the Str::slug
method, and we can use the creating
method to do this.
use Illuminate\Support\Str;
/**
* Handle the Post "creating" event.
*/
public function creating(Post $post): void
{
$post->slug = Str::slug($post->title);
}
Updating the slug and deleting the old cover photo
To update the slug we can use the Str::slug
method, and we can use the updating
method to do this, and we can use the isDirty
method to check if the title is changed.
To delete the old cover photo we can use the Storage::delete
method, and we can use the getOriginal
method to get the old cover photo.
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;
/**
* Handle the Post "updating" event.
*/
public function updating(Post $post): void
{
/**
* Update the slug if the title is changed.
*/
if ($post->isDirty('title')) {
$post->slug = Str::slug($post->title);
}
/**
* Delete the old cover photo if it's changed.
*/
if ($post->isDirty('cover_image')) {
Storage::delete($post->getOriginal('cover_image'));
}
}
Deleting the comments and the cover photo
To delete the comments we can use the delete
method, and we can use the deleted
method to do this.
To delete the cover photo we can use the Storage::delete
method.
use Illuminate\Support\Facades\Storage;
/**
* Handle the Post "deleted" event.
*/
public function deleted(Post $post): void
{
/**
* Delete the comments related to the post.
*/
$post->comments()->delete();
/**
* Delete the cover photo.
*/
Storage::delete($post->cover_image);
}
This is the full code of the observer class:
<?php
namespace App\Observers;
use App\Models\Post;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;
class PostObserver
{
/**
* Handle the Post "creating" event.
*/
public function creating(Post $post): void
{
$post->slug = Str::slug($post->title);
}
/**
* Handle the Post "updating" event.
*/
public function updating(Post $post): void
{
/**
* Update the slug if the title is changed.
*/
if ($post->isDirty('title')) {
$post->slug = Str::slug($post->title);
}
/**
* Delete the old cover photo if it's changed.
*/
if ($post->isDirty('cover_image')) {
Storage::delete($post->getOriginal('cover_image'));
}
}
/**
* Handle the Post "deleted" event.
*/
public function deleted(Post $post): void
{
/**
* Delete the comments related to the post.
*/
$post->comments()->delete();
/**
* Delete the cover photo.
*/
Storage::delete($post->cover_image);
}
}
To learn more about the observer class you can check the official documentation.
Using the Model Events - boot method
Alternatively, you may register the event listeners in the boot method of your model:
<?php
namespace App\Models;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;
class Post extends Model
{
/**
* The "booted" method of the model.
*/
protected static function booted(): void
{
parent::booted();
/**
* Handle the Post "creating" event.
*/
static::creating(function (Post $post) {
$post->slug = Str::slug($post->title);
});
/**
* Handle the Post "updating" event.
*/
static::updating(function (Post $post) {
/**
* Update the slug if the title is changed.
*/
if ($post->isDirty('title')) {
$post->slug = Str::slug($post->title);
}
/**
* Delete the old cover photo if it's changed.
*/
if ($post->isDirty('cover_image')) {
Storage::delete($post->getOriginal('cover_image'));
}
});
/**
* Handle the Post "deleted" event.
*/
static::deleted(function (Post $post) {
/**
* Delete the comments related to the post.
*/
$post->comments()->delete();
/**
* Delete the cover photo.
*/
Storage::delete($post->cover_image);
});
}
}
To learn more about the model events you can check the official documentation.
Conclusion
In this article, we learned how to use the observer class and the model events to do some actions related to the model.
In that case, if you need any help regarding this you can easily contact me from here, I will be happy to help you.
Resources
Subscribe to my newsletter
Read articles from Saiful Alam directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Saiful Alam
Saiful Alam
An Expert software engineer in Laravel and React. Creates robust backends and seamless user interfaces. Committed to clean code and efficient project delivery, In-demand for delivering excellent user experiences.