Eloquent model timestamp updated without changes
2 min readJun 18, 2024
When performing an update, Laravel's Eloquent ORM only touches the timestamp (updated_at
) when something was modified. However, depending on your database, the values can be stored with a different value.
Case in Point
MySQL and SQLite store boolean as integer values 1
and 0
. As a result, updating a boolean 1
with true
will touch the timestamp, which can be confusing.
Solution
To avoid this, you can use attribute casting to cast the column to boolean in the model class.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ChecklistItem extends Model
{
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return ['checked' => 'boolean'];
}
}
This way, Eloquent will check for changes after casting. Here is a simplified version of how Eloquent checks if changes occured (full version here):
/**
* Determine if the new and old values for a given key are equivalent.
*
* @param string $key
* @return bool
*/
public function originalIsEquivalent($key)
{
if (! array_key_exists($key, $this->original)) {
return false;
}
$attribute = Arr::get($this->attributes, $key);
$original = Arr::get($this->original, $key);
if ($attribute === $original) {
return true;
}
...
elseif ($this->hasCast($key, static::$primitiveCastTypes)) {
return $this->castAttribute($key, $attribute) ===
$this->castAttribute($key, $original);
}
...
}