How to Use Model Observers in Laravel

Laravel 3 mins read

Table of Content

    Introduction

    Laravel's Eloquent OM is the rock-solid implementation of Active Record. It has many features includes Observers, Laravel implements Observer Pattern to fire some events, which can be listened to hook into, when various actions are performed on a model.

    Requisite

    You must have the least basic knowledge in laravel and how to generate models and knowledge in MVC Pattern and PHP in general.

    Laravel Model Events

    If you worked before in a medium to large scale project with laravel, you may notice you need to fire an event in some situation to keep your project nice and clean and easy to maintain. One of the Events in laravel is Model Events, that let you do some actions after the model saved, saving ...

    Let's take an example, imagine You have Article model, and you want to set a slug automatically to saving the article. Instead of setting the slug when the articles got saved:

    Article::create([
        'title'  => $name,
        'slug'  => Str::slug($name),
    ]);
    

    You can do the following:

    use Illuminate\Support\Str;
    
    class Article extends Model
    {
        ...
    
        protected static function boot()
        {
            parent::boot();
    
            static::saving( function ($model) {
                $model->slug = Str::slug($model->title);
            })
        }
    }
    

    This method is very straight forward, because if you have a multiple models requires a slug, you can a single Trait and use this method into it and implement the trait in every model requires a slug to be filled. I hope you got the idea.

    The saving event is one of the provided events that Eloquent provides:

    • retrieved: after a record has been retrieved.
    • creating: before a record has been created.
    • created: after a record has been created.
    • updating: before a record is updated.
    • updated: after a record has been updated.
    • saving: before a record is saved (either created or updated).
    • saved: after a record has been saved (either created or updated).
    • deleting: before a record is deleted or soft-deleted.
    • restoring: before a soft-deleted record is going to be restored
    • restored: after a soft-deleted record has been restored.

    You can use any of the methods listed above like we did before with saving

    Laravel Model Observers

    If you are planing to use more than one of the listed events above (depend on of your project), it is not a good idea to place all of them in your model. Laravel solved you issue and provided you with observer command to generate class contain all the available events, you can generate observer class like so:

    php artisan make:observer ArticleObserver --model=Article
    

    As the command tell, you are generating an observer class for the article model, and you can change it to the needed model.

    The generated Observer leaves in app/Observers folder and contain the code below:

    namespace App\Observers;
    
    use App\Models\Post;
    
    class PostObserver
    {
        /**
         * Handle the article "created" event.
         *
         * @param  \App\Models\Article  $article
         * @return void
         */
        public function created(Article $article)
        {
            //
        }
    
        /**
         * Handle the article "updated" event.
         *
         * @param  \App\Models\Article  $article
         * @return void
         */
        public function updated(Article $article)
        {
            //
        }
    
        /**
         * Handle the article "deleted" event.
         *
         * @param  \App\Models\Article  $article
         * @return void
         */
        public function deleted(Article $article)
        {
            //
        }
    
        /**
         * Handle the article "restored" event.
         *
         * @param  \App\Models\Article  $article
         * @return void
         */
        public function restored(Article $article)
        {
            //
        }
    
        /**
         * Handle the article "force deleted" event.
         *
         * @param  \App\Models\Article  $article
         * @return void
         */
        public function forceDeleted(Article $article)
        {
            //
        }
    }
    

    After the observer class generated successfully you need to register it inside AppServiceProvider in app/Providers/AppServiceProvider folder inside the boot() method

    ...
    public function boot()
    {
        Article::observe(ArticleObserver::class);
    }
    ...
    

    Now we have successfully added a model observer to Article model, and you are good to go with your application.

    Real Life Example

    Some of you see the explanation above and other not (including me) so, we will build a small application to show you how to use them properly.

    Now, we have a User model (came by default in laravel) and Article model generated before, normally the user have many articles and let's assume we deleted the user from our records, well. There're many scenarios on how to deal with the articles created by the deleted user but, let's delete his/her article as well.

    You may want to define the relationship first:

    class User extends Model
    {
        public function articles()
        {
            return $this->hasMany(Article::class);
        }
    }
    

    Let's generate a new User Observer

    php artisan make:observer UserObserver --model=User
    

    After you registered the UserObserver inside AppServiceProvider as we do in ArticleObserver above, let's open it and make some modifications

    class UserObserver
    {
        /**
         * Handle the user "deleting" event.
         *
         * @param  \App\User  $user
         * @return void
         */
        public function deleting(User $user)
        {
            $user->articles()->delete();
        }
    }
    

    Note: You are not forced to keep the unneeded methods, and you may only keep the one who you are truly need it

    So, All what we are doing here, after the user get delete the articles belongs to him deleted as well. That's all, Coll, isn't it?

    Tips

    Everything's in this world has limitation and the Model Observers among them. You should keep in mind while you are using the model observers the following:

    • When you use saved or saving hooks (events), you should never call the model's save method
    • If you are using saved hook and want to call the save method, then you should probably use the saving hook as well.
    • if your logic need to call model's save method. Then rethink your logic or avoid using observers.

    If you're not familiar with save method here is a small definition from Laravel Documentation:

    Eloquent provides convenient methods for adding new models to relationships. For example, perhaps you need to add a new comment to a post. Instead of manually setting the post_id attribute on the Comment model you may insert the comment using the relationship's save method:

    use App\Models\Comment;
    use App\Models\Post;
    
    $comment = new Comment(['message' => 'A new comment.']);
    
    $post = Post::find(1);
    
    $post->comments()->save($comment);
    

    Conclusion

    Laravel Model Observers are a very powerful and useful features and helps to keep your code maintainable and easy to understand.

    You should keep in mind the limitation above in the Tips section to avoid any problems with your code base.

    That's it for today and if you have any questions about the Observers, you can ask me at any time.

    If you enjoy with my articles you can follow me at Twitter for more Tips and Tricks about laravel.


    Related Tags

    About the Author

    Oussama's Profile Picture
    Oussama
    Full Stack Web Developer

    I'm a full stack web developer and telecommunications engineer who love to share knowledge and build stuff online!


    Comments

    Join Our Newsletter

    Subscribe to Our Newsletter and never miss our offers, latest news, Articles, etc.

    Our news letter sent once a week, every tuesday.