Skip to content

Commit

Permalink
update Model dirty check (#30565)
Browse files Browse the repository at this point in the history
for attributes that are cast to any type of Object, the strict equivalency (`===`) will never return `true`, because even though the values may be equal, the Object there reference will be different.

this changes checks if the cast type is either `object` or `collection`, both with return Objects, and uses loose equivalency to compare them.

even though date casting also returns an Object, we don't need to handle that since it's handled in the previous conditional.

the test represents a scenario that occurs when using JSON fields in MySQL. MySQL returns the value with spaces between the elements, but `json_encode` returns a string **without** spaces between the elements.
  • Loading branch information
browner12 authored and taylorotwell committed Nov 12, 2019
1 parent 6460d2b commit f1cfa85
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,9 @@ public function originalIsEquivalent($key, $current)
} elseif ($this->isDateAttribute($key)) {
return $this->fromDateTime($current) ===
$this->fromDateTime($original);
} elseif ($this->hasCast($key, ['object', 'collection'])) {
return $this->castAttribute($key, $current) ==
$this->castAttribute($key, $original);
} elseif ($this->hasCast($key)) {
return $this->castAttribute($key, $current) ===
$this->castAttribute($key, $original);
Expand Down
17 changes: 17 additions & 0 deletions tests/Database/DatabaseEloquentModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,23 @@ public function testDirtyOnCastOrDateAttributes()
$this->assertTrue($model->isDirty('datetimeAttribute'));
}

public function testDirtyOnCastedObjects()
{
$model = new EloquentModelCastingStub;
$model->setRawAttributes([
'objectAttribute' => '["one", "two", "three"]',
'collectionAttribute' => '["one", "two", "three"]',
]);
$model->syncOriginal();

$model->objectAttribute = ['one', 'two', 'three'];
$model->collectionAttribute = ['one', 'two', 'three'];

$this->assertFalse($model->isDirty());
$this->assertFalse($model->isDirty('objectAttribute'));
$this->assertFalse($model->isDirty('collectionAttribute'));
}

public function testCleanAttributes()
{
$model = new EloquentModelStub(['foo' => '1', 'bar' => 2, 'baz' => 3]);
Expand Down

0 comments on commit f1cfa85

Please sign in to comment.