Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8846f64

Browse files
committed
bug #46525 [Serializer] Get attributeContext after converting name (zenas1210)
This PR was merged into the 5.4 branch. Discussion ---------- [Serializer] Get attributeContext after converting name | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | | License | MIT | Doc PR | Property specific denormalization context doesn't work when property name in the array being denormalized is different from property name in the class. To reproduce: ``` // composer require symfony/serializer:"5.4.*" doctrine/annotations symfony/property-access <?php require_once __DIR__.'/vendor/autoload.php'; use Doctrine\Common\Annotations\AnnotationReader; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\Serializer\Annotation\Context; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; class Item { /** * `@Context`({ DateTimeNormalizer::FORMAT_KEY = "d/m/Y" }) */ public \DateTime $createdAt; } $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $objectNormalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter(), null, new ReflectionExtractor()); $normalizers = [new DateTimeNormalizer(), $objectNormalizer]; new Serializer($normalizers, []); // outputs 2011-07-28 echo ($objectNormalizer->denormalize(['createdAt' => '28/07/2011'], Item::class))->createdAt->format('Y-m-d') . PHP_EOL; // crashes because 'created_at' !== 'createdAt' echo ($objectNormalizer->denormalize(['created_at' => '28/07/2011'], Item::class))->createdAt->format('Y-m-d') . PHP_EOL; ``` Theoretically this could introduce breaking changes to people who use property specific context in their custom name converters, but due to this bug that context reaches the name converter only when the source name already matches the property name, so in that case no name converting is needed anyway and the context is useless. Moreover, I'm not sure if 'deserialization_path' changing from source name to the converted name is an issue, if it is I can modify my PR to preserve the original functionality. Commits ------- 48c47df [Serializer] Get attributeContext after converting name
2 parents 7a9e4e9 + 48c47df commit 8846f64

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,12 +359,12 @@ public function denormalize($data, string $type, string $format = null, array $c
359359
$resolvedClass = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object);
360360

361361
foreach ($normalizedData as $attribute => $value) {
362-
$attributeContext = $this->getAttributeDenormalizationContext($resolvedClass, $attribute, $context);
363-
364362
if ($this->nameConverter) {
365-
$attribute = $this->nameConverter->denormalize($attribute, $resolvedClass, $format, $attributeContext);
363+
$attribute = $this->nameConverter->denormalize($attribute, $resolvedClass, $format, $context);
366364
}
367365

366+
$attributeContext = $this->getAttributeDenormalizationContext($resolvedClass, $attribute, $context);
367+
368368
if ((false !== $allowedAttributes && !\in_array($attribute, $allowedAttributes)) || !$this->isAllowedAttribute($resolvedClass, $attribute, $format, $context)) {
369369
if (!($context[self::ALLOW_EXTRA_ATTRIBUTES] ?? $this->defaultContext[self::ALLOW_EXTRA_ATTRIBUTES])) {
370370
$extraAttributes[] = $attribute;

src/Symfony/Component/Serializer/Tests/Normalizer/Features/ContextMetadataTestTrait.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Serializer\Annotation\Groups;
1818
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
1919
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
20+
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
2021
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
2122
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
2223
use Symfony\Component\Serializer\Serializer;
@@ -70,6 +71,17 @@ public function testContextMetadataContextDenormalize()
7071
]);
7172
self::assertEquals('2011-07-28', $dummy->date->format('Y-m-d'), 'a specific denormalization context is used for this group');
7273
}
74+
75+
public function testContextDenormalizeWithNameConverter()
76+
{
77+
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
78+
$normalizer = new ObjectNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter(), null, new PhpDocExtractor());
79+
new Serializer([new DateTimeNormalizer(), $normalizer]);
80+
81+
/** @var ContextMetadataNamingDummy $dummy */
82+
$dummy = $normalizer->denormalize(['created_at' => '28/07/2011'], ContextMetadataNamingDummy::class);
83+
self::assertEquals('2011-07-28', $dummy->createdAt->format('Y-m-d'));
84+
}
7385
}
7486

7587
class ContextMetadataDummy
@@ -90,3 +102,13 @@ class ContextMetadataDummy
90102
*/
91103
public $date;
92104
}
105+
106+
class ContextMetadataNamingDummy
107+
{
108+
/**
109+
* @var \DateTime
110+
*
111+
* @Context({ DateTimeNormalizer::FORMAT_KEY = "d/m/Y" })
112+
*/
113+
public $createdAt;
114+
}

0 commit comments

Comments
 (0)