1212namespace Symfony \Component \Serializer \Tests \Normalizer ;
1313
1414use PHPUnit \Framework \Attributes \DataProvider ;
15- use PHPUnit \Framework \Attributes \RequiresMethod ;
15+ use PHPUnit \Framework \Attributes \Group ;
16+ use PHPUnit \Framework \Attributes \IgnoreDeprecations ;
1617use PHPUnit \Framework \TestCase ;
1718use Symfony \Component \PropertyAccess \PropertyPath ;
1819use Symfony \Component \PropertyInfo \Extractor \PhpDocExtractor ;
@@ -979,7 +980,6 @@ public function testDenormalizeSelfConstructorPromotedParameter()
979980 $ this ->assertEquals (new DummyWithSelfConstructorPromotedParameter ('A ' , new DummyWithSelfConstructorPromotedParameter ('B ' )), $ serializer ->denormalize ($ normalized , DummyWithSelfConstructorPromotedParameter::class));
980981 }
981982
982- #[RequiresMethod(ReflectionTypeResolver::class, 'resolve ' )]
983983 public function testDenormalizeUsesConstructorUnionTypeWhenExtractorIsLessPrecise ()
984984 {
985985 $ extractor = new class implements PropertyTypeExtractorInterface {
@@ -999,6 +999,118 @@ public function getTypes(string $class, string $property, array $context = []):
999999 $ this ->assertEquals (new DummyWithIntOrString (1 ), $ serializer ->denormalize (['value ' => 1 ], DummyWithIntOrString::class));
10001000 }
10011001
1002+ public function testDenormalizeMixedConstructorParameterUsesExtractorType ()
1003+ {
1004+ $ extractor = new PropertyInfoExtractor ([], [new ReflectionExtractor ()]);
1005+
1006+ $ entityDenormalizer = new class implements DenormalizerInterface {
1007+ public function denormalize (mixed $ data , string $ type , ?string $ format = null , array $ context = []): mixed
1008+ {
1009+ return new DummyEntity ((int ) $ data );
1010+ }
1011+
1012+ public function supportsDenormalization (mixed $ data , string $ type , ?string $ format = null , array $ context = []): bool
1013+ {
1014+ return DummyEntity::class === $ type ;
1015+ }
1016+
1017+ public function getSupportedTypes (?string $ format ): array
1018+ {
1019+ return [DummyEntity::class => true ];
1020+ }
1021+ };
1022+
1023+ $ serializer = new Serializer ([
1024+ $ entityDenormalizer ,
1025+ new ObjectNormalizer (propertyTypeExtractor: $ extractor ),
1026+ ]);
1027+
1028+ $ result = $ serializer ->denormalize (['entity ' => 42 ], DummyWithMixedConstructorParamAndEntityGetter::class);
1029+
1030+ $ this ->assertInstanceOf (DummyWithMixedConstructorParamAndEntityGetter::class, $ result );
1031+ $ this ->assertInstanceOf (DummyEntity::class, $ result ->getEntity ());
1032+ $ this ->assertSame (42 , $ result ->getEntity ()->id );
1033+ }
1034+
1035+ #[Group('legacy ' )]
1036+ #[IgnoreDeprecations]
1037+ public function testDenormalizeMixedConstructorParameterUsesExtractorTypeLegacy ()
1038+ {
1039+ $ extractor = new PropertyInfoExtractor ([], [new ReflectionExtractor ()]);
1040+
1041+ $ entityDenormalizer = new class implements DenormalizerInterface {
1042+ public function denormalize (mixed $ data , string $ type , ?string $ format = null , array $ context = []): mixed
1043+ {
1044+ return new DummyEntity ((int ) $ data );
1045+ }
1046+
1047+ public function supportsDenormalization (mixed $ data , string $ type , ?string $ format = null , array $ context = []): bool
1048+ {
1049+ return DummyEntity::class === $ type ;
1050+ }
1051+
1052+ public function getSupportedTypes (?string $ format ): array
1053+ {
1054+ return [DummyEntity::class => true ];
1055+ }
1056+ };
1057+
1058+ $ serializer = new Serializer ([
1059+ $ entityDenormalizer ,
1060+ new ObjectNormalizer (propertyTypeExtractor: $ extractor ),
1061+ ]);
1062+
1063+ $ result = $ serializer ->denormalize (['entity ' => 42 ], DummyWithMixedConstructorParamAndEntityGetter::class);
1064+
1065+ $ this ->assertInstanceOf (DummyWithMixedConstructorParamAndEntityGetter::class, $ result );
1066+ $ this ->assertInstanceOf (DummyEntity::class, $ result ->getEntity ());
1067+ $ this ->assertSame (42 , $ result ->getEntity ()->id );
1068+ }
1069+
1070+ #[Group('legacy ' )]
1071+ #[IgnoreDeprecations]
1072+ public function testDenormalizeMixedConstructorParameterUsesExtractorTypeLegacyTypes ()
1073+ {
1074+ $ extractor = new class implements PropertyTypeExtractorInterface {
1075+ public function getTypes (string $ class , string $ property , array $ context = []): ?array
1076+ {
1077+ if (DummyWithMixedConstructorParamAndEntityGetter::class === $ class && 'entity ' === $ property ) {
1078+ return [new LegacyType (LegacyType::BUILTIN_TYPE_OBJECT , true , DummyEntity::class)];
1079+ }
1080+
1081+ return null ;
1082+ }
1083+ };
1084+
1085+ $ entityDenormalizer = new class implements DenormalizerInterface {
1086+ public function denormalize (mixed $ data , string $ type , ?string $ format = null , array $ context = []): mixed
1087+ {
1088+ return new DummyEntity ((int ) $ data );
1089+ }
1090+
1091+ public function supportsDenormalization (mixed $ data , string $ type , ?string $ format = null , array $ context = []): bool
1092+ {
1093+ return DummyEntity::class === $ type ;
1094+ }
1095+
1096+ public function getSupportedTypes (?string $ format ): array
1097+ {
1098+ return [DummyEntity::class => true ];
1099+ }
1100+ };
1101+
1102+ $ serializer = new Serializer ([
1103+ $ entityDenormalizer ,
1104+ new ObjectNormalizer (propertyTypeExtractor: $ extractor ),
1105+ ]);
1106+
1107+ $ result = $ serializer ->denormalize (['entity ' => 42 ], DummyWithMixedConstructorParamAndEntityGetter::class);
1108+
1109+ $ this ->assertInstanceOf (DummyWithMixedConstructorParamAndEntityGetter::class, $ result );
1110+ $ this ->assertInstanceOf (DummyEntity::class, $ result ->getEntity ());
1111+ $ this ->assertSame (42 , $ result ->getEntity ()->id );
1112+ }
1113+
10021114 public function testDenormalizeWithNumberAsSerializedNameAndNoArrayReindex ()
10031115 {
10041116 $ normalizer = new AbstractObjectNormalizerWithMetadata ();
@@ -2076,3 +2188,24 @@ class DummyGenericsValueWrapper
20762188 /** @var T[] */
20772189 public array $ values ;
20782190}
2191+
2192+ class DummyEntity
2193+ {
2194+ public function __construct (
2195+ public int $ id ,
2196+ ) {
2197+ }
2198+ }
2199+
2200+ class DummyWithMixedConstructorParamAndEntityGetter
2201+ {
2202+ public function __construct (
2203+ private mixed $ entity = null ,
2204+ ) {
2205+ }
2206+
2207+ public function getEntity (): ?DummyEntity
2208+ {
2209+ return $ this ->entity ;
2210+ }
2211+ }
0 commit comments