diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index 692226968f2c0..cffe3f208ad84 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -21,6 +21,8 @@ CHANGELOG * `JsonSerializableNormalizer` * `ObjectNormalizer` * `PropertyNormalizer` + * Make `BackedEnumNormalizer` throw `NotNormalizableValueException` when the backed type doesn't match + * Make `BackedEnumNormalizer` throw `NotNormalizableValueException` when the value does not belong to a backed enumeration 6.2 --- diff --git a/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php index 32ee831c8c2df..30d4515b5791f 100644 --- a/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Serializer\Normalizer; -use Symfony\Component\PropertyInfo\Type; use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; @@ -69,14 +68,17 @@ public function denormalize(mixed $data, string $type, string $format = null, ar } } - if (!\is_int($data) && !\is_string($data)) { - throw NotNormalizableValueException::createForUnexpectedDataType('The data is neither an integer nor a string, you should pass an integer or a string that can be parsed as an enumeration case of type '.$type.'.', $data, [Type::BUILTIN_TYPE_INT, Type::BUILTIN_TYPE_STRING], $context['deserialization_path'] ?? null, true); + $backingType = (new \ReflectionEnum($type))->getBackingType()->getName(); + $givenType = \get_debug_type($data); + + if ($givenType !== $backingType) { + throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Data expected to be "%s", "%s" given. You should pass a value that can be parsed as an enumeration case of type %s.', $backingType, $givenType, $type), $data, [$backingType], $context['deserialization_path'] ?? null, true); } try { return $type::from($data); } catch (\ValueError $e) { - throw new InvalidArgumentException('The data must belong to a backed enumeration of type '.$type); + throw NotNormalizableValueException::createForUnexpectedDataType('The data must belong to a backed enumeration of type '.$type, $data, [$backingType], $context['deserialization_path'] ?? null, true); } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/BackedEnumNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/BackedEnumNormalizerTest.php index aa0cefe0b431c..15c180d19f23f 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/BackedEnumNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/BackedEnumNormalizerTest.php @@ -86,9 +86,16 @@ public function testDenormalizeObjectThrowsException() $this->normalizer->denormalize(new \stdClass(), StringBackedEnumDummy::class); } + public function testDenormalizeBadBackingTypeThrowsException() + { + $this->expectException(NotNormalizableValueException::class); + $this->expectExceptionMessage('Data expected to be "string", "int" given. You should pass a value that can be parsed as an enumeration case of type '.StringBackedEnumDummy::class.'.'); + $this->normalizer->denormalize(1, StringBackedEnumDummy::class); + } + public function testDenormalizeBadBackingValueThrowsException() { - $this->expectException(InvalidArgumentException::class); + $this->expectException(NotNormalizableValueException::class); $this->expectExceptionMessage('The data must belong to a backed enumeration of type '.StringBackedEnumDummy::class); $this->normalizer->denormalize('POST', StringBackedEnumDummy::class); diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index c178e1b752725..d249f1645cd00 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -59,6 +59,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy; use Symfony\Component\Serializer\Tests\Fixtures\Php74Full; use Symfony\Component\Serializer\Tests\Fixtures\Php80WithPromotedTypedConstructor; +use Symfony\Component\Serializer\Tests\Fixtures\StringBackedEnumDummy; use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy; use Symfony\Component\Serializer\Tests\Fixtures\TrueBuiltInDummy; use Symfony\Component\Serializer\Tests\Fixtures\UpcomingDenormalizerInterface as DenormalizerInterface; @@ -1208,7 +1209,7 @@ public function testCollectDenormalizationErrorsWithEnumConstructor() $this->assertSame($expected, $exceptionsAsArray); } - public function testNoCollectDenormalizationErrorsWithWrongEnum() + public function testCollectDenormalizationErrorsWithWrongEnum() { $serializer = new Serializer( [ @@ -1223,8 +1224,9 @@ public function testNoCollectDenormalizationErrorsWithWrongEnum() DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true, ]); } catch (\Throwable $th) { - $this->assertNotInstanceOf(PartialDenormalizationException::class, $th); - $this->assertInstanceOf(InvalidArgumentException::class, $th); + $this->assertInstanceOf(PartialDenormalizationException::class, $th); + $this->assertArrayHasKey(0, $th->getErrors()); + $this->assertSame("The data must belong to a backed enumeration of type ".StringBackedEnumDummy::class, $th->getErrors()[0]->getMessage()); } }