1111
1212namespace Symfony \Component \Serializer \Normalizer ;
1313
14+ use Symfony \Component \PropertyInfo \PropertyTypeExtractorInterface ;
15+ use Symfony \Component \Serializer \Context \ObjectChildContextTrait ;
1416use Symfony \Component \Serializer \Exception \CircularReferenceException ;
1517use Symfony \Component \Serializer \Exception \InvalidArgumentException ;
1618use Symfony \Component \Serializer \Exception \LogicException ;
1719use Symfony \Component \Serializer \Exception \MissingConstructorArgumentsException ;
1820use Symfony \Component \Serializer \Exception \RuntimeException ;
21+ use Symfony \Component \Serializer \Instantiator \Instantiator ;
22+ use Symfony \Component \Serializer \Instantiator \InstantiatorInterface ;
1923use Symfony \Component \Serializer \Mapping \AttributeMetadataInterface ;
24+ use Symfony \Component \Serializer \Mapping \ClassDiscriminatorResolverInterface ;
2025use Symfony \Component \Serializer \Mapping \Factory \ClassMetadataFactoryInterface ;
2126use Symfony \Component \Serializer \NameConverter \NameConverterInterface ;
2227use Symfony \Component \Serializer \SerializerAwareInterface ;
2732 *
2833 * @author Kévin Dunglas <[email protected] > 2934 */
30- abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, CacheableSupportsMethodInterface
35+ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, CacheableSupportsMethodInterface, DenormalizerAwareInterface
3136{
3237 use ObjectToPopulateTrait;
3338 use SerializerAwareTrait;
39+ use ObjectChildContextTrait;
40+ use DenormalizerAwareTrait;
3441
3542 /* constants to configure the context */
3643
@@ -133,10 +140,15 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
133140 */
134141 protected $ nameConverter ;
135142
143+ /**
144+ * @var Instantiator|null
145+ */
146+ protected $ instantiator ;
147+
136148 /**
137149 * Sets the {@link ClassMetadataFactoryInterface} to use.
138150 */
139- public function __construct (ClassMetadataFactoryInterface $ classMetadataFactory = null , NameConverterInterface $ nameConverter = null , array $ defaultContext = [])
151+ public function __construct (ClassMetadataFactoryInterface $ classMetadataFactory = null , NameConverterInterface $ nameConverter = null , array $ defaultContext = [], InstantiatorInterface $ instantiator = null , PropertyTypeExtractorInterface $ propertyTypeExtractor = null , ClassDiscriminatorResolverInterface $ classDiscriminatorResolver = null )
140152 {
141153 $ this ->classMetadataFactory = $ classMetadataFactory ;
142154 $ this ->nameConverter = $ nameConverter ;
@@ -157,6 +169,24 @@ public function __construct(ClassMetadataFactoryInterface $classMetadataFactory
157169 if (isset ($ this ->defaultContext [self ::CIRCULAR_REFERENCE_HANDLER ]) && !\is_callable ($ this ->defaultContext [self ::CIRCULAR_REFERENCE_HANDLER ])) {
158170 throw new InvalidArgumentException (sprintf ('Invalid callback found in the "%s" default context option. ' , self ::CIRCULAR_REFERENCE_HANDLER ));
159171 }
172+
173+ if (null === $ instantiator ) {
174+ $ instantiator = new Instantiator ($ classMetadataFactory , $ classDiscriminatorResolver , $ propertyTypeExtractor , null , $ nameConverter , null );
175+
176+ if ($ this ->denormalizer instanceof DenormalizerInterface) {
177+ $ instantiator ->setDenormalizer ($ this ->denormalizer );
178+ }
179+ }
180+ $ this ->instantiator = $ instantiator ;
181+ }
182+
183+ public function setDenormalizer (DenormalizerInterface $ denormalizer )
184+ {
185+ $ this ->denormalizer = $ denormalizer ;
186+
187+ // Because we need a denormalizer in the Instantiator and we create it in the construct method, it won't get it.
188+ // So we are obliged to overwrite this method in order to give the denormalizer to the Instantiator.
189+ $ this ->instantiator ->setDenormalizer ($ denormalizer );
160190 }
161191
162192 /**
@@ -312,6 +342,8 @@ protected function prepareForDenormalization($data)
312342 * @param array|bool $allowedAttributes
313343 *
314344 * @return \ReflectionMethod|null
345+ *
346+ * @deprecated
315347 */
316348 protected function getConstructor (array &$ data , string $ class , array &$ context , \ReflectionClass $ reflectionClass , $ allowedAttributes )
317349 {
@@ -332,77 +364,18 @@ protected function getConstructor(array &$data, string $class, array &$context,
332364 *
333365 * @throws RuntimeException
334366 * @throws MissingConstructorArgumentsException
367+ *
368+ * @deprecated
335369 */
336370 protected function instantiateObject (array &$ data , string $ class , array &$ context , \ReflectionClass $ reflectionClass , $ allowedAttributes , string $ format = null )
337371 {
338- if (null !== $ object = $ this ->extractObjectToPopulate ($ class , $ context , self ::OBJECT_TO_POPULATE )) {
339- unset($ context [self ::OBJECT_TO_POPULATE ]);
340-
341- return $ object ;
372+ if (!\array_key_exists (Instantiator::INSTANTIATOR_CONSTRUCTOR , $ context )) {
373+ $ context [Instantiator::INSTANTIATOR_CONSTRUCTOR ] = \Closure::fromCallable ([$ this , 'getConstructor ' ]);
342374 }
343- // clean up even if no match
344- unset($ context [static ::OBJECT_TO_POPULATE ]);
345-
346- $ constructor = $ this ->getConstructor ($ data , $ class , $ context , $ reflectionClass , $ allowedAttributes );
347- if ($ constructor ) {
348- if (true !== $ constructor ->isPublic ()) {
349- return $ reflectionClass ->newInstanceWithoutConstructor ();
350- }
351-
352- $ constructorParameters = $ constructor ->getParameters ();
353-
354- $ params = [];
355- foreach ($ constructorParameters as $ constructorParameter ) {
356- $ paramName = $ constructorParameter ->name ;
357- $ key = $ this ->nameConverter ? $ this ->nameConverter ->normalize ($ paramName , $ class , $ format , $ context ) : $ paramName ;
358-
359- $ allowed = false === $ allowedAttributes || \in_array ($ paramName , $ allowedAttributes );
360- $ ignored = !$ this ->isAllowedAttribute ($ class , $ paramName , $ format , $ context );
361- if ($ constructorParameter ->isVariadic ()) {
362- if ($ allowed && !$ ignored && (isset ($ data [$ key ]) || \array_key_exists ($ key , $ data ))) {
363- if (!\is_array ($ data [$ paramName ])) {
364- throw new RuntimeException (sprintf ('Cannot create an instance of "%s" from serialized data because the variadic parameter "%s" can only accept an array. ' , $ class , $ constructorParameter ->name ));
365- }
366-
367- $ variadicParameters = [];
368- foreach ($ data [$ paramName ] as $ parameterData ) {
369- $ variadicParameters [] = $ this ->denormalizeParameter ($ reflectionClass , $ constructorParameter , $ paramName , $ parameterData , $ context , $ format );
370- }
371-
372- $ params = array_merge ($ params , $ variadicParameters );
373- unset($ data [$ key ]);
374- }
375- } elseif ($ allowed && !$ ignored && (isset ($ data [$ key ]) || \array_key_exists ($ key , $ data ))) {
376- $ parameterData = $ data [$ key ];
377- if (null === $ parameterData && $ constructorParameter ->allowsNull ()) {
378- $ params [] = null ;
379- // Don't run set for a parameter passed to the constructor
380- unset($ data [$ key ]);
381- continue ;
382- }
383-
384- // Don't run set for a parameter passed to the constructor
385- $ params [] = $ this ->denormalizeParameter ($ reflectionClass , $ constructorParameter , $ paramName , $ parameterData , $ context , $ format );
386- unset($ data [$ key ]);
387- } elseif (\array_key_exists ($ key , $ context [static ::DEFAULT_CONSTRUCTOR_ARGUMENTS ][$ class ] ?? [])) {
388- $ params [] = $ context [static ::DEFAULT_CONSTRUCTOR_ARGUMENTS ][$ class ][$ key ];
389- } elseif (\array_key_exists ($ key , $ this ->defaultContext [self ::DEFAULT_CONSTRUCTOR_ARGUMENTS ][$ class ] ?? [])) {
390- $ params [] = $ this ->defaultContext [self ::DEFAULT_CONSTRUCTOR_ARGUMENTS ][$ class ][$ key ];
391- } elseif ($ constructorParameter ->isDefaultValueAvailable ()) {
392- $ params [] = $ constructorParameter ->getDefaultValue ();
393- } else {
394- throw new MissingConstructorArgumentsException (sprintf ('Cannot create an instance of "%s" from serialized data because its constructor requires parameter "%s" to be present. ' , $ class , $ constructorParameter ->name ));
395- }
396- }
397375
398- if ($ constructor ->isConstructor ()) {
399- return $ reflectionClass ->newInstanceArgs ($ params );
400- } else {
401- return $ constructor ->invokeArgs (null , $ params );
402- }
403- }
376+ $ result = $ this ->instantiator ->instantiate ($ class , $ data , $ context , $ format );
404377
405- return new $ class ();
378+ return $ result -> getObject ();
406379 }
407380
408381 /**
@@ -433,18 +406,4 @@ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionPara
433406
434407 return $ parameterData ;
435408 }
436-
437- /**
438- * @internal
439- */
440- protected function createChildContext (array $ parentContext , string $ attribute , ?string $ format ): array
441- {
442- if (isset ($ parentContext [self ::ATTRIBUTES ][$ attribute ])) {
443- $ parentContext [self ::ATTRIBUTES ] = $ parentContext [self ::ATTRIBUTES ][$ attribute ];
444- } else {
445- unset($ parentContext [self ::ATTRIBUTES ]);
446- }
447-
448- return $ parentContext ;
449- }
450409}
0 commit comments