Override updated_at, or "hidden" save() parameters

Another interesting feature in Laravel Eloquent mechanism. When updating existing entry, we just use update() or save() and then updated_at field is changed automatically. But what if we want to stick our own updated_at instead of automatic one?

How timestamps work

If in your Model you don't have $timestamps = false setting, you should have created_at and updated_at in your DB table, which are changed automatically in the background, you don't need to take care of anything. At the moment of creating new entry with create() or save(), created_at and updated_at are filled with current timestamp. And when something is updated, then only updated_at field is changing, created_at remains the same, well, forever. Notice: interestingly, updated_at is changed only when at least one column in table was *actually* changed. If you just call update() with old values, updated_at would remain the same.

Why we might need to override updated_at?

Let's say we have some external data source - that we need to sync something with another database or API. And you need to update entry in your database, but with updated_at timestamp from another database. So you would think we can do that:
$product = Product::find($id);
$product->updated_at = '2015-01-01 10:00:00';
$product->save();
But the problem is that updated_at is overridden after that by automatic Laravel magic - so whatever you put in this value it will be updated to current timestamp.

Solution: save() with parameters

Sometimes it's interesting to dig deeper in Laravel functions and find out about some additional optional parameters. So this is the example - when calling save() method, we can specify timestamps to be ignored and not updated automatically. Like this:
$product = Product::find($id);
$product->updated_at = '2015-01-01 10:00:00';
$product->save(['timestamps' => false]);
If we look at the actual save() method, it looks like this:
/**
 * Save the model to the database.
 *
 * @param  array  $options
 * @return bool
 */
public function save(array $options = array())
Which then is actually leads to method performUpdate() and used only for this instance:
protected function performUpdate(Builder $query, array $options = [])
{
// .... some code
// ....
// First we need to create a fresh query instance and touch the creation and
// update timestamp on the model which are maintained by us for developer
// convenience. Then we will just continue saving the model instances.
if ($this->timestamps && array_get($options, 'timestamps', true))
{
    $this->updateTimestamps();
}
So far I cannot find any more usages of the $options, except for 'timestamps', but I guess it's possibly to add some parameters in the future, so pretty flexible code. Taylor strikes again.

No comments or questions yet...

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 22 courses (477 lessons, total 38 h 20 min)
  • 2 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord