diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 43182cfb9b2a..f3f1a0b9443c 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -458,10 +458,13 @@ 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')) { - $objectData = $data->toArray(); } elseif ($data instanceof Traversable) { $objectData = iterator_to_array($data); } elseif ($data instanceof DateTimeInterface) { @@ -469,11 +472,8 @@ 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, - ]; + } elseif (method_exists($data, 'toArray')) { + $objectData = $data->toArray(); } 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..5b151e167862 --- /dev/null +++ b/tests/_support/Enum/StateEnum.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Enum; + +enum StateEnum: string +{ + case DRAFT = 'draft'; + case PUBLISHED = 'published'; + + public function toArray(): array + { + return self::cases(); + } +} diff --git a/tests/system/Entity/EntityTest.php b/tests/system/Entity/EntityTest.php index 7c19d9d09b89..804d33b0b9d7 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,19 @@ public function testCastEnumSetWithUnitEnumObject(): void $this->assertSame(ColorEnum::RED, $entity->color); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/10136 + */ + public function testInjectRawDataWithEnumThatHasToArrayMethod(): void + { + $entity = new class () extends Entity {}; + + $entity->injectRawData(['state' => StateEnum::DRAFT]); + + $this->assertSame(StateEnum::DRAFT, $entity->toRawArray()['state']); + $this->assertFalse($entity->hasChanged('state')); + } + public function testAsArray(): void { $entity = $this->getEntity(); diff --git a/user_guide_src/source/changelogs/v4.7.3.rst b/user_guide_src/source/changelogs/v4.7.3.rst index b53dce77a93d..b88c04239d24 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. - **Kint:** Fixed a bug where stale Content Security Policy nonces were reused in worker mode, causing browser CSP violations for Debug Toolbar assets. - **Validation:** Fixed a bug where ``Validation::getValidated()`` dropped fields whose validated value was explicitly ``null``.