framework Eloquent dirty check for collections PHP

  • Laravel Version: 8.x
  • PHP Version: all

Description:

Currently, the eloquent model dirty checks are not working correctly for collection attributes if a value changes between boolean and string.

Steps To Reproduce:

use Illuminate\Database\Eloquent\Model;

class Test extends Model
{
    protected $casts = [
        'collection' => 'collection',
    ];
    protected $fillable = [
        'collection',
    ];
}

$model = new Test(['collection' => ['key' => true]]);
$model->syncOriginal();
$model->fill(['collection' => ['key' => 'value']]);

$model->isDirty(); // false but should be true

Reason for this behaviour:

The attributes are casted within the HasAttributes trait to a collection and checked with php's equality logic: 1. $this->castAttribute($key, $attribute) == $this->castAttribute($key, $original); 2. When using the comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values (values are compared with ==), and are instances of the same class. [PHP: Comparing Objects] 3. $a == $b | Equality | true if $a and $b have the same key/value pairs. [PHP: Array Operators]

So, the values are checked with PHP's simple equality check, which is now showing the typical unsafe type checks with strings. In my opinion, the model should be marked as dirty. Depending on the opinion whether this is a bug or expected behavior, I would propose doing strict dirty checks for next major release.

Asked Oct 08 '21 06:10
avatar tpetry
tpetry

4 Answer:

Hey @tpetry, this is more of a feature request I think. Feel free to attempt a PR to see if Taylor would accept it 👍

1
Answered Jul 09 '21 at 10:00
avatar  of driesvints
driesvints

I wouldn't call it a feature request if my models at the moment don't save their updated values to the database because of the actual behavior of the dirty check algorithm.

1
Answered Jul 09 '21 at 10:09
avatar  of tpetry
tpetry

@tpetry we could maybe add another strict-collection besides the current one. Please try a PR if you're willing. If it's not accepted you can always use if in your own code base.

1
Answered Jul 09 '21 at 10:11
avatar  of driesvints
driesvints

The same problem is happening for array, object, maybe AsArrayObject::class and AsCollection ::class. @taylorotwell Is this expected behavior, or a bug? If it's a bug, i can write a PR for 8.x or 9.x if it is declared a breaking change.

1
Answered Jul 09 '21 at 10:33
avatar  of tpetry
tpetry