From 71b27f2203deafe04f6a9fcd8e0c14560061a016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=CC=88nther=20Debrauwer?= Date: Thu, 9 Sep 2021 18:44:38 +0200 Subject: [PATCH 1/5] Add failing test --- tests/Database/DatabaseEloquentModelTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index a36bba4fe3eb..d21ddb4ecdd0 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -13,6 +13,7 @@ use Illuminate\Database\ConnectionResolverInterface; use Illuminate\Database\ConnectionResolverInterface as Resolver; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Casts\AsArrayObject; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\JsonEncodingException; use Illuminate\Database\Eloquent\MassAssignmentException; @@ -155,6 +156,21 @@ public function testDirtyOnCastedObjects() $this->assertFalse($model->isDirty('collectionAttribute')); } + public function testDirtyOnCastedArrayObject() + { + $model = new EloquentModelCastingStub; + $model->setRawAttributes([ + 'arrayobjectAttribute' => '{"foo": "bar"}', + ]); + $model->syncOriginal(); + + $model->arrayobjectAttribute = ['foo' => 'bar']; + $this->assertFalse($model->isDirty()); + + $model->arrayobjectAttribute = ['foo' => 'baz']; + $this->assertTrue($model->isDirty()); + } + public function testCleanAttributes() { $model = new EloquentModelStub(['foo' => '1', 'bar' => 2, 'baz' => 3]); @@ -2570,6 +2586,7 @@ class EloquentModelCastingStub extends Model 'dateAttribute' => 'date', 'datetimeAttribute' => 'datetime', 'timestampAttribute' => 'timestamp', + 'arrayobjectAttribute' => AsArrayObject::class, ]; public function jsonAttributeValue() From b2be39f8ced0aa105d82c735f8a7ab36fe1b843f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=CC=88nther=20Debrauwer?= Date: Thu, 9 Sep 2021 18:45:28 +0200 Subject: [PATCH 2/5] Fix originalIsEquivalent method --- .../Database/Eloquent/Casts/AsArrayObject.php | 2 +- .../Database/Eloquent/Casts/AsCollection.php | 2 +- .../Database/Eloquent/Casts/AsEncryptedArrayObject.php | 2 +- .../Database/Eloquent/Casts/AsEncryptedCollection.php | 2 +- .../Database/Eloquent/Concerns/HasAttributes.php | 10 ++++++++++ 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php b/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php index db9a21b461ba..b039fb29cfd6 100644 --- a/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php +++ b/src/Illuminate/Database/Eloquent/Casts/AsArrayObject.php @@ -19,7 +19,7 @@ public static function castUsing(array $arguments) { public function get($model, $key, $value, $attributes) { - return isset($attributes[$key]) ? new ArrayObject(json_decode($attributes[$key], true)) : null; + return $value ? new ArrayObject(json_decode($value, true)) : null; } public function set($model, $key, $value, $attributes) diff --git a/src/Illuminate/Database/Eloquent/Casts/AsCollection.php b/src/Illuminate/Database/Eloquent/Casts/AsCollection.php index 585b6cfc7012..7c989c1eb9a2 100644 --- a/src/Illuminate/Database/Eloquent/Casts/AsCollection.php +++ b/src/Illuminate/Database/Eloquent/Casts/AsCollection.php @@ -20,7 +20,7 @@ public static function castUsing(array $arguments) { public function get($model, $key, $value, $attributes) { - return isset($attributes[$key]) ? new Collection(json_decode($attributes[$key], true)) : null; + return $value ? new Collection(json_decode($value, true)) : null; } public function set($model, $key, $value, $attributes) diff --git a/src/Illuminate/Database/Eloquent/Casts/AsEncryptedArrayObject.php b/src/Illuminate/Database/Eloquent/Casts/AsEncryptedArrayObject.php index 5918bc1b2203..c54b678d6f3f 100644 --- a/src/Illuminate/Database/Eloquent/Casts/AsEncryptedArrayObject.php +++ b/src/Illuminate/Database/Eloquent/Casts/AsEncryptedArrayObject.php @@ -20,7 +20,7 @@ public static function castUsing(array $arguments) { public function get($model, $key, $value, $attributes) { - return new ArrayObject(json_decode(Crypt::decryptString($attributes[$key]), true)); + return new ArrayObject(json_decode(Crypt::decryptString($value), true)); } public function set($model, $key, $value, $attributes) diff --git a/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php b/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php index ad11b1787b38..bd61d7557a2b 100644 --- a/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php +++ b/src/Illuminate/Database/Eloquent/Casts/AsEncryptedCollection.php @@ -21,7 +21,7 @@ public static function castUsing(array $arguments) { public function get($model, $key, $value, $attributes) { - return new Collection(json_decode(Crypt::decryptString($attributes[$key]), true)); + return new Collection(json_decode(Crypt::decryptString($value), true)); } public function set($model, $key, $value, $attributes) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 1e57c91004d8..584feaf05e31 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -1658,6 +1658,16 @@ public function originalIsEquivalent($key) } elseif ($this->hasCast($key, static::$primitiveCastTypes)) { return $this->castAttribute($key, $attribute) === $this->castAttribute($key, $original); + } elseif ($this->isClassCastable($key)) { + $caster = $this->resolveCasterClass($key); + $original = $this->normalizeCastClassResponse($key, $caster->set( + $this, + $key, + $this->castAttribute($key, $original), + $this->attributes + )); + + return $attribute === $original[$key]; } return is_numeric($attribute) && is_numeric($original) From 1d18888e5ca05a8a0599a234b7f8bdf30105ba97 Mon Sep 17 00:00:00 2001 From: GuntherDebrauwer Date: Sun, 12 Sep 2021 14:24:38 +0200 Subject: [PATCH 3/5] Improve test --- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 3 +-- tests/Database/DatabaseEloquentModelTest.php | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 584feaf05e31..b57ecec1df95 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -1659,8 +1659,7 @@ public function originalIsEquivalent($key) return $this->castAttribute($key, $attribute) === $this->castAttribute($key, $original); } elseif ($this->isClassCastable($key)) { - $caster = $this->resolveCasterClass($key); - $original = $this->normalizeCastClassResponse($key, $caster->set( + $original = $this->normalizeCastClassResponse($key, $this->resolveCasterClass($key)->set( $this, $key, $this->castAttribute($key, $original), diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index d21ddb4ecdd0..4e528885cd8f 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Database; +use ArrayObject; use DateTime; use DateTimeImmutable; use DateTimeInterface; @@ -164,6 +165,9 @@ public function testDirtyOnCastedArrayObject() ]); $model->syncOriginal(); + $this->assertInstanceOf(ArrayObject::class, $model->arrayobjectAttribute); + $this->assertFalse($model->isDirty()); + $model->arrayobjectAttribute = ['foo' => 'bar']; $this->assertFalse($model->isDirty()); From d76eaa3da1039546b642b41dd4611efe6a026b20 Mon Sep 17 00:00:00 2001 From: GuntherDebrauwer Date: Sun, 12 Sep 2021 14:47:10 +0200 Subject: [PATCH 4/5] Improve test even more --- tests/Database/DatabaseEloquentModelTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 4e528885cd8f..f5acc6a0673c 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -166,13 +166,13 @@ public function testDirtyOnCastedArrayObject() $model->syncOriginal(); $this->assertInstanceOf(ArrayObject::class, $model->arrayobjectAttribute); - $this->assertFalse($model->isDirty()); + $this->assertFalse($model->isDirty('arrayobjectAttribute')); $model->arrayobjectAttribute = ['foo' => 'bar']; - $this->assertFalse($model->isDirty()); + $this->assertFalse($model->isDirty('arrayobjectAttribute')); $model->arrayobjectAttribute = ['foo' => 'baz']; - $this->assertTrue($model->isDirty()); + $this->assertTrue($model->isDirty('arrayobjectAttribute')); } public function testCleanAttributes() From 899e3c16d59f6cf58b29a0911e8e53e076e2fe6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=CC=88nther=20Debrauwer?= Date: Mon, 13 Sep 2021 16:38:34 +0200 Subject: [PATCH 5/5] Cast attribute manually --- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index b57ecec1df95..b125baed4e46 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -1659,10 +1659,12 @@ public function originalIsEquivalent($key) return $this->castAttribute($key, $attribute) === $this->castAttribute($key, $original); } elseif ($this->isClassCastable($key)) { - $original = $this->normalizeCastClassResponse($key, $this->resolveCasterClass($key)->set( + $caster = $this->resolveCasterClass($key); + + $original = $this->normalizeCastClassResponse($key, $caster->set( $this, $key, - $this->castAttribute($key, $original), + $caster instanceof CastsInboundAttributes ? $original : $caster->get($this, $key, $original, $this->attributes), $this->attributes ));