8000 [Serializer] fix denormalization of xml-values to objects when no (op… · mkrauser/symfony@c25813b · GitHub
[go: up one dir, main page]

Skip to content

Commit c25813b

Browse files
committed
[Serializer] fix denormalization of xml-values to objects when no (optional) attributes are present symfony#32144
1 parent 302243d commit c25813b

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,17 @@ public function denormalize($data, $type, $format = null, array $context = [])
329329
$object = $this->instantiateObject($normalizedData, $type, $context, $reflectionClass, $allowedAttributes, $format);
330330
$resolvedClass = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object);
331331

332+
if(is_string($data) && 'xml' === $format && $this->classMetadataFactory->hasMetadataFor($type)) {
333+
$attributes = $this->classMetadataFactory->getMetadataFor($type)->getAttributesMetadata();
334+
335+
foreach($attributes as $attribute) {
336+
if($attribute->getSerializedName() === '#') {
337+
$normalizedData = ['#' => $data];
338+
break;
339+
}
340+
}
341+
}
342+
332343
foreach ($normalizedData as $attribute => $value) {
333344
if ($this->nameConverter) {
334345
$attribute = $this->nameConverter->denormalize($attribute, $resolvedClass, $format, $context);

src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use PHPUnit\Framework\TestCase;
1616
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
1717
use Symfony\Component\PropertyInfo\Type;
18+
use Symfony\Component\Serializer\Annotation\SerializedName;
1819
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
1920
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
2021
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
@@ -24,6 +25,7 @@
2425
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
2526
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
2627
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
28+
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
2729
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
2830
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
2931
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
@@ -227,6 +229,28 @@ public function hasMetadataFor($value): bool
227229
$this->assertInstanceOf(DummySecondChildQuux::class, $normalizedData->quux);
228230
}
229231

232+
public function testDenormalizeXmlStringNodeWithoutAttributesToObject()
233+
{
234+
$denormalizer = $this->getDenormalizerForStringNode();
235+
236+
// if an xml-node can have children which should be deserialized as string[]
237+
// and only one child exists
238+
$object = $denormalizer->denormalize("string-value", DummyObjectWithOptionalAttributes::class, 'xml');
239+
240+
$this->assertInstanceOf(DummyObjectWithOptionalAttributes::class, $object);
241+
$this->assertEquals("string-value", $object->value);
242+
$this->assertNull($object->foo);
243+
}
244+
245+
public function getDenormalizerForStringNode()
246+
{
247+
$denormalizer = new AbstractObjectNormalizerWithMetadataAndNameConverter();
248+
$serializer = new Serializer([$denormalizer]);
249+
$denormalizer->setSerializer($serializer);
250+
251+
return $denormalizer;
252+
}
253+
230254
/**
231255
* Test that additional attributes throw an exception if no metadata factory is specified.
232256
*/
@@ -296,6 +320,28 @@ protected function setAttributeValue($object, $attribute, $value, $format = null
296320
}
297321
}
298322

323+
class AbstractObjectNormalizerWithMetadataAndNameConverter extends AbstractObjectNormalizer
324+
{
325+
public function __construct()
326+
{
327+
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
328+
parent::__construct($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory));
329+
}
330+
331+
protected function extractAttributes($object, $format = null, array $context = [])
332+
{
333+
}
334+
335+
protected function getAttributeValue($object, $attribute, $format = null, array $context = [])
336+
{
337+
}
338+
339+
protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = [])
340+
{
341+
$object->$attribute = $value;
342+
}
343+
}
344+
299345
class StringCollection
300346
{
301347
/** @var string[] */
@@ -313,6 +359,21 @@ class DummyChild
313359
public $bar;
314360
}
315361

362+
class DummyObjectWithOptionalAttributes
363+
{
364+
/**
365+
* @SerializedName("#")
366+
* @var string
367+
*/
368+
public $value;
369+
370+
/**
371+
* @SerializedName("@foo")
372+
* @var string
373+
*/
374+
public $foo = null;
375+
}
376+
316377
class SerializerCollectionDummy implements SerializerInterface, DenormalizerInterface
317378
{
318379
private $normalizers;

0 commit comments

Comments
 (0)
0