11
11
12
12
namespace Symfony \Component \Serializer \Normalizer ;
13
13
14
+ use Symfony \Component \PropertyInfo \PropertyTypeExtractorInterface ;
15
+ use Symfony \Component \Serializer \Context \ChildContextTrait ;
16
+ use Symfony \Component \Serializer \Context \ObjectChildContextTrait ;
14
17
use Symfony \Component \Serializer \Exception \CircularReferenceException ;
15
18
use Symfony \Component \Serializer \Exception \InvalidArgumentException ;
16
19
use Symfony \Component \Serializer \Exception \LogicException ;
17
20
use Symfony \Component \Serializer \Exception \MissingConstructorArgumentsException ;
18
21
use Symfony \Component \Serializer \Exception \RuntimeException ;
22
+ use Symfony \Component \Serializer \Instantiator \Instantiator ;
23
+ use Symfony \Component \Serializer \Instantiator \InstantiatorInterface ;
19
24
use Symfony \Component \Serializer \Mapping \AttributeMetadataInterface ;
25
+ use Symfony \Component \Serializer \Mapping \ClassDiscriminatorResolverInterface ;
20
26
use Symfony \Component \Serializer \Mapping \Factory \ClassMetadataFactoryInterface ;
21
27
use Symfony \Component \Serializer \NameConverter \NameConverterInterface ;
22
28
use Symfony \Component \Serializer \SerializerAwareInterface ;
27
33
*
28
34
* @author Kévin Dunglas <dunglas@gmail.com>
29
35
*/
30
- abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, CacheableSupportsMethodInterface
36
+ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface, CacheableSupportsMethodInterface, DenormalizerAwareInterface
31
37
{
32
38
use ObjectToPopulateTrait;
33
39
use SerializerAwareTrait;
40
+ use ObjectChildContextTrait;
41
+ use DenormalizerAwareTrait;
42
+ use ChildContextTrait;
34
43
35
44
/* constants to configure the context */
36
45
@@ -133,10 +142,15 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
133
142
*/
134
143
protected $ nameConverter ;
135
144
145
+ /**
146
+ * @var Instantiator|null
147
+ */
148
+ protected $ instantiator ;
149
+
136
150
/**
137
151
* Sets the {@link ClassMetadataFactoryInterface} to use.
138
152
*/
139
- public function __construct (ClassMetadataFactoryInterface $ classMetadataFactory = null , NameConverterInterface $ nameConverter = null , array $ defaultContext = [])
153
+ public function __construct (ClassMetadataFactoryInterface $ classMetadataFactory = null , NameConverterInterface $ nameConverter = null , array $ defaultContext = [], InstantiatorInterface $ instantiator = null , PropertyTypeExtractorInterface $ propertyTypeExtractor = null , ClassDiscriminatorResolverInterface $ classDiscriminatorResolver = null )
140
154
{
141
155
$ this ->classMetadataFactory = $ classMetadataFactory ;
142
156
$ this ->nameConverter = $ nameConverter ;
@@ -157,6 +171,27 @@ public function __construct(ClassMetadataFactoryInterface $classMetadataFactory
157
171
if (isset ($ this ->defaultContext [self ::CIRCULAR_REFERENCE_HANDLER ]) && !\is_callable ($ this ->defaultContext [self ::CIRCULAR_REFERENCE_HANDLER ])) {
158
172
throw new InvalidArgumentException (sprintf ('Invalid callback found in the "%s" default context option. ' , self ::CIRCULAR_REFERENCE_HANDLER ));
159
173
}
174
+
175
+ if (null === $ instantiator ) {
176
+ $ instantiator = new Instantiator ($ classMetadataFactory , $ classDiscriminatorResolver , $ propertyTypeExtractor , null , $ nameConverter , null );
177
+
178
+ if ($ this ->denormalizer instanceof DenormalizerInterface) {
179
+ $ instantiator ->setDenormalizer ($ this ->denormalizer );
180
+ }
181
+ }
182
+ $ this ->instantiator = $ instantiator ;
183
+ }
184
+
185
+ /**
186
+ * @internal
187
+ */
188
+ public function setDenormalizer (DenormalizerInterface $ denormalizer )
189
+ {
190
+ $ this ->denormalizer = $ denormalizer ;
191
+
192
+ // Because we need a denormalizer in the Instantiator and we create it in the construct method, it won't get it.
193
+ // So we are obliged to overwrite this method in order to give the denormalizer to the Instantiator.
194
+ $ this ->instantiator ->setDenormalizer ($ denormalizer );
160
195
}
161
196
162
197
/**
@@ -312,9 +347,13 @@ protected function prepareForDenormalization($data)
312
347
* @param array|bool $allowedAttributes
313
348
*
314
349
* @return \ReflectionMethod|null
350
+ *
351
+ * @deprecated since Symfony 5.3, use "instantiator_constructor" field in context array instead.
315
352
*/
316
353
protected function getConstructor (array &$ data , string $ class , array &$ context , \ReflectionClass $ reflectionClass , $ allowedAttributes )
317
354
{
355
+ trigger_deprecation ('symfony/serializer ' , '5.3 ' , 'The "%s()" method is deprecated. Use "%s" field in context array instead. ' , __METHOD__ , Instantiator::INSTANTIATOR_CONSTRUCTOR );
356
+
318
357
return $ reflectionClass ->getConstructor ();
319
358
}
320
359
@@ -332,77 +371,20 @@ protected function getConstructor(array &$data, string $class, array &$context,
332
371
*
333
372
* @throws RuntimeException
334
373
* @throws MissingConstructorArgumentsException
374
+ *
375
+ * @deprecated since Symfony 5.3, Use "Symfony\Component\Serializer\Instantiator\Instantiator::instantiate()" instead.
335
376
*/
336
377
protected function instantiateObject (array &$ data , string $ class , array &$ context , \ReflectionClass $ reflectionClass , $ allowedAttributes , string $ format = null )
337
378
{
338
- if (null !== $ object = $ this ->extractObjectToPopulate ($ class , $ context , self ::OBJECT_TO_POPULATE )) {
339
- unset($ context [self ::OBJECT_TO_POPULATE ]);
379
+ trigger_deprecation ('symfony/serializer ' , '5.3 ' , 'The "%s()" method is deprecated. Use "%s::instantiate()" instead. ' , __METHOD__ , Instantiator::class);
340
380
341
- return $ object ;
381
+ if (!\array_key_exists (Instantiator::INSTANTIATOR_CONSTRUCTOR , $ context )) {
382
+ $ context [Instantiator::INSTANTIATOR_CONSTRUCTOR ] = \Closure::fromCallable ([$ this , 'getConstructor ' ]);
342
383
}
343
- // clean up even if no match
344
- unset($ context [static ::OBJECT_TO_POPULATE ]);
345
384
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
- }
385
+ $ result = $ this ->instantiator ->instantiate ($ class , $ data , $ context , $ format );
397
386
398
- if ($ constructor ->isConstructor ()) {
399
- return $ reflectionClass ->newInstanceArgs ($ params );
400
- } else {
401
- return $ constructor ->invokeArgs (null , $ params );
402
- }
403
- }
404
-
405
- return new $ class ();
387
+ return $ result ->getObject ();
406
388
}
407
389
408
390
/**
@@ -433,18 +415,4 @@ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionPara
433
415
434
416
return $ parameterData ;
435
417
}
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
418
}
0 commit comments