Skip to content

Commit fef0260

Browse files
[9.x] Fix enum casts arrayable behaviour (#40885)
* Fix enum casts toArray behaviour * CI Style fix * Update HasAttributes.php Co-authored-by: Taylor Otwell <[email protected]>
1 parent aeea9ff commit fef0260

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ protected function addCastAttributesToArray(array $attributes, array $mutatedAtt
297297
$attributes[$key] = $this->serializeClassCastableAttribute($key, $attributes[$key]);
298298
}
299299

300-
if ($this->isEnumCastable($key)) {
300+
if ($this->isEnumCastable($key) && (! ($attributes[$key] ?? null) instanceof Arrayable)) {
301301
$attributes[$key] = isset($attributes[$key]) ? $attributes[$key]->value : null;
302302
}
303303

tests/Integration/Database/EloquentModelEnumCastingTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ protected function defineDatabaseMigrationsAfterDatabaseRefreshed()
2222
$table->increments('id');
2323
$table->string('string_status', 100)->nullable();
2424
$table->integer('integer_status')->nullable();
25+
$table->string('arrayable_status')->nullable();
2526
});
2627
}
2728

@@ -30,37 +31,47 @@ public function testEnumsAreCastable()
3031
DB::table('enum_casts')->insert([
3132
'string_status' => 'pending',
3233
'integer_status' => 1,
34+
'arrayable_status' => 'pending',
3335
]);
3436

3537
$model = EloquentModelEnumCastingTestModel::first();
3638

3739
$this->assertEquals(StringStatus::pending, $model->string_status);
3840
$this->assertEquals(IntegerStatus::pending, $model->integer_status);
41+
$this->assertEquals(ArrayableStatus::pending, $model->arrayable_status);
3942
}
4043

4144
public function testEnumsReturnNullWhenNull()
4245
{
4346
DB::table('enum_casts')->insert([
4447
'string_status' => null,
4548
'integer_status' => null,
49+
'arrayable_status' => null,
4650
]);
4751

4852
$model = EloquentModelEnumCastingTestModel::first();
4953

5054
$this->assertEquals(null, $model->string_status);
5155
$this->assertEquals(null, $model->integer_status);
56+
$this->assertEquals(null, $model->arrayable_status);
5257
}
5358

5459
public function testEnumsAreCastableToArray()
5560
{
5661
$model = new EloquentModelEnumCastingTestModel([
5762
'string_status' => StringStatus::pending,
5863
'integer_status' => IntegerStatus::pending,
64+
'arrayable_status' => ArrayableStatus::pending,
5965
]);
6066

6167
$this->assertEquals([
6268
'string_status' => 'pending',
6369
'integer_status' => 1,
70+
'arrayable_status' => [
71+
'name' => 'pending',
72+
'value' => 'pending',
73+
'description' => 'pending status description',
74+
],
6475
], $model->toArray());
6576
}
6677

@@ -69,11 +80,13 @@ public function testEnumsAreCastableToArrayWhenNull()
6980
$model = new EloquentModelEnumCastingTestModel([
7081
'string_status' => null,
7182
'integer_status' => null,
83+
'arrayable_status' => null,
7284
]);
7385

7486
$this->assertEquals([
7587
'string_status' => null,
7688
'integer_status' => null,
89+
'arrayable_status' => null,
7790
], $model->toArray());
7891
}
7992

@@ -82,6 +95,7 @@ public function testEnumsAreConvertedOnSave()
8295
$model = new EloquentModelEnumCastingTestModel([
8396
'string_status' => StringStatus::pending,
8497
'integer_status' => IntegerStatus::pending,
98+
'arrayable_status' => ArrayableStatus::pending,
8599
]);
86100

87101
$model->save();
@@ -90,6 +104,7 @@ public function testEnumsAreConvertedOnSave()
90104
'id' => $model->id,
91105
'string_status' => 'pending',
92106
'integer_status' => 1,
107+
'arrayable_status' => 'pending',
93108
], DB::table('enum_casts')->where('id', $model->id)->first());
94109
}
95110

@@ -98,6 +113,7 @@ public function testEnumsAcceptNullOnSave()
98113
$model = new EloquentModelEnumCastingTestModel([
99114
'string_status' => null,
100115
'integer_status' => null,
116+
'arrayable_status' => null,
101117
]);
102118

103119
$model->save();
@@ -106,6 +122,7 @@ public function testEnumsAcceptNullOnSave()
106122
'id' => $model->id,
107123
'string_status' => null,
108124
'integer_status' => null,
125+
'arrayable_status' => null,
109126
], DB::table('enum_casts')->where('id', $model->id)->first());
110127
}
111128

@@ -114,6 +131,7 @@ public function testEnumsAcceptBackedValueOnSave()
114131
$model = new EloquentModelEnumCastingTestModel([
115132
'string_status' => 'pending',
116133
'integer_status' => 1,
134+
'arrayable_status' => 'pending',
117135
]);
118136

119137
$model->save();
@@ -122,13 +140,15 @@ public function testEnumsAcceptBackedValueOnSave()
122140

123141
$this->assertEquals(StringStatus::pending, $model->string_status);
124142
$this->assertEquals(IntegerStatus::pending, $model->integer_status);
143+
$this->assertEquals(ArrayableStatus::pending, $model->arrayable_status);
125144
}
126145

127146
public function testFirstOrNew()
128147
{
129148
DB::table('enum_casts')->insert([
130149
'string_status' => 'pending',
131150
'integer_status' => 1,
151+
'arrayable_status' => 'pending',
132152
]);
133153

134154
$model = EloquentModelEnumCastingTestModel::firstOrNew([
@@ -176,5 +196,6 @@ class EloquentModelEnumCastingTestModel extends Model
176196
public $casts = [
177197
'string_status' => StringStatus::class,
178198
'integer_status' => IntegerStatus::class,
199+
'arrayable_status' => ArrayableStatus::class,
179200
];
180201
}

tests/Integration/Database/Enums.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Illuminate\Tests\Integration\Database;
44

5+
use Illuminate\Contracts\Support\Arrayable;
6+
57
enum StringStatus: string
68
{
79
case pending = 'pending';
@@ -13,3 +15,26 @@ enum IntegerStatus: int
1315
case pending = 1;
1416
case done = 2;
1517
}
18+
19+
enum ArrayableStatus: string implements Arrayable
20+
{
21+
case pending = 'pending';
22+
case done = 'done';
23+
24+
public function description(): string
25+
{
26+
return match ($this) {
27+
self::pending => 'pending status description',
28+
self::done => 'done status description'
29+
};
30+
}
31+
32+
public function toArray()
33+
{
34+
return [
35+
'name' => $this->name,
36+
'value' => $this->value,
37+
'description' => $this->description(),
38+
];
39+
}
40+
}

0 commit comments

Comments
 (0)