laravel Eloquent model update event is not fired

24,668

Solution 1

You need to retrieve the user from the database and then save that user in order to fire the event. For example:

This will NOT fire the update event:

User::where('id', $id)->update(['username' => $newUsername]);

This will fire the update event:

User::find($id)->update(['username' => $newUsername]);

Solution 2

Possible reasons:

  1. The row is not updated at all - no changes. Hence not firing, and

  2. You used update. Check the docs here: https://laravel.com/docs/5.3/eloquent#updates

When issuing a mass update via Eloquent, the saved and updated model events will not be fired for the updated models. This is because the models are never actually retrieved when issuing a mass update.

Share:
24,668
northblue
Author by

northblue

Updated on July 09, 2022

Comments

  • northblue
    northblue almost 2 years

    Merry Christmas guys!

    I am new to Laravel. Just had a beginner's question, when I am trying to use service provider and model event to log the update information.

    Was following the online doc: https://laravel.com/docs/5.3/eloquent#events

    After put all code together, I find that the model event only fire when create the use but never log anything when I edit the user.

    Did I miss anything? Feel like the $user didn't get assigned properly. Where is it from? from other service provider?

    Any explanation or hint will be appreciated!

    <?php
    
    namespace App\Providers;
    
    use App\User;
    use Illuminate\Support\ServiceProvider;
    
    class AppServiceProvider extends ServiceProvider
    {
        /**
         * Bootstrap any application services.
         *
         * @return void
         */
        public function boot()
        {
            User::creating(function ($user) {
                Log::info('event creating');
            });
    
            User::created(function ($user) {
                Log::info('event created');
            });
    
            User::updating(function ($user) {
                Log::info('event updating');
            });
    
            User::updated(function ($user) {
                Log::info('event updated');
            });
    
            User::saving(function ($user) {
                Log::info('event saving');
            });
    
            User::saved(function ($user) {
                Log::info('event saved');
            });
    
            User::deleting(function ($user) {
                Log::info('event deleting');
            });
    
            User::deleted(function ($user) {
                Log::info('event deleted');
            });
        }
    
        /**
         * Register the service provider.
         *
         * @return void
         */
        public function register()
        {
            //
        }
    }
    
    • Lionel Chan
      Lionel Chan over 7 years
      What's your code that does the create and edit? It could be that no changes were made hence the event was not fired, or you are doing mass updating which is not firing event at all.
    • northblue
      northblue over 7 years
      Thanks @LionelChan, Ohgodwhy and Eric Tucker! The event trigger is working perfectly after change the update to: User::find($id)->update(['username' => $newUsername]); Appreciated for your help!
    • Lionel Chan
      Lionel Chan over 7 years
      Same goes to delete. Model will fire relevant events only when model object is being created. Which means it only fires if you do find, get, first first to retrieve the objects :)
  • Ohgodwhy
    Ohgodwhy over 7 years
    In short; you must issue a find($id) and modify the properties manually for this to work correctly.
  • padawanTony
    padawanTony almost 4 years
    This works: User::find(4)->update(['earings' => 0]); while this doesn't: $user = User::find(1); $user->earings=0; $user->update(). In the second case the event is not being fired. Can you explain why? What is the difference between the two statements? Aren't they both mass assignment?
  • padawanTony
    padawanTony almost 4 years
    This works: User::find(4)->update(['earings' => 0]); while this doesn't: $user = User::find(1); $user->earings=0; $user->update(). In the second case the event is not being fired. Can you explain why? What is the difference between the two statements? Aren't they both mass assignment?
  • Eric Tucker
    Eric Tucker almost 4 years
    Both of your examples are doing the same thing and will fire the event only if the model is dirty. In your case, the model event will only fire if $user->earings does not equal 0. This may be what you are experiencing.
  • padawanTony
    padawanTony almost 4 years
    You mean if the original value of earings was not 0. It wasn't. This is why I'm doing $user->earings=0;. So that it changes and the instance becomes dirty.
  • padawanTony
    padawanTony almost 4 years
    OK. I'm reading the source code trying to understand this. The question I have now is this, "How does changing an attribute (ex: $user->earings=0;) make the instance dirty? Which is the code/function that does that?
  • Eric Tucker
    Eric Tucker almost 4 years
    When Laravel pulls a model from the database it immediately stores a snapshot of the original state. Then, when you update attributes, before persisting those changes to the DB, Laravel checks the current state of each attribute against what was pulled originally from the database. When at least one of those don't match, that model is considered dirty and only then will the actual update command be sent to the DB and events will be fired.
  • Grant
    Grant over 2 years
    Um... why though? Had to change my where to find & it fixed my event misfire... thanks
  • Eric Tucker
    Eric Tucker over 2 years
    @Grant It's because, in this case, model events are registered for each model when they're hydrated from the database. These are not database triggers. Without pulling the row from the db, ie: User::where('id', $id)->update(['username' => $newUsername]);, you're just executing UPDATE users SET username = ? WHERE id = ? which never hydrates a model, bypassing those events.
  • Grant
    Grant over 2 years
    Thanks for the answer @EricTucker makes perfect sense