diff --git a/UPGRADE-5.1.md b/UPGRADE-5.1.md index 6a0244b9b8eb5..7633570a260e0 100644 --- a/UPGRADE-5.1.md +++ b/UPGRADE-5.1.md @@ -23,3 +23,8 @@ Routing ------- * Deprecated `RouteCollectionBuilder` in favor of `RoutingConfigurator`. + +Serializer +---------- + + * Deprecated passing a name converter directly to the second argument of the constructor of `AbstractNormalizer`, pass an array of name converters instead. diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml index 0dbc388ddffcb..a0dcaa0ee01c2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml @@ -72,7 +72,10 @@ - + + + + diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index ab845f736cfa0..7e951c3819145 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -5,6 +5,8 @@ CHANGELOG ----- * added support for scalar values denormalization + * changed the name converter constructor argument in normalizers to an array of name converters + * added `AbstractNormalizer::NAME_CONVERTER` constant to set the name converter to use in context 5.0.0 ----- diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 13387e2bc818f..7661c1070fba1 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -111,6 +111,15 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn */ public const IGNORED_ATTRIBUTES = 'ignored_attributes'; + /** + * The name converter to use when (de)normalizing a property. + * + * It has to correspond of a class of the given name converters. + * + * If not specified or if it does not exist, the first name converter will be used if available. + */ + public const NAME_CONVERTER = 'name_converter'; + /** * @internal */ @@ -130,16 +139,30 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn /** * @var NameConverterInterface|null + * + * @deprecated since Symfony 5.1, use $nameConverters instead. */ protected $nameConverter; + /** + * @var array + */ + protected $nameConverters = []; + /** * Sets the {@link ClassMetadataFactoryInterface} to use. */ - public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null, array $defaultContext = []) + public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, /* array */ $nameConverter/*s*/ = [], array $defaultContext = []) { $this->classMetadataFactory = $classMetadataFactory; - $this->nameConverter = $nameConverter; + if (!\is_array($nameConverter)) { + @trigger_error(sprintf('The 2nd constructor argument of the class "%s" should be an array of name converters, using a name converter directly or null is deprecated since Symfony 5.1.', __CLASS__), E_USER_DEPRECATED); + $this->nameConverter = $nameConverter; + } else { + foreach ($nameConverter as $nameConverterInstance) { + $this->nameConverters[\get_class($nameConverterInstance)] = $nameConverterInstance; + } + } $this->defaultContext = array_merge($this->defaultContext, $defaultContext); if (isset($this->defaultContext[self::CALLBACKS])) { @@ -347,7 +370,14 @@ protected function instantiateObject(array &$data, string $class, array &$contex $params = []; foreach ($constructorParameters as $constructorParameter) { $paramName = $constructorParameter->name; - $key = $this->nameConverter ? $this->nameConverter->normalize($paramName, $class, $format, $context) : $paramName; + $key = $paramName; + if (\count($this->nameConverters) > 0) { + $nameConverter = $this->nameConverters[$context[static::NAME_CONVERTER] ?? null] ?? reset($this->nameConverters); + $key = $nameConverter->normalize($paramName, $class, $format, $context); + } elseif ($this->nameConverter) { + @trigger_error(sprintf('Using the "nameConverter" property of the class "%s" is deprecated since Symfony 5.1, use the "nameConverters" property instead.', __CLASS__), E_USER_DEPRECATED); + $key = $this->nameConverter->normalize($paramName, $class, $format, $context); + } $allowed = false === $allowedAttributes || \in_array($paramName, $allowedAttributes); $ignored = !$this->isAllowedAttribute($class, $paramName, $format, $context); diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 38b3498413554..17a935adc07ef 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -24,7 +24,6 @@ use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; -use Symfony\Component\Serializer\NameConverter\NameConverterInterface; /** * Base class for a normalizer dealing with objects. @@ -101,7 +100,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer */ protected $classDiscriminatorResolver; - public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null, PropertyTypeExtractorInterface $propertyTypeExtractor = null, ClassDiscriminatorResolverInterface $classDiscriminatorResolver = null, callable $objectClassResolver = null, array $defaultContext = []) + public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, /* array */ $nameConverter/*s*/ = [], PropertyTypeExtractorInterface $propertyTypeExtractor = null, ClassDiscriminatorResolverInterface $classDiscriminatorResolver = null, callable $objectClassResolver = null, array $defaultContext = []) { parent::__construct($classMetadataFactory, $nameConverter, $defaultContext); @@ -309,7 +308,11 @@ public function denormalize($data, string $type, string $format = null, array $c $resolvedClass = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object); foreach ($normalizedData as $attribute => $value) { - if ($this->nameConverter) { + if (\count($this->nameConverters) > 0) { + $nameConverter = $this->nameConverters[$context[static::NAME_CONVERTER] ?? null] ?? reset($this->nameConverters); + $attribute = $nameConverter->denormalize($attribute, $resolvedClass, $format, $context); + } elseif ($this->nameConverter) { + @trigger_error(sprintf('Using the "nameConverter" property of the class "%s" is deprecated since Symfony 5.1, use the "nameConverters" property instead.', __CLASS__), E_USER_DEPRECATED); $attribute = $this->nameConverter->denormalize($attribute, $resolvedClass, $format, $context); } @@ -505,7 +508,11 @@ private function updateData(array $data, string $attribute, $attributeValue, str return $data; } - if ($this->nameConverter) { + if (\count($this->nameConverters) > 0) { + $nameConverter = $this->nameConverters[$context[static::NAME_CONVERTER] ?? null] ?? reset($this->nameConverters); + $attribute = $nameConverter->normalize($attribute, $class, $format, $context); + } elseif ($this->nameConverter) { + @trigger_error(sprintf('Using the "nameConverter" property of the class "%s" is deprecated since Symfony 5.1, use the "nameConverters" property instead.', __CLASS__), E_USER_DEPRECATED); $attribute = $this->nameConverter->normalize($attribute, $class, $format, $context); } diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php index 81fe9c1166797..a10a2db930e6b 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php @@ -19,7 +19,6 @@ use Symfony\Component\Serializer\Mapping\AttributeMetadata; use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; -use Symfony\Component\Serializer\NameConverter\NameConverterInterface; /** * Converts between objects and arrays using the PropertyAccess component. @@ -34,7 +33,7 @@ class ObjectNormalizer extends AbstractObjectNormalizer private $objectClassResolver; - public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null, PropertyAccessorInterface $propertyAccessor = null, PropertyTypeExtractorInterface $propertyTypeExtractor = null, ClassDiscriminatorResolverInterface $classDiscriminatorResolver = null, callable $objectClassResolver = null, array $defaultContext = []) + public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, /* array */ $nameConverter/*s*/ = [], PropertyAccessorInterface $propertyAccessor = null, PropertyTypeExtractorInterface $propertyTypeExtractor = null, ClassDiscriminatorResolverInterface $classDiscriminatorResolver = null, callable $objectClassResolver = null, array $defaultContext = []) { if (!class_exists(PropertyAccess::class)) { throw new LogicException('The ObjectNormalizer class requires the "PropertyAccess" component. Install "symfony/property-access" to use it.'); diff --git a/src/Symfony/Component/Serializer/Tests/DeserializeNestedArrayOfObjectsTest.php b/src/Symfony/Component/Serializer/Tests/DeserializeNestedArrayOfObjectsTest.php index 654a6c6e90717..66c578744f615 100644 --- a/src/Symfony/Component/Serializer/Tests/DeserializeNestedArrayOfObjectsTest.php +++ b/src/Symfony/Component/Serializer/Tests/DeserializeNestedArrayOfObjectsTest.php @@ -44,7 +44,7 @@ public function testPropertyPhpDoc($class) } EOF; $serializer = new Serializer([ - new ObjectNormalizer(null, null, null, new PhpDocExtractor()), + new ObjectNormalizer(null, [], null, new PhpDocExtractor()), new ArrayDenormalizer(), ], ['json' => new JsonEncoder()]); //WHEN diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php index cc84452cbe487..7dd277606ff54 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php @@ -7,6 +7,7 @@ use Symfony\Component\Serializer\Mapping\AttributeMetadata; use Symfony\Component\Serializer\Mapping\ClassMetadata; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; +use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Normalizer\PropertyNormalizer; @@ -134,4 +135,13 @@ public function testObjectWithVariadicConstructorTypedArguments() $this->assertInstanceOf(Dummy::class, $foo); } } + + /** + * @group legacy + * @expectedDeprecation The 2nd constructor argument of the class "Symfony\Component\Serializer\Normalizer\AbstractNormalizer" should be an array of name converters, using a name converter directly or null is deprecated since Symfony 5.1. + */ + public function testConstructNameConverter() + { + new AbstractNormalizerDummy($this->classMetadata, new CamelCaseToSnakeCaseNameConverter()); + } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index 0ea075e056b57..a721d352e7f81 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -136,7 +136,7 @@ private function getDenormalizerForDummyCollection() null )); - $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor); + $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, [], $extractor); $arrayDenormalizer = new ArrayDenormalizerDummy(); $serializer = new SerializerCollectionDummy([$arrayDenormalizer, $denormalizer]); $arrayDenormalizer->setSerializer($serializer); @@ -183,7 +183,7 @@ private function getDenormalizerForStringCollection() null )); - $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor); + $denormalizer = new AbstractObjectNormalizerCollectionDummy(null, [], $extractor); $arrayDenormalizer = new ArrayDenormalizerDummy(); $serializer = new SerializerCollectionDummy([$arrayDenormalizer, $denormalizer]); $arrayDenormalizer->setSerializer($serializer); @@ -219,7 +219,7 @@ public function hasMetadataFor($value): bool }; $discriminatorResolver = new ClassDiscriminatorFromClassMetadata($loaderMock); - $normalizer = new AbstractObjectNormalizerDummy($factory, null, new PhpDocExtractor(), $discriminatorResolver); + $normalizer = new AbstractObjectNormalizerDummy($factory, [], new PhpDocExtractor(), $discriminatorResolver); $serializer = new Serializer([$normalizer]); $normalizer->setSerializer($serializer); $normalizedData = $normalizer->denormalize(['foo' => 'foo', 'baz' => 'baz', 'quux' => ['value' => 'quux'], 'type' => 'second'], AbstractDummy::class); diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php index bc5eb596e1dd2..be619281bb66d 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php @@ -67,7 +67,7 @@ protected function setUp(): void private function createNormalizer(array $defaultContext = []) { $this->serializer = $this->getMockBuilder(SerializerNormalizer::class)->getMock(); - $this->normalizer = new GetSetMethodNormalizer(null, null, null, null, null, $defaultContext); + $this->normalizer = new GetSetMethodNormalizer(null, [], null, null, null, $defaultContext); $this->normalizer->setSerializer($this->serializer); } @@ -228,13 +228,13 @@ protected function getNormalizerForCallbacks(): GetSetMethodNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - return new GetSetMethodNormalizer($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory)); + return new GetSetMethodNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory)]); } protected function getNormalizerForCircularReference(): GetSetMethodNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $normalizer = new GetSetMethodNormalizer($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory)); + $normalizer = new GetSetMethodNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory)]); new Serializer([$normalizer]); return $normalizer; @@ -248,7 +248,7 @@ protected function getSelfReferencingModel() protected function getDenormalizerForConstructArguments(): GetSetMethodNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $denormalizer = new GetSetMethodNormalizer($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory)); + $denormalizer = new GetSetMethodNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory)]); new Serializer([$denormalizer]); return $denormalizer; @@ -268,7 +268,11 @@ protected function getDenormalizerForGroups(): GetSetMethodNormalizer return new GetSetMethodNormalizer($classMetadataFactory); } - public function testGroupsNormalizeWithNameConverter() + /** + * @group legacy + * @expectedDeprecation Using the "nameConverter" property of the class "Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer" is deprecated since Symfony 5.1, use the "nameConverters" property instead. + */ + public function testGroupsNormalizeWithDirectNameConverter() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); @@ -289,10 +293,52 @@ public function testGroupsNormalizeWithNameConverter() ); } + public function testGroupsNormalizeWithNameConverter() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, [new CamelCaseToSnakeCaseNameConverter()]); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + $obj->setCoopTilleuls('les-tilleuls.coop'); + + $this->assertEquals( + [ + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + ], + $this->normalizer->normalize($obj, null, [GetSetMethodNormalizer::GROUPS => ['name_converter']]) + ); + } + + public function testGroupsNormalizeWithNameConverters() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory), new CamelCaseToSnakeCaseNameConverter()]); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + $obj->setCoopTilleuls('les-tilleuls.coop'); + + $this->assertEquals( + [ + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + ], + $this->normalizer->normalize($obj, null, [GetSetMethodNormalizer::GROUPS => ['name_converter'], GetSetMethodNormalizer::NAME_CONVERTER => CamelCaseToSnakeCaseNameConverter::class]) + ); + } + public function testGroupsDenormalizeWithNameConverter() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); + $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, [new CamelCaseToSnakeCaseNameConverter()]); $this->normalizer->setSerializer($this->serializer); $obj = new GroupDummy(); @@ -310,6 +356,27 @@ public function testGroupsDenormalizeWithNameConverter() ); } + public function testGroupsDenormalizeWithNameConverters() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory), new CamelCaseToSnakeCaseNameConverter()]); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + + $this->assertEquals( + $obj, + $this->normalizer->denormalize([ + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + 'coop_tilleuls' => 'les-tilleuls.coop', + ], 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', null, [GetSetMethodNormalizer::GROUPS => ['name_converter'], GetSetMethodNormalizer::NAME_CONVERTER => CamelCaseToSnakeCaseNameConverter::class]) + ); + } + protected function getNormalizerForMaxDepth(): NormalizerInterface { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); @@ -323,7 +390,7 @@ protected function getNormalizerForMaxDepth(): NormalizerInterface protected function getDenormalizerForObjectToPopulate(): DenormalizerInterface { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $normalizer = new GetSetMethodNormalizer($classMetadataFactory, null, new PhpDocExtractor()); + $normalizer = new GetSetMethodNormalizer($classMetadataFactory, [], new PhpDocExtractor()); new Serializer([$normalizer]); return $normalizer; @@ -332,7 +399,7 @@ protected function getDenormalizerForObjectToPopulate(): DenormalizerInterface protected function getDenormalizerForTypeEnforcement(): DenormalizerInterface { $extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]); - $normalizer = new GetSetMethodNormalizer(null, null, $extractor); + $normalizer = new GetSetMethodNormalizer(null, [], $extractor); $serializer = new Serializer([new ArrayDenormalizer(), $normalizer]); $normalizer->setSerializer($serializer); @@ -347,7 +414,7 @@ public function testRejectInvalidKey() protected function getNormalizerForIgnoredAttributes(): GetSetMethodNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $normalizer = new GetSetMethodNormalizer($classMetadataFactory, null, new PhpDocExtractor()); + $normalizer = new GetSetMethodNormalizer($classMetadataFactory, [], new PhpDocExtractor()); new Serializer([$normalizer]); return $normalizer; @@ -356,7 +423,7 @@ protected function getNormalizerForIgnoredAttributes(): GetSetMethodNormalizer protected function getDenormalizerForIgnoredAttributes(): GetSetMethodNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $normalizer = new GetSetMethodNormalizer($classMetadataFactory, null, new PhpDocExtractor()); + $normalizer = new GetSetMethodNormalizer($classMetadataFactory, [], new PhpDocExtractor()); new Serializer([$normalizer]); return $normalizer; diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/JsonSerializableNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/JsonSerializableNormalizerTest.php index 9222823da3f17..7b05ab6535891 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/JsonSerializableNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/JsonSerializableNormalizerTest.php @@ -41,7 +41,7 @@ protected function setUp(): void private function createNormalizer(array $defaultContext = []) { $this->serializer = $this->getMockBuilder(JsonSerializerNormalizer::class)->getMock(); - $this->normalizer = new JsonSerializableNormalizer(null, null, $defaultContext); + $this->normalizer = new JsonSerializableNormalizer(null, [], $defaultContext); $this->normalizer->setSerializer($this->serializer); } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index aca0ded3ab4ec..8bfaee9f1dd4b 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -78,7 +78,7 @@ protected function setUp(): void private function createNormalizer(array $defaultContext = [], ClassMetadataFactoryInterface $classMetadataFactory = null) { $this->serializer = $this->getMockBuilder(ObjectSerializerNormalizer::class)->getMock(); - $this->normalizer = new ObjectNormalizer($classMetadataFactory, null, null, null, null, null, $defaultContext); + $this->normalizer = new ObjectNormalizer($classMetadataFactory, [], null, null, null, null, $defaultContext); $this->normalizer->setSerializer($this->serializer); } @@ -275,7 +275,7 @@ protected function getNormalizerForAttributes(): ObjectNormalizer protected function getDenormalizerForAttributes(): ObjectNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $normalizer = new ObjectNormalizer($classMetadataFactory, null, null, new ReflectionExtractor()); + $normalizer = new ObjectNormalizer($classMetadataFactory, [], null, new ReflectionExtractor()); new Serializer([$normalizer]); return $normalizer; @@ -283,7 +283,7 @@ protected function getDenormalizerForAttributes(): ObjectNormalizer public function testAttributesContextDenormalizeConstructor() { - $normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor()); + $normalizer = new ObjectNormalizer(null, [], null, new ReflectionExtractor()); $serializer = new Serializer([$normalizer]); $objectInner = new ObjectInner(); @@ -371,7 +371,7 @@ public function testSiblingReference() protected function getDenormalizerForConstructArguments(): ObjectNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $denormalizer = new ObjectNormalizer($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory)); + $denormalizer = new ObjectNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory)]); $serializer = new Serializer([$denormalizer]); $denormalizer->setSerializer($serializer); @@ -397,7 +397,11 @@ protected function getDenormalizerForGroups(): ObjectNormalizer return new ObjectNormalizer($classMetadataFactory); } - public function testGroupsNormalizeWithNameConverter() + /** + * @group legacy + * @expectedDeprecation Using the "nameConverter" property of the class "Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer" is deprecated since Symfony 5.1, use the "nameConverters" property instead. + */ + public function testGroupsNormalizeWithDirectNameConverter() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $this->normalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); @@ -418,10 +422,52 @@ public function testGroupsNormalizeWithNameConverter() ); } + public function testGroupsNormalizeWithNameConverter() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new ObjectNormalizer($classMetadataFactory, [new CamelCaseToSnakeCaseNameConverter()]); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + $obj->setCoopTilleuls('les-tilleuls.coop'); + + $this->assertEquals( + [ + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + ], + $this->normalizer->normalize($obj, null, [ObjectNormalizer::GROUPS => ['name_converter']]) + ); + } + + public function testGroupsNormalizeWithNameConverters() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new ObjectNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory), new CamelCaseToSnakeCaseNameConverter()]); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + $obj->setCoopTilleuls('les-tilleuls.coop'); + + $this->assertEquals( + [ + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + ], + $this->normalizer->normalize($obj, null, [ObjectNormalizer::GROUPS => ['name_converter'], ObjectNormalizer::NAME_CONVERTER => CamelCaseToSnakeCaseNameConverter::class]) + ); + } + public function testGroupsDenormalizeWithNameConverter() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $this->normalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); + $this->normalizer = new ObjectNormalizer($classMetadataFactory, [new CamelCaseToSnakeCaseNameConverter()]); $this->normalizer->setSerializer($this->serializer); $obj = new GroupDummy(); @@ -439,10 +485,31 @@ public function testGroupsDenormalizeWithNameConverter() ); } + public function testGroupsDenormalizeWithNameConverters() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new ObjectNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory), new CamelCaseToSnakeCaseNameConverter()]); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + + $this->assertEquals( + $obj, + $this->normalizer->denormalize([ + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + 'coop_tilleuls' => 'les-tilleuls.coop', + ], 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', null, [ObjectNormalizer::GROUPS => ['name_converter'], ObjectNormalizer::NAME_CONVERTER => CamelCaseToSnakeCaseNameConverter::class]) + ); + } + public function testGroupsDenormalizeWithMetaDataNameConverter() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $this->normalizer = new ObjectNormalizer($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory)); + $this->normalizer = new ObjectNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory)]); $this->normalizer->setSerializer($this->serializer); $obj = new OtherSerializedNameDummy(); @@ -470,7 +537,7 @@ protected function getNormalizerForIgnoredAttributes(): ObjectNormalizer protected function getDenormalizerForIgnoredAttributes(): ObjectNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $normalizer = new ObjectNormalizer($classMetadataFactory, null, null, new ReflectionExtractor()); + $normalizer = new ObjectNormalizer($classMetadataFactory, [], null, new ReflectionExtractor()); new Serializer([$normalizer]); return $normalizer; @@ -493,7 +560,7 @@ protected function getNormalizerForMaxDepth(): ObjectNormalizer protected function getDenormalizerForObjectToPopulate(): ObjectNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $normalizer = new ObjectNormalizer($classMetadataFactory, null, null, new PhpDocExtractor()); + $normalizer = new ObjectNormalizer($classMetadataFactory, [], null, new PhpDocExtractor()); new Serializer([$normalizer]); return $normalizer; @@ -511,7 +578,7 @@ protected function getNormalizerForSkipNullValues(): ObjectNormalizer protected function getDenormalizerForTypeEnforcement(): ObjectNormalizer { $extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]); - $normalizer = new ObjectNormalizer(null, null, null, $extractor); + $normalizer = new ObjectNormalizer(null, [], null, $extractor); new Serializer([new ArrayDenormalizer(), $normalizer]); return $normalizer; @@ -579,7 +646,7 @@ public function testThrowUnexpectedValueException() public function testDenomalizeRecursive() { $extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]); - $normalizer = new ObjectNormalizer(null, null, null, $extractor); + $normalizer = new ObjectNormalizer(null, [], null, $extractor); $serializer = new Serializer([new ArrayDenormalizer(), new DateTimeNormalizer(), $normalizer]); $obj = $serializer->denormalize([ @@ -598,7 +665,7 @@ public function testDenomalizeRecursive() public function testAcceptJsonNumber() { $extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]); - $normalizer = new ObjectNormalizer(null, null, null, $extractor); + $normalizer = new ObjectNormalizer(null, [], null, $extractor); $serializer = new Serializer([new ArrayDenormalizer(), new DateTimeNormalizer(), $normalizer]); $this->assertSame(10.0, $serializer->denormalize(['number' => 10], JsonNumber::class, 'json')->number); @@ -641,7 +708,7 @@ public function denormalize(string $propertyName, string $class = null, string $ } }; - $normalizer = new ObjectNormalizer(null, $nameConverter); + $normalizer = new ObjectNormalizer(null, [$nameConverter]); $this->assertArrayHasKey('foo-Symfony\Component\Serializer\Tests\Normalizer\Features\ObjectDummy-json-bar', $normalizer->normalize(new ObjectDummy(), 'json', ['foo' => 'bar'])); } @@ -675,7 +742,7 @@ public function testObjectClassResolver() return ObjectDummy::class; }; - $normalizer = new ObjectNormalizer(null, null, null, null, null, $classResolver); + $normalizer = new ObjectNormalizer(null, [], null, null, null, $classResolver); $obj = new ProxyObjectDummy(); $obj->setFoo('foo'); diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php index f93f7616763d0..ed4219312f1b9 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php @@ -69,7 +69,7 @@ protected function setUp(): void private function createNormalizer(array $defaultContext = []) { $this->serializer = $this->getMockBuilder('Symfony\Component\Serializer\SerializerInterface')->getMock(); - $this->normalizer = new PropertyNormalizer(null, null, null, null, null, $defaultContext); + $this->normalizer = new PropertyNormalizer(null, [], null, null, null, $defaultContext); $this->normalizer->setSerializer($this->serializer); } @@ -194,7 +194,7 @@ public function testSiblingReference() protected function getDenormalizerForConstructArguments(): PropertyNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $denormalizer = new PropertyNormalizer($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory)); + $denormalizer = new PropertyNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory)]); $serializer = new Serializer([$denormalizer]); $denormalizer->setSerializer($serializer); @@ -215,7 +215,11 @@ protected function getDenormalizerForGroups(): PropertyNormalizer return new PropertyNormalizer($classMetadataFactory); } - public function testGroupsNormalizeWithNameConverter() + /** + * @group legacy + * @expectedDeprecation Using the "nameConverter" property of the class "Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer" is deprecated since Symfony 5.1, use the "nameConverters" property instead. + */ + public function testGroupsNormalizeWithDirectNameConverter() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $this->normalizer = new PropertyNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); @@ -236,10 +240,52 @@ public function testGroupsNormalizeWithNameConverter() ); } + public function testGroupsNormalizeWithNameConverter() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new PropertyNormalizer($classMetadataFactory, [new CamelCaseToSnakeCaseNameConverter()]); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + $obj->setCoopTilleuls('les-tilleuls.coop'); + + $this->assertEquals( + [ + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + ], + $this->normalizer->normalize($obj, null, [PropertyNormalizer::GROUPS => ['name_converter']]) + ); + } + + public function testGroupsNormalizeWithNameConverters() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new PropertyNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory), new CamelCaseToSnakeCaseNameConverter()]); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + $obj->setCoopTilleuls('les-tilleuls.coop'); + + $this->assertEquals( + [ + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + ], + $this->normalizer->normalize($obj, null, [PropertyNormalizer::GROUPS => ['name_converter'], PropertyNormalizer::NAME_CONVERTER => CamelCaseToSnakeCaseNameConverter::class]) + ); + } + public function testGroupsDenormalizeWithNameConverter() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $this->normalizer = new PropertyNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter()); + $this->normalizer = new PropertyNormalizer($classMetadataFactory, [new CamelCaseToSnakeCaseNameConverter()]); $this->normalizer->setSerializer($this->serializer); $obj = new GroupDummy(); @@ -257,6 +303,27 @@ public function testGroupsDenormalizeWithNameConverter() ); } + public function testGroupsDenormalizeWithNameConverters() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->normalizer = new PropertyNormalizer($classMetadataFactory, [new MetadataAwareNameConverter($classMetadataFactory), new CamelCaseToSnakeCaseNameConverter()]); + $this->normalizer->setSerializer($this->serializer); + + $obj = new GroupDummy(); + $obj->setFooBar('@dunglas'); + $obj->setSymfony('@coopTilleuls'); + + $this->assertEquals( + $obj, + $this->normalizer->denormalize([ + 'bar' => null, + 'foo_bar' => '@dunglas', + 'symfony' => '@coopTilleuls', + 'coop_tilleuls' => 'les-tilleuls.coop', + ], 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', null, [PropertyNormalizer::GROUPS => ['name_converter'], PropertyNormalizer::NAME_CONVERTER => CamelCaseToSnakeCaseNameConverter::class]) + ); + } + protected function getDenormalizerForIgnoredAttributes(): PropertyNormalizer { $normalizer = new PropertyNormalizer(); @@ -293,7 +360,7 @@ protected function getNormalizerForMaxDepth(): PropertyNormalizer protected function getDenormalizerForObjectToPopulate(): PropertyNormalizer { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $normalizer = new PropertyNormalizer($classMetadataFactory, null, new PhpDocExtractor()); + $normalizer = new PropertyNormalizer($classMetadataFactory, [], new PhpDocExtractor()); new Serializer([$normalizer]); return $normalizer; @@ -302,7 +369,7 @@ protected function getDenormalizerForObjectToPopulate(): PropertyNormalizer protected function getDenormalizerForTypeEnforcement(): DenormalizerInterface { $extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]); - $normalizer = new PropertyNormalizer(null, null, $extractor); + $normalizer = new PropertyNormalizer(null, [], $extractor); $serializer = new Serializer([new ArrayDenormalizer(), $normalizer]); $normalizer->setSerializer($serializer); diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index a60c81322fabe..52ed3dd36edc8 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -406,7 +406,7 @@ public function hasMetadataFor($value): bool }; $discriminatorResolver = new ClassDiscriminatorFromClassMetadata($loaderMock); - $serializer = new Serializer([new ObjectNormalizer(null, null, null, new PhpDocExtractor(), $discriminatorResolver)], ['json' => new JsonEncoder()]); + $serializer = new Serializer([new ObjectNormalizer(null, [], null, new PhpDocExtractor(), $discriminatorResolver)], ['json' => new JsonEncoder()]); $jsonData = '{"type":"first","quux":{"value":"quux"},"bar":"bar-value","foo":"foo-value"}'; @@ -573,7 +573,7 @@ private function serializerWithClassDiscriminator() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - return new Serializer([new ObjectNormalizer($classMetadataFactory, null, null, new ReflectionExtractor(), new ClassDiscriminatorFromClassMetadata($classMetadataFactory))], ['json' => new JsonEncoder()]); + return new Serializer([new ObjectNormalizer($classMetadataFactory, [], null, new ReflectionExtractor(), new ClassDiscriminatorFromClassMetadata($classMetadataFactory))], ['json' => new JsonEncoder()]); } }