11
11
12
12
namespace Symfony \Component \Serializer \Normalizer ;
13
13
14
+ use Symfony \Component \PropertyInfo \PropertyTypeExtractorInterface ;
15
+ use Symfony \Component \Serializer \Context \ObjectChildContextTrait ;
14
16
use Symfony \Component \Serializer \Exception \CircularReferenceException ;
15
17
use Symfony \Component \Serializer \Exception \InvalidArgumentException ;
16
18
use Symfony \Component \Serializer \Exception \LogicException ;
17
19
use Symfony \Component \Serializer \Exception \MissingConstructorArgumentsException ;
18
20
use Symfony \Component \Serializer \Exception \RuntimeException ;
21
+ use Symfony \Component \Serializer \Instantiator \Instantiator ;
22
+ use Symfony \Component \Serializer \Instantiator \InstantiatorInterface ;
19
23
use Symfony \Component \Serializer \Mapping \AttributeMetadataInterface ;
24
+ use Symfony \Component \Serializer \Mapping \ClassDiscriminatorResolverInterface ;
20
25
use Symfony \Component \Serializer \Mapping \Factory \ClassMetadataFactoryInterface ;
21
26
use Symfony \Component \Serializer \NameConverter \NameConverterInterface ;
22
27
use Symfony \Component \Serializer \SerializerAwareInterface ;
27
32
*
28
33
* @author Kévin Dunglas <[email protected] >
29
34
*/
30
- abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, CacheableSupportsMethodInterface
35
+ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, CacheableSupportsMethodInterface, DenormalizerAwareInterface
31
36
{
32
37
use ObjectToPopulateTrait;
33
38
use SerializerAwareTrait;
39
+ use ObjectChildContextTrait;
40
+ use DenormalizerAwareTrait;
34
41
35
42
/* constants to configure the context */
36
43
@@ -133,10 +140,15 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
133
140
*/
134
141
protected $ nameConverter ;
135
142
143
+ /**
144
+ * @var Instantiator|null
145
+ */
146
+ protected $ instantiator ;
147
+
136
148
/**
137
149
* Sets the {@link ClassMetadataFactoryInterface} to use.
138
150
*/
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 )
140
152
{
141
153
$ this ->classMetadataFactory = $ classMetadataFactory ;
142
154
$ this ->nameConverter = $ nameConverter ;
@@ -157,6 +169,24 @@ public function __construct(ClassMetadataFactoryInterface $classMetadataFactory
157
169
if (isset ($ this ->defaultContext [self ::CIRCULAR_REFERENCE_HANDLER ]) && !\is_callable ($ this ->defaultContext [self ::CIRCULAR_REFERENCE_HANDLER ])) {
158
170
throw new InvalidArgumentException (sprintf ('Invalid callback found in the "%s" default context option. ' , self ::CIRCULAR_REFERENCE_HANDLER ));
159
171
}
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 );
160
190
}
161
191
162
192
/**
@@ -312,6 +342,8 @@ protected function prepareForDenormalization($data)
312
342
* @param array|bool $allowedAttributes
313
343
*
314
344
* @return \ReflectionMethod|null
345
+ *
346
+ * @deprecated
315
347
*/
316
348
protected function getConstructor (array &$ data , string $ class , array &$ context , \ReflectionClass $ reflectionClass , $ allowedAttributes )
317
349
{
@@ -332,77 +364,18 @@ protected function getConstructor(array &$data, string $class, array &$context,
332
364
*
333
365
* @throws RuntimeException
334
366
* @throws MissingConstructorArgumentsException
367
+ *
368
+ * @deprecated
335
369
*/
336
370
protected function instantiateObject (array &$ data , string $ class , array &$ context , \ReflectionClass $ reflectionClass , $ allowedAttributes , string $ format = null )
337
371
{
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 ' ]);
342
374
}
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
- }
397
375
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 );
404
377
405
- return new $ class ();
378
+ return $ result -> getObject ();
406
379
}
407
380
408
381
/**
@@ -433,18 +406,4 @@ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionPara
433
406
434
407
return $ parameterData ;
435
408
}
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
- }
450
409
}
0 commit comments