Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c9cb10d

Browse files
committed
fix: deserialization union type of enum
1 parent 01dc108 commit c9cb10d

File tree

4 files changed

+67
-24
lines changed

4 files changed

+67
-24
lines changed

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Serializer\Encoder\CsvEncoder;
2020
use Symfony\Component\Serializer\Encoder\JsonEncoder;
2121
use Symfony\Component\Serializer\Encoder\XmlEncoder;
22+
use Symfony\Component\Serializer\Exception\ExceptionInterface;
2223
use Symfony\Component\Serializer\Exception\ExtraAttributesException;
2324
use Symfony\Component\Serializer\Exception\LogicException;
2425
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
@@ -450,8 +451,7 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
450451
{
451452
$expectedTypes = [];
452453
$isUnionType = \count($types) > 1;
453-
$extraAttributesException = null;
454-
$missingConstructorArgumentException = null;
454+
$exception = null;
455455
foreach ($types as $type) {
456456
if (null === $data && $type->isNullable()) {
457457
return null;
@@ -585,35 +585,19 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
585585
if (('is_'.$builtinType)($data)) {
586586
return $data;
587587
}
588-
} catch (NotNormalizableValueException $e) {
589-
if (!$isUnionType) {
590-
throw $e;
591-
}
592-
} catch (ExtraAttributesException $e) {
593-
if (!$isUnionType) {
594-
throw $e;
595-
}
596-
597-
if (!$extraAttributesException) {
598-
$extraAttributesException = $e;
599-
}
600-
} catch (MissingConstructorArgumentsException $e) {
588+
} catch (ExceptionInterface $e) {
601589
if (!$isUnionType) {
602590
throw $e;
603591
}
604592

605-
if (!$missingConstructorArgumentException) {
606-
$missingConstructorArgumentException = $e;
593+
if (!$exception) {
594+
$exception = $e;
607595
}
608596
}
609597
}
610598

611-
if ($extraAttributesException) {
612-
throw $extraAttributesException;
613-
}
614-
615-
if ($missingConstructorArgumentException) {
616-
throw $missingConstructorArgumentException;
599+
if ($exception) {
600+
throw $exception;
617601
}
618602

619603
if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) {

src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public function denormalize($data, string $type, string $format = null, array $c
6363

6464
try {
6565
return $type::from($data);
66-
} catch (\ValueError $e) {
66+
} catch (\ValueError|\TypeError $e) {
6767
throw new InvalidArgumentException('The data must belong to a backed enumeration of type '.$type);
6868
}
6969
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Symfony\Component\Serializer\Tests\Fixtures;
4+
5+
class DummyObjectWithUnionEnumConstructor
6+
{
7+
public function __construct(public StringBackedEnumDummy|IntegerBackedEnumDummy $sub)
8+
{
9+
}
10+
}

src/Symfony/Component/Serializer/Tests/SerializerTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,13 @@
6060
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne;
6161
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo;
6262
use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumConstructor;
63+
use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithUnionEnumConstructor;
6364
use Symfony\Component\Serializer\Tests\Fixtures\FalseBuiltInDummy;
65+
use Symfony\Component\Serializer\Tests\Fixtures\IntegerBackedEnumDummy;
6466
use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy;
6567
use Symfony\Component\Serializer\Tests\Fixtures\Php74Full;
6668
use Symfony\Component\Serializer\Tests\Fixtures\Php80WithPromotedTypedConstructor;
69+
use Symfony\Component\Serializer\Tests\Fixtures\StringBackedEnumDummy;
6770
use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy;
6871
use Symfony\Component\Serializer\Tests\Normalizer\TestDenormalizer;
6972
use Symfony\Component\Serializer\Tests\Normalizer\TestNormalizer;
@@ -790,6 +793,52 @@ public function testUnionTypeDeserializableWithoutAllowedExtraAttributes()
790793
]);
791794
}
792795

796+
/**
797+
* @requires PHP 8.1
798+
*/
799+
public function testEnumUnionTypeDeserializable()
800+
{
801+
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
802+
$extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]);
803+
804+
$serializer = new Serializer(
805+
[
806+
new BackedEnumNormalizer(),
807+
new ObjectNormalizer($classMetadataFactory, null, null, $extractor, new ClassDiscriminatorFromClassMetadata($classMetadataFactory)),
808+
],
809+
['json' => new JsonEncoder()]
810+
);
811+
812+
$actual = $serializer->deserialize('{"sub": 200}', DummyObjectWithUnionEnumConstructor::class, 'json');
813+
$this->assertEquals(new DummyObjectWithUnionEnumConstructor(IntegerBackedEnumDummy::SUCCESS), $actual);
814+
815+
$actual = $serializer->deserialize('{"sub": "GET"}', DummyObjectWithUnionEnumConstructor::class, 'json');
816+
$this->assertEquals(new DummyObjectWithUnionEnumConstructor(StringBackedEnumDummy::GET), $actual);
817+
}
818+
819+
/**
820+
* @requires PHP 8.1
821+
*/
822+
public function testEnumUnionTypeDeserializationWithWrongEnum()
823+
{
824+
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
825+
$extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]);
826+
827+
$serializer = new Serializer(
828+
[
829+
new BackedEnumNormalizer(),
830+
new ObjectNormalizer($classMetadataFactory, null, null, $extractor, new ClassDiscriminatorFromClassMetadata($classMetadataFactory)),
831+
],
832+
['json' => new JsonEncoder()]
833+
);
834+
835+
try {
836+
$serializer->deserialize('{"sub": "INVALID"}', DummyObjectWithUnionEnumConstructor::class, 'json');
837+
} catch (\Throwable $th) {
838+
$this->assertInstanceOf(InvalidArgumentException::class, $th);
839+
}
840+
}
841+
793842
/**
794843
* @requires PHP 8.2
795844
*/

0 commit comments

Comments
 (0)