11
11
12
12
namespace Symfony \Component \Serializer \Normalizer ;
13
13
14
+ use Symfony \Component \PropertyInfo \PropertyTypeExtractorInterface ;
15
+ use Symfony \Component \Serializer \Context \ChildContextTrait ;
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 DenormalizerAwareTrait;
40
+ use ChildContextTrait;
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,27 @@ 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
+ /**
184
+ * @internal
185
+ */
186
+ public function setDenormalizer (DenormalizerInterface $ denormalizer )
187
+ {
188
+ $ this ->denormalizer = $ denormalizer ;
189
+
190
+ // Because we need a denormalizer in the Instantiator and we create it in the construct method, it won't get it.
191
+ // So we are obliged to overwrite this method in order to give the denormalizer to the Instantiator.
192
+ $ this ->instantiator ->setDenormalizer ($ denormalizer );
160
193
}
161
194
162
195
/**
@@ -312,9 +345,13 @@ protected function prepareForDenormalization($data)
312
345
* @param array|bool $allowedAttributes
313
346
*
314
347
* @return \ReflectionMethod|null
348
+ *
349
+ * @deprecated since Symfony 5.3, use "instantiator_constructor" field in context array instead.
315
350
*/
316
351
protected function getConstructor (array &$ data , string $ class , array &$ context , \ReflectionClass $ reflectionClass , $ allowedAttributes )
317
352
{
353
+ trigger_deprecation ('symfony/serializer ' , '5.3 ' , 'The "%s()" method is deprecated. Use "%s" field in context array instead. ' , __METHOD__ , Instantiator::INSTANTIATOR_CONSTRUCTOR );
354
+
318
355
return $ reflectionClass ->getConstructor ();
319
356
}
320
357
@@ -332,77 +369,20 @@ protected function getConstructor(array &$data, string $class, array &$context,
332
369
*
333
370
* @throws RuntimeException
334
371
* @throws MissingConstructorArgumentsException
372
+ *
373
+ * @deprecated since Symfony 5.3, Use "Symfony\Component\Serializer\Instantiator\Instantiator::instantiate()" instead.
335
374
*/
336
375
protected function instantiateObject (array &$ data , string $ class , array &$ context , \ReflectionClass $ reflectionClass , $ allowedAttributes , string $ format = null )
337
376
{
338
- if (null !== $ object = $ this ->extractObjectToPopulate ($ class , $ context , self ::OBJECT_TO_POPULATE )) {
339
- unset($ context [self ::OBJECT_TO_POPULATE ]);
377
+ trigger_deprecation ('symfony/serializer ' , '5.3 ' , 'The "%s()" method is deprecated. Use "%s::instantiate()" instead. ' , __METHOD__ , Instantiator::class);
340
378
341
- return $ object ;
379
+ if (!\array_key_exists (Instantiator::INSTANTIATOR_CONSTRUCTOR , $ context )) {
380
+ $ context [Instantiator::INSTANTIATOR_CONSTRUCTOR ] = \Closure::fromCallable ([$ this , 'getConstructor ' ]);
342
381
}
343
- // clean up even if no match
344
- unset($ context [static ::OBJECT_TO_POPULATE ]);
345
382
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
- }
383
+ $ result = $ this ->instantiator ->instantiate ($ class , $ data , $ context , $ format );
397
384
398
- if ($ constructor ->isConstructor ()) {
399
- return $ reflectionClass ->newInstanceArgs ($ params );
400
- } else {
401
- return $ constructor ->invokeArgs (null , $ params );
402
- }
403
- }
404
-
405
- return new $ class ();
385
+ return $ result ->getObject ();
406
386
}
407
387
408
388
/**
@@ -433,18 +413,4 @@ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionPara
433
413
434
414
return $ parameterData ;
435
415
}
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
416
}
0 commit comments