Skip to content

Commit 94a05ff

Browse files
Copilotmaniaba
andauthored
fix: Entity::normalizeValue() must handle UnitEnum before toArray() (#5)
* fix: Entity::normalizeValue() must handle UnitEnum before toArray() Moves the `UnitEnum` instanceof check before `JsonSerializable` and `method_exists($data, 'toArray')` in Entity::normalizeValue(), so that enums implementing toArray() are always normalized as enums rather than as generic objects. Fixes #10136 Agent-Logs-Url: https://github.com/maniaba/CodeIgniter4/sessions/d5c8c660-329b-4872-8633-dd918674e4ac Co-authored-by: maniaba <[email protected]> * fix test: correct toRawArray() assertion for injected enum toRawArray() returns raw $this->attributes, so an injected enum object stays as an enum object — not the backing string value. The real regression is that hasChanged() must return false (normalizeValue() handles UnitEnum before toArray()). Fixes the failing test from the previous commit. Agent-Logs-Url: https://github.com/maniaba/CodeIgniter4/sessions/d86b9a68-aee9-4178-a8b8-cf1bac285359 Co-authored-by: maniaba <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: maniaba <[email protected]>
1 parent 91f2cb0 commit 94a05ff

3 files changed

Lines changed: 53 additions & 5 deletions

File tree

system/Entity/Entity.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,11 @@ private function normalizeValue(mixed $data): mixed
458458
// Check for Entity instance (use raw values, recursive)
459459
if ($data instanceof self) {
460460
$objectData = $data->toRawArray(false, true);
461+
} elseif ($data instanceof UnitEnum) {
462+
return [
463+
'__class' => $data::class,
464+
'__enum' => $data instanceof BackedEnum ? $data->value : $data->name,
465+
];
461466
} elseif ($data instanceof JsonSerializable) {
462467
$objectData = $data->jsonSerialize();
463468
} elseif (method_exists($data, 'toArray')) {
@@ -469,11 +474,6 @@ private function normalizeValue(mixed $data): mixed
469474
'__class' => $data::class,
470475
'__datetime' => $data->format(DATE_RFC3339_EXTENDED),
471476
];
472-
} elseif ($data instanceof UnitEnum) {
473-
return [
474-
'__class' => $data::class,
475-
'__enum' => $data instanceof BackedEnum ? $data->value : $data->name,
476-
];
477477
} else {
478478
$objectData = get_object_vars($data);
479479

tests/_support/Enum/StateEnum.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter 4 framework.
7+
*
8+
* (c) CodeIgniter Foundation <[email protected]>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace Tests\Support\Enum;
15+
16+
/**
17+
* An enum that also defines toArray(), used to test that UnitEnum handling
18+
* takes precedence over toArray() in Entity::normalizeValue().
19+
*/
20+
enum StateEnum: string
21+
{
22+
case DRAFT = 'draft';
23+
case PUBLISHED = 'published';
24+
25+
public function toArray(): array
26+
{
27+
return array_column(self::cases(), 'value');
28+
}
29+
}

tests/system/Entity/EntityTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use Tests\Support\Entity\Cast\NotExtendsBaseCast;
3636
use Tests\Support\Enum\ColorEnum;
3737
use Tests\Support\Enum\RoleEnum;
38+
use Tests\Support\Enum\StateEnum;
3839
use Tests\Support\Enum\StatusEnum;
3940
use Tests\Support\SomeEntity;
4041

@@ -1045,6 +1046,24 @@ public function testCastEnumSetWithUnitEnumObject(): void
10451046
$this->assertSame(ColorEnum::RED, $entity->color);
10461047
}
10471048

1049+
public function testInjectRawDataWithEnumThatHasToArrayMethod(): void
1050+
{
1051+
// Regression test for https://github.com/codeigniter4/CodeIgniter4/issues/10136
1052+
// Enums implementing toArray() must still be handled by the UnitEnum branch in
1053+
// normalizeValue(), so hasChanged() does not incorrectly report a change after
1054+
// injectRawData() stores the same enum value.
1055+
$entity = new class () extends Entity {};
1056+
1057+
$entity->injectRawData(['state' => StateEnum::DRAFT]);
1058+
1059+
// toRawArray() returns raw attributes, so the enum object is returned as-is.
1060+
$this->assertSame(StateEnum::DRAFT, $entity->toRawArray()['state']);
1061+
1062+
// The key assertion: normalizeValue() must treat the enum as a UnitEnum
1063+
// (not call toArray() on it), so the original and current normalized forms match.
1064+
$this->assertFalse($entity->hasChanged('state'));
1065+
}
1066+
10481067
public function testAsArray(): void
10491068
{
10501069
$entity = $this->getEntity();

0 commit comments

Comments
 (0)