diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index b252d62194d87..5187955dd8528 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -326,13 +326,15 @@ public function denormalize(mixed $data, string $type, string $format = null, ar $mappedClass = $this->getMappedClass($normalizedData, $type, $context); $nestedAttributes = $this->getNestedAttributes($mappedClass); - $nestedData = []; + $nestedData = $originalNestedData = []; $propertyAccessor = PropertyAccess::createPropertyAccessor(); foreach ($nestedAttributes as $property => $serializedPath) { if (null === $value = $propertyAccessor->getValue($normalizedData, $serializedPath)) { continue; } - $nestedData[$property] = $value; + $convertedProperty = $this->nameConverter ? $this->nameConverter->normalize($property, $mappedClass, $format, $context) : $property; + $nestedData[$convertedProperty] = $value; + $originalNestedData[$property] = $value; $normalizedData = $this->removeNestedValue($serializedPath->getElements(), $normalizedData); } @@ -345,7 +347,7 @@ public function denormalize(mixed $data, string $type, string $format = null, ar if ($this->nameConverter) { $notConverted = $attribute; $attribute = $this->nameConverter->denormalize($attribute, $resolvedClass, $format, $context); - if (isset($nestedData[$notConverted]) && !isset($nestedData[$attribute])) { + if (isset($nestedData[$notConverted]) && !isset($originalNestedData[$attribute])) { throw new LogicException(sprintf('Duplicate values for key "%s" found. One value is set via the SerializedPath annotation: "%s", the other one is set via the SerializedName annotation: "%s".', $notConverted, implode('->', $nestedAttributes[$notConverted]->getElements()), $attribute)); } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index bed7c33cecc19..361f8520d3a22 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -33,6 +33,7 @@ use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; +use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; @@ -140,6 +141,29 @@ public function testDenormalizeWithNestedAttributesWithoutMetadata() $this->assertNull($test->notfoo); } + public function testDenormalizeWithSnakeCaseNestedAttributes() + { + $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $normalizer = new ObjectNormalizer($factory, new CamelCaseToSnakeCaseNameConverter()); + $data = [ + 'one' => [ + 'two_three' => 'fooBar', + ], + ]; + $test = $normalizer->denormalize($data, SnakeCaseNestedDummy::class, 'any'); + $this->assertSame('fooBar', $test->fooBar); + } + + public function testNormalizeWithSnakeCaseNestedAttributes() + { + $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $normalizer = new ObjectNormalizer($factory, new CamelCaseToSnakeCaseNameConverter()); + $dummy = new SnakeCaseNestedDummy(); + $dummy->fooBar = 'fooBar'; + $test = $normalizer->normalize($dummy, 'any'); + $this->assertSame(['one' => ['two_three' => 'fooBar']], $test); + } + public function testDenormalizeWithNestedAttributes() { $normalizer = new AbstractObjectNormalizerWithMetadata(); @@ -861,6 +885,14 @@ public function __construct( } } +class SnakeCaseNestedDummy +{ + /** + * @SerializedPath("[one][two_three]") + */ + public $fooBar; +} + /** * @DiscriminatorMap(typeProperty="type", mapping={ * "first" = FirstNestedDummyWithConstructorAndDiscriminator::class,
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: