Skip to content

Commit f027089

Browse files
fix incorrect behaviour when comparing castable attributes in originalIsEquivalent method
1 parent 74d2cb5 commit f027089

File tree

5 files changed

+102
-0
lines changed

5 files changed

+102
-0
lines changed

src/Eloquent/DocumentModel.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
use function is_string;
4444
use function ltrim;
4545
use function method_exists;
46+
use function serialize;
4647
use function sprintf;
4748
use function str_contains;
4849
use function str_starts_with;
@@ -377,6 +378,17 @@ public function originalIsEquivalent($key)
377378
$this->castAttribute($key, $original);
378379
}
379380

381+
if ($this->isClassCastable($key)) {
382+
$attribute = $this->castAttribute($key, $attribute);
383+
$original = $this->castAttribute($key, $original);
384+
385+
if ($attribute === $original) {
386+
return true;
387+
}
388+
389+
return serialize($attribute) === serialize($original);
390+
}
391+
380392
return is_numeric($attribute) && is_numeric($original)
381393
&& strcmp((string) $attribute, (string) $original) === 0;
382394
}

tests/ModelTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use MongoDB\Laravel\Tests\Models\Item;
2727
use MongoDB\Laravel\Tests\Models\MemberStatus;
2828
use MongoDB\Laravel\Tests\Models\NonIncrementing;
29+
use MongoDB\Laravel\Tests\Models\Options;
2930
use MongoDB\Laravel\Tests\Models\Soft;
3031
use MongoDB\Laravel\Tests\Models\SqlUser;
3132
use MongoDB\Laravel\Tests\Models\User;
@@ -1075,6 +1076,16 @@ public function testGetDirtyDates(): void
10751076
$this->assertEmpty($user->getDirty());
10761077
}
10771078

1079+
public function testGetDirtyObjects(): void
1080+
{
1081+
$user = new User();
1082+
$user->options = new Options();
1083+
$this->assertNotEmpty($user->getDirty());
1084+
1085+
$user->save();
1086+
$this->assertEmpty($user->getDirty());
1087+
}
1088+
10781089
public function testChunkById(): void
10791090
{
10801091
User::create(['name' => 'fork', 'tags' => ['sharp', 'pointy']]);

tests/Models/Options.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MongoDB\Laravel\Tests\Models;
6+
7+
class Options
8+
{
9+
private string $option1;
10+
private string $option2;
11+
12+
public function setOption1(string $option1): self
13+
{
14+
$this->option1 = $option1;
15+
return $this;
16+
}
17+
18+
public function setOption2(string $option2): self
19+
{
20+
$this->option2 = $option2;
21+
return $this;
22+
}
23+
24+
public function serialize(): object
25+
{
26+
$result = [];
27+
if (isset($this->option1)) {
28+
$result['option1'] = $this->option1;
29+
}
30+
31+
if (isset($this->option2)) {
32+
$result['option2'] = $this->option2;
33+
}
34+
35+
return (object) $result;
36+
}
37+
}

tests/Models/OptionsCast.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MongoDB\Laravel\Tests\Models;
6+
7+
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
8+
use Illuminate\Database\Eloquent\Model;
9+
10+
class OptionsCast implements CastsAttributes
11+
{
12+
public function get(Model $model, string $key, mixed $value, array $attributes): Options
13+
{
14+
$attributes = new Options();
15+
if (! empty($value['option1'])) {
16+
$attributes->setOption1($value['option1']);
17+
}
18+
19+
if (! empty($value['option2'])) {
20+
$attributes->setOption2($value['option2']);
21+
}
22+
23+
return $attributes;
24+
}
25+
26+
/**
27+
* @param Model $model
28+
* @param string $key
29+
* @param Options|null $value
30+
* @param array $attributes
31+
*
32+
* @return null[]
33+
*/
34+
public function set(Model $model, string $key, mixed $value, array $attributes): array
35+
{
36+
return [
37+
$key => $value?->serialize(),
38+
];
39+
}
40+
}

tests/Models/User.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* @property Carbon $updated_at
3030
* @property string $username
3131
* @property MemberStatus member_status
32+
* @property Options $options
3233
*/
3334
class User extends Model implements AuthenticatableContract, CanResetPasswordContract
3435
{
@@ -44,6 +45,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
4445
'birthday' => 'datetime',
4546
'entry.date' => 'datetime',
4647
'member_status' => MemberStatus::class,
48+
'options' => OptionsCast::class,
4749
];
4850

4951
protected $fillable = [

0 commit comments

Comments
 (0)