bug #33733 [Serializer] fix denormalization of string-arrays with only 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 ac70edf8cd, just not only for arrays of objects.

Commits
-------

8814751b96 [Serializer] fix denormalization of string-arrays with only one element #33731
This commit is contained in:
Nicolas Grekas 2019-09-30 16:55:04 +02:00
commit a2cd56c12f
2 changed files with 63 additions and 17 deletions

View File

@ -244,16 +244,18 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
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;
}

View File

@ -121,16 +121,54 @@ class AbstractObjectNormalizerTest extends TestCase
$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
));
@ -212,6 +250,12 @@ class AbstractObjectNormalizerWithMetadata extends AbstractObjectNormalizer
}
}
class StringCollection
{
/** @var string[] */
public $children;
}
class DummyCollection
{
/** @var DummyChild[] */