diff --git a/src/JMS/Serializer/GraphNavigator.php b/src/JMS/Serializer/GraphNavigator.php index 08503bd53..2748fc26f 100644 --- a/src/JMS/Serializer/GraphNavigator.php +++ b/src/JMS/Serializer/GraphNavigator.php @@ -150,6 +150,15 @@ public function accept($data, array $type = null, Context $context) return $visitor->visitDouble($data, $type, $context); case 'array': + $metadata = $context->getMetadataStack()->count() ? $context->getMetadataStack()->top() : null; + if ($visitor instanceof XmlDeserializationVisitor && null !== $metadata && $metadata->xmlKeyValuePairs) { + $visitor->setCurrentMetadata($metadata); + $result = $visitor->visitArray($data, $type, $context); + $visitor->revertCurrentMetadata(); + + return $result; + } + return $visitor->visitArray($data, $type, $context); case 'resource': diff --git a/src/JMS/Serializer/XmlDeserializationVisitor.php b/src/JMS/Serializer/XmlDeserializationVisitor.php index a604ea5fb..28145f6f5 100644 --- a/src/JMS/Serializer/XmlDeserializationVisitor.php +++ b/src/JMS/Serializer/XmlDeserializationVisitor.php @@ -151,6 +151,23 @@ public function visitDouble($data, array $type, Context $context) public function visitArray($data, array $type, Context $context) { + // handle key-value-pairs + if (null !== $this->currentMetadata && $this->currentMetadata->xmlKeyValuePairs) { + if (2 !== count($type['params'])) { + throw new RuntimeException('The array type must be specified as "array" for Key-Value-Pairs.'); + } + + list($keyType, $entryType) = $type['params']; + + $result = []; + foreach ($data as $key => $v) { + $k = $this->navigator->accept($key, $keyType, $context); + $result[$k] = $this->navigator->accept($v, $entryType, $context); + } + + return $result; + } + $entryName = null !== $this->currentMetadata && $this->currentMetadata->xmlEntryName ? $this->currentMetadata->xmlEntryName : 'entry'; $namespace = null !== $this->currentMetadata && $this->currentMetadata->xmlEntryNamespace ? $this->currentMetadata->xmlEntryNamespace : null; diff --git a/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php new file mode 100644 index 000000000..f6ebc5534 --- /dev/null +++ b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php @@ -0,0 +1,68 @@ + + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace JMS\Serializer\Tests\Fixtures; + +use JMS\Serializer\Annotation\Type; +use JMS\Serializer\Annotation\XmlKeyValuePairs; + +class ObjectWithXmlKeyValuePairsWithType +{ + /** + * @var array + * @Type("array") + * @XmlKeyValuePairs + */ + private $list; + + /** + * @var array + * @Type("array") + */ + private $list2; + + public function __construct(array $list, array $list2 = []) + { + $this->list = $list; + $this->list2 = $list2; + } + + public static function create1() + { + return new self( + [ + 'key-one' => 'foo', + 'key-two' => 'bar', + ] + ); + } + + public static function create2() + { + return new self( + [ + 'key_01' => 'One', + 'key_02' => 'Two', + 'key_03' => 'Three', + ], + [ + 'Four', + ] + ); + } +} diff --git a/tests/Serializer/XmlSerializationTest.php b/tests/Serializer/XmlSerializationTest.php index b2d1e2425..e5ac29aad 100644 --- a/tests/Serializer/XmlSerializationTest.php +++ b/tests/Serializer/XmlSerializationTest.php @@ -42,6 +42,7 @@ use JMS\Serializer\Tests\Fixtures\ObjectWithToString; use JMS\Serializer\Tests\Fixtures\ObjectWithVirtualXmlProperties; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairs; +use JMS\Serializer\Tests\Fixtures\ObjectWithXmlKeyValuePairsWithType; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespaces; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespacesAndObjectProperty; use JMS\Serializer\Tests\Fixtures\ObjectWithXmlNamespacesAndObjectPropertyAuthor; @@ -249,6 +250,19 @@ public function testArrayKeyValues() $this->assertEquals($this->getContent('array_key_values'), $this->serializer->serialize(new ObjectWithXmlKeyValuePairs(), 'xml')); } + public function testDeserializeArrayKeyValues() + { + $xml = $this->getContent('array_key_values_with_type_1'); + $result = $this->serializer->deserialize($xml, ObjectWithXmlKeyValuePairsWithType::class, 'xml'); + $this->assertInstanceOf(ObjectWithXmlKeyValuePairsWithType::class, $result); + $this->assertEquals(ObjectWithXmlKeyValuePairsWithType::create1(), $result); + + $xml2 = $this->getContent('array_key_values_with_type_2'); + $result2 = $this->serializer->deserialize($xml2, ObjectWithXmlKeyValuePairsWithType::class, 'xml'); + $this->assertInstanceOf(ObjectWithXmlKeyValuePairsWithType::class, $result2); + $this->assertEquals(ObjectWithXmlKeyValuePairsWithType::create2(), $result2); + } + /** * @dataProvider getDateTime * @group datetime diff --git a/tests/Serializer/xml/array_key_values_with_type_1.xml b/tests/Serializer/xml/array_key_values_with_type_1.xml new file mode 100644 index 000000000..7b3bfc964 --- /dev/null +++ b/tests/Serializer/xml/array_key_values_with_type_1.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/Serializer/xml/array_key_values_with_type_2.xml b/tests/Serializer/xml/array_key_values_with_type_2.xml new file mode 100644 index 000000000..a5a518b65 --- /dev/null +++ b/tests/Serializer/xml/array_key_values_with_type_2.xml @@ -0,0 +1,11 @@ + + + + + + + + + + +