DEV Community

Cover image for wasChanged() vs wasRecentlyCreated - Laravel Tips
Tony Joe Dev
Tony Joe Dev

Posted on • Originally published at tonyjoe.dev

4

wasChanged() vs wasRecentlyCreated - Laravel Tips

Let's start with a simple model like this:



class MyModel extends Model
{
    protected $fillable = [
        'name'
    ];

    protected static function booted(): void
    {
        static::created(function ($model) {
            $model->dumpEvent('CREATED');
        });

        static::updated(function ($model) {
            $model->dumpEvent('UPDATED');
        });

        static::saved(function ($model) {
            $model->dumpEvent('SAVED');
        });
    }

    public function dumpEvent(string $event): void
    {
        dump([
            'event' => $event,
            'wasChanged()' => $this->wasChanged(),
            'wasRecentlyCreated' => $this->wasRecentlyCreated
        ]);
    }
}


Enter fullscreen mode Exit fullscreen mode

Let’s create a new model:



$model = MyModel::create(['name' => 'ABC']);


Enter fullscreen mode Exit fullscreen mode

We get:



array:3 [ // app/Models/MyModel.php:30
  "event" => "CREATED"
  "wasChanged()" => false      // <-- ❗
  "wasRecentlyCreated" => true
]
array:3 [ // app/Models/MyModel.php:30
  "event" => "SAVED"
  "wasChanged()" => false      // <-- ❗
  "wasRecentlyCreated" => true
]


Enter fullscreen mode Exit fullscreen mode

NOTE:

  • wasChanged() is false

If we call save() without changes on the same model instance:



// $model = MyModel::create(['name' => 'ABC']);
// ...
// ... no changes on `$model` fields

$model->save();


Enter fullscreen mode Exit fullscreen mode

We get:



array:3 [ // app/Models/MyModel.php:30
  "event" => "SAVED"
  "wasChanged()" => false
  "wasRecentlyCreated" => true
]


Enter fullscreen mode Exit fullscreen mode

NOTE:

  • it will be triggered the saved() event
  • but it will not be triggered the updated() event
  • wasRecentlyCreated is still true (remember: it’s the same $model instance)

Now, let’s make some changes, always on the same model instance:



// $model = MyModel::create(['name' => 'ABC']);
// ...

$model->name = 'ABC new';
$model->save();


Enter fullscreen mode Exit fullscreen mode

We get:



array:3 [ // app/Models/MyModel.php:30
  "event" => "UPDATED"
  "wasChanged()" => true
  "wasRecentlyCreated" => true // <-- ❗
]
array:3 [ // app/Models/MyModel.php:30
  "event" => "SAVED"
  "wasChanged()" => true
  "wasRecentlyCreated" => true // <-- ❗
]


Enter fullscreen mode Exit fullscreen mode

NOTE:

  • wasChanged() is true (OK, we expected it to be)
  • wasRecentlyCreated is still true (remember: it’s the same $model instance)

What happens after a refresh()?



// $model = MyModel::create(['name' => 'ABC']);
// ...

// $model->name = 'ABC new';
// $model->save();

$model->refresh();
$model->save();


Enter fullscreen mode Exit fullscreen mode

We get again:



array:3 [ // app/Models/MyModel.php:30
  "event" => "SAVED"
  "wasChanged()" => true       // <-- ❗
  "wasRecentlyCreated" => true // <-- ❗
]


Enter fullscreen mode Exit fullscreen mode

So even after a refresh(), it doesn’t change the internal status for the wasChanged() or wasRecentlyCreated!


Conclusion

In general, between different requests, reloading a model from the DB does not generate problems. But the behavior of wasChanged() and wasRecentlyCreated can become bizarre in the same request, i.e. on the same instance of the newly created model, especially if the model is configured to trigger events in the saved() method, when something has actually changed, for example:



protected static function booted(): void
{
    static::saved(function ($model) {
        if (! $model->wasChanged() && ! $model->wasRecentlyCreated) {
            return; // no changes and no new record
        }

        event(new MyCustomEvent(
            $model->wasRecentlyCreated ? 'mymodel.new' : 'mymodel.updated'),
            $model
        );
    });
}


Enter fullscreen mode Exit fullscreen mode

✸ Enjoy your coding!

 

If you liked this post, don't forget to add your Follow to my profile!

If you want to preview my content, Subscrive to my Newsletter!

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (0)

Cloudinary image

Video API: manage, encode, and optimize for any device, channel or network condition. Deliver branded video experiences in minutes and get deep engagement insights.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay