diff --git a/src/JsonMapper.php b/src/JsonMapper.php index 25534d0a6..aca4f6059 100644 --- a/src/JsonMapper.php +++ b/src/JsonMapper.php @@ -296,12 +296,20 @@ public function map($json, $object) } else if (is_array($jvalue) && $this->hasVariadicArrayType($accessor)) { $array = array(); $subtype = $type; - } else { - if (is_a($type, 'ArrayAccess', true) - && is_a($type, 'Traversable', true) - ) { - $array = $this->createInstance($type, false, $jvalue); + } else if (is_a($type, 'ArrayAccess', true) + && is_a($type, 'Traversable', true) + ) { + $array = $this->createInstance($type, false, $jvalue); + } else if (PHP_VERSION_ID >= 80100 && enum_exists($type)) { + $evalue = $type::tryFrom($jvalue); + if ($evalue === null) { + throw new JsonMapper_Exception( + 'Enum value "' . $jvalue . '" does not belong to ' + . $type . ' enumerator class' + ); } + $this->setProperty($object, $accessor, $evalue); + continue; } if ($array !== null) { diff --git a/tests/Enums_PHP81_Test.php b/tests/Enums_PHP81_Test.php index ae22af1b9..192811655 100644 --- a/tests/Enums_PHP81_Test.php +++ b/tests/Enums_PHP81_Test.php @@ -32,4 +32,45 @@ public function testEnumMapping() $this->assertSame(\Enums\StringBackedEnum::FOO, $sn->stringBackedEnum); $this->assertSame(\Enums\IntBackedEnum::BAR, $sn->intBackedEnum); } + + /** + * Test that string values are correctly mapped to backed enum properties. + */ + public function testBackedEnumPropertyIsMappedFromString(): void + { + $json = (object) [ + 'stringBackedEnum' => 'foo', + 'intBackedEnum' => 2, + ]; + + $mapper = new \JsonMapper(); + $target = new \Enums\ObjectWithEnum(); + + $mapped = $mapper->map($json, $target); + + $this->assertSame( + \Enums\StringBackedEnum::FOO, + $mapped->stringBackedEnum, + 'Expected JSON scalar to be converted to the corresponding backed enum case' + ); + } + + /** + * Test that mapping invalid string values to backed enum properties throws an exception. + */ + public function testBackedEnumPropertyWithInvalidStringThrowsJsonMapperException(): void + { + $json = (object) [ + 'stringBackedEnum' => 'not-a-valid-enum-value', + 'intBackedEnum' => 'not-a-valid-enum-value', + ]; + + $mapper = new \JsonMapper(); + $target = new \Enums\ObjectWithEnum(); + + $this->expectException(\JsonMapper_Exception::class); + $this->expectExceptionMessage('Enum value "not-a-valid-enum-value" does not belong to'); + + $mapper->map($json, $target); + } }