Skip to content

Commit

Permalink
bug #33733 [Serializer] fix denormalization of string-arrays with onl…
Browse files Browse the repository at this point in the history
…y one element (mkrauser)

This PR was merged into the 3.4 branch.

Discussion
----------

[Serializer] fix denormalization of string-arrays with only one element

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  |no
| Deprecations? |no
| Tickets       | Fix #33731
| License       | MIT
| Doc PR        |

This PR does almost the same as ac70edf, just not only for arrays of objects.

Commits
-------

8814751 [Serializer] fix denormalization of string-arrays with only one element #33731
  • Loading branch information
nicolas-grekas committed Sep 30, 2019
2 parents 03f2adc + 8814751 commit a2cd56c
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -244,16 +244,18 @@ private function validateAndDenormalize($currentClass, $attribute, $data, $forma
return null;
}

if ($type->isCollection() && null !== ($collectionValueType = $type->getCollectionValueType()) && Type::BUILTIN_TYPE_OBJECT === $collectionValueType->getBuiltinType()) {
$collectionValueType = $type->isCollection() ? $type->getCollectionValueType() : null;

// Fix a collection that contains the only one element
// This is special to xml format only
if ('xml' === $format && null !== $collectionValueType && (!\is_array($data) || !\is_int(key($data)))) {
$data = [$data];
}

if (null !== $collectionValueType && Type::BUILTIN_TYPE_OBJECT === $collectionValueType->getBuiltinType()) {
$builtinType = Type::BUILTIN_TYPE_OBJECT;
$class = $collectionValueType->getClassName().'[]';

// Fix a collection that contains the only one element
// This is special to xml format only
if ('xml' === $format && !\is_int(key($data))) {
$data = [$data];
}

if (null !== $collectionKeyType = $type->getCollectionKeyType()) {
$context['key_type'] = $collectionKeyType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,54 @@ private function getDenormalizerForDummyCollection()
$extractor = $this->getMockBuilder(PhpDocExtractor::class)->getMock();
$extractor->method('getTypes')
->will($this->onConsecutiveCalls(
[
new Type(
'array',
false,
null,
true,
new Type('int'),
new Type('object', false, DummyChild::class)
),
],
[new Type('array', false, null, true, new Type('int'), new Type('object', false, DummyChild::class))],
null
));

$denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor);
$arrayDenormalizer = new ArrayDenormalizerDummy();
$serializer = new SerializerCollectionDummy([$arrayDenormalizer, $denormalizer]);
$arrayDenormalizer->setSerializer($serializer);
$denormalizer->setSerializer($serializer);

return $denormalizer;
}

public function testDenormalizeStringCollectionDecodedFromXmlWithOneChild()
{
$denormalizer = $this->getDenormalizerForStringCollection();

// if an xml-node can have children which should be deserialized as string[]
// and only one child exists
$stringCollection = $denormalizer->denormalize(['children' => 'foo'], StringCollection::class, 'xml');

$this->assertInstanceOf(StringCollection::class, $stringCollection);
$this->assertIsArray($stringCollection->children);
$this->assertCount(1, $stringCollection->children);
$this->assertEquals('foo', $stringCollection->children[0]);
}

public function testDenormalizeStringCollectionDecodedFromXmlWithTwoChildren()
{
$denormalizer = $this->getDenormalizerForStringCollection();

// if an xml-node can have children which should be deserialized as string[]
// and only one child exists
$stringCollection = $denormalizer->denormalize(['children' => ['foo', 'bar']], StringCollection::class, 'xml');

$this->assertInstanceOf(StringCollection::class, $stringCollection);
$this->assertIsArray($stringCollection->children);
$this->assertCount(2, $stringCollection->children);
$this->assertEquals('foo', $stringCollection->children[0]);
$this->assertEquals('bar', $stringCollection->children[1]);
}

private function getDenormalizerForStringCollection()
{
$extractor = $this->getMockBuilder(PhpDocExtractor::class)->getMock();
$extractor->method('getTypes')
->will($this->onConsecutiveCalls(
[new Type('array', false, null, true, new Type('int'), new Type('string'))],
null
));

Expand Down Expand Up @@ -212,6 +250,12 @@ protected function setAttributeValue($object, $attribute, $value, $format = null
}
}

class StringCollection
{
/** @var string[] */
public $children;
}

class DummyCollection
{
/** @var DummyChild[] */
Expand Down

0 comments on commit a2cd56c

Please sign in to comment.