From c30f057db29a8fcc819b71adf390532085b10c9f Mon Sep 17 00:00:00 2001 From: allison guilhem Date: Sat, 30 Jul 2022 17:36:59 +0200 Subject: [PATCH] [Serializer] Throw InvalidArgumentException if the data needed in the constructor doesn't belong to a backedEnum --- .../Normalizer/BackedEnumNormalizer.php | 2 +- .../DummyObjectWithEnumConstructor.php | 12 ++++ .../Normalizer/BackedEnumNormalizerTest.php | 5 +- .../Serializer/Tests/SerializerTest.php | 65 +++++++++++++++++++ 4 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/DummyObjectWithEnumConstructor.php diff --git a/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php index 8d5566bcc86f5..ad9fb807aed19 100644 --- a/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php @@ -64,7 +64,7 @@ public function denormalize($data, string $type, string $format = null, array $c try { return $type::from($data); } catch (\ValueError $e) { - throw NotNormalizableValueException::createForUnexpectedDataType($e->getMessage(), $data, [Type::BUILTIN_TYPE_INT, Type::BUILTIN_TYPE_STRING], $context['deserialization_path'] ?? null, true, $e->getCode(), $e); + throw new InvalidArgumentException('The data must belong to a backed enumeration of type '.$type); } } diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyObjectWithEnumConstructor.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyObjectWithEnumConstructor.php new file mode 100644 index 0000000000000..be5ea3cff0ece --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyObjectWithEnumConstructor.php @@ -0,0 +1,12 @@ +expectException(NotNormalizableValueException::class); - $this->expectExceptionMessage('"POST" is not a valid backing value for enum "'.StringBackedEnumDummy::class.'"'); + $this->expectException(InvalidArgumentException::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 761ea066b5962..b2a33cbc0e5db 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -36,6 +36,7 @@ use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; +use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer; use Symfony\Component\Serializer\Normalizer\CustomNormalizer; use Symfony\Component\Serializer\Normalizer\DataUriNormalizer; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; @@ -58,6 +59,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface; use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne; use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo; +use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumConstructor; use Symfony\Component\Serializer\Tests\Fixtures\FalseBuiltInDummy; use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy; use Symfony\Component\Serializer\Tests\Fixtures\Php74Full; @@ -1173,6 +1175,69 @@ public function testCollectDenormalizationErrorsWithConstructor(?ClassMetadataFa $this->assertSame($expected, $exceptionsAsArray); } + /** + * @requires PHP 8.1 + */ + public function testCollectDenormalizationErrorsWithEnumConstructor() + { + $serializer = new Serializer( + [ + new BackedEnumNormalizer(), + new ObjectNormalizer(), + ], + ['json' => new JsonEncoder()] + ); + + try { + $serializer->deserialize('{"invalid": "GET"}', DummyObjectWithEnumConstructor::class, 'json', [ + DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true, + ]); + } catch (\Throwable $th) { + $this->assertInstanceOf(PartialDenormalizationException::class, $th); + } + + $exceptionsAsArray = array_map(function (NotNormalizableValueException $e): array { + return [ + 'currentType' => $e->getCurrentType(), + 'useMessageForUser' => $e->canUseMessageForUser(), + 'message' => $e->getMessage(), + ]; + }, $th->getErrors()); + + $expected = [ + [ + 'currentType' => 'array', + 'useMessageForUser' => true, + 'message' => 'Failed to create object because the class misses the "get" property.', + ], + ]; + + $this->assertSame($expected, $exceptionsAsArray); + } + + /** + * @requires PHP 8.1 + */ + public function testNoCollectDenormalizationErrorsWithWrongEnum() + { + $serializer = new Serializer( + [ + new BackedEnumNormalizer(), + new ObjectNormalizer(), + ], + ['json' => new JsonEncoder()] + ); + + try { + $serializer->deserialize('{"get": "invalid"}', DummyObjectWithEnumConstructor::class, 'json', [ + DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true, + ]); + } catch (\Throwable $th) { + $this->assertNotInstanceOf(PartialDenormalizationException::class, $th); + $this->assertInstanceOf(InvalidArgumentException::class, $th); + } + } + public function provideCollectDenormalizationErrors() { return [