From 94a05ff80ecbd924934cec760c187f8b81a8ce8c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Apr 2026 16:43:07 +0200 Subject: [PATCH 1/2] fix: Entity::normalizeValue() must handle UnitEnum before toArray() (#5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 codeigniter4/CodeIgniter4#10136 Agent-Logs-Url: https://github.com/maniaba/CodeIgniter4/sessions/d5c8c660-329b-4872-8633-dd918674e4ac Co-authored-by: maniaba <61078470+maniaba@users.noreply.github.com> * 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 <61078470+maniaba@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: maniaba <61078470+maniaba@users.noreply.github.com> --- system/Entity/Entity.php | 10 +++++----- tests/_support/Enum/StateEnum.php | 29 +++++++++++++++++++++++++++++ tests/system/Entity/EntityTest.php | 19 +++++++++++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 tests/_support/Enum/StateEnum.php diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 43182cfb9b2a..e3733bd0fc02 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -458,6 +458,11 @@ private function normalizeValue(mixed $data): mixed // Check for Entity instance (use raw values, recursive) if ($data instanceof self) { $objectData = $data->toRawArray(false, true); + } elseif ($data instanceof UnitEnum) { + return [ + '__class' => $data::class, + '__enum' => $data instanceof BackedEnum ? $data->value : $data->name, + ]; } elseif ($data instanceof JsonSerializable) { $objectData = $data->jsonSerialize(); } elseif (method_exists($data, 'toArray')) { @@ -469,11 +474,6 @@ private function normalizeValue(mixed $data): mixed '__class' => $data::class, '__datetime' => $data->format(DATE_RFC3339_EXTENDED), ]; - } elseif ($data instanceof UnitEnum) { - return [ - '__class' => $data::class, - '__enum' => $data instanceof BackedEnum ? $data->value : $data->name, - ]; } else { $objectData = get_object_vars($data); diff --git a/tests/_support/Enum/StateEnum.php b/tests/_support/Enum/StateEnum.php new file mode 100644 index 000000000000..84d6a1713aae --- /dev/null +++ b/tests/_support/Enum/StateEnum.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Enum; + +/** + * An enum that also defines toArray(), used to test that UnitEnum handling + * takes precedence over toArray() in Entity::normalizeValue(). + */ +enum StateEnum: string +{ + case DRAFT = 'draft'; + case PUBLISHED = 'published'; + + public function toArray(): array + { + return array_column(self::cases(), 'value'); + } +} diff --git a/tests/system/Entity/EntityTest.php b/tests/system/Entity/EntityTest.php index 7c19d9d09b89..59445f6c294d 100644 --- a/tests/system/Entity/EntityTest.php +++ b/tests/system/Entity/EntityTest.php @@ -35,6 +35,7 @@ use Tests\Support\Entity\Cast\NotExtendsBaseCast; use Tests\Support\Enum\ColorEnum; use Tests\Support\Enum\RoleEnum; +use Tests\Support\Enum\StateEnum; use Tests\Support\Enum\StatusEnum; use Tests\Support\SomeEntity; @@ -1045,6 +1046,24 @@ public function testCastEnumSetWithUnitEnumObject(): void $this->assertSame(ColorEnum::RED, $entity->color); } + public function testInjectRawDataWithEnumThatHasToArrayMethod(): void + { + // Regression test for https://github.com/codeigniter4/CodeIgniter4/issues/10136 + // Enums implementing toArray() must still be handled by the UnitEnum branch in + // normalizeValue(), so hasChanged() does not incorrectly report a change after + // injectRawData() stores the same enum value. + $entity = new class () extends Entity {}; + + $entity->injectRawData(['state' => StateEnum::DRAFT]); + + // toRawArray() returns raw attributes, so the enum object is returned as-is. + $this->assertSame(StateEnum::DRAFT, $entity->toRawArray()['state']); + + // The key assertion: normalizeValue() must treat the enum as a UnitEnum + // (not call toArray() on it), so the original and current normalized forms match. + $this->assertFalse($entity->hasChanged('state')); + } + public function testAsArray(): void { $entity = $this->getEntity(); From 76a4c33a74b57fef8df1264d6f11d6599635a769 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Apr 2026 17:26:22 +0200 Subject: [PATCH 2/2] docs: add Entity::normalizeValue() UnitEnum fix to v4.7.3 changelog (#6) Agent-Logs-Url: https://github.com/maniaba/CodeIgniter4/sessions/40f33833-bf97-486e-a6d8-5d95bff1bf50 Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: maniaba <61078470+maniaba@users.noreply.github.com> --- user_guide_src/source/changelogs/v4.7.3.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.7.3.rst b/user_guide_src/source/changelogs/v4.7.3.rst index 677e1072500b..45ef4c7b09f5 100644 --- a/user_guide_src/source/changelogs/v4.7.3.rst +++ b/user_guide_src/source/changelogs/v4.7.3.rst @@ -40,6 +40,7 @@ Bugs Fixed - **CLI:** Fixed a bug where ``CLI::generateDimensions()`` leaked ``stty`` error output (e.g., ``stty: 'standard input': Inappropriate ioctl for device``) to stderr when stdin was not a TTY. - **Commands:** Fixed a bug in the ``env`` command where passing options only would cause the command to throw a ``TypeError`` instead of showing the current environment. - **Common:** Fixed a bug where the ``command()`` helper function did not properly clean up output buffers, which could lead to risky tests when exceptions were thrown. +- **Entity:** Fixed a bug where ``Entity::normalizeValue()`` did not handle ``UnitEnum`` before checking for ``toArray()``, causing enums implementing ``toArray()`` to be incorrectly normalized as generic objects instead of enums. - **Validation:** Fixed a bug where ``Validation::getValidated()`` dropped fields whose validated value was explicitly ``null``. See the repo's