From 2852fe1417c26aef53339f9ba71cfe8486f0e37a Mon Sep 17 00:00:00 2001 From: Franziska Dyckhoff Date: Wed, 22 Nov 2017 10:04:20 +0100 Subject: [PATCH 1/4] deserialize array with key-value pairs relates to #820 deserialize arrays with key-value pairs add test case with other values from default set current metadata from stack in serialization context --- .../Serializer/XmlDeserializationVisitor.php | 21 +++++++ .../ObjectWithXmlKeyValuePairsWithType.php | 58 +++++++++++++++++++ tests/Serializer/XmlSerializationTest.php | 14 +++++ .../xml/array_key_values_with_type_1.xml | 7 +++ .../xml/array_key_values_with_type_2.xml | 8 +++ 5 files changed, 108 insertions(+) create mode 100644 tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php create mode 100644 tests/Serializer/xml/array_key_values_with_type_1.xml create mode 100644 tests/Serializer/xml/array_key_values_with_type_2.xml diff --git a/src/JMS/Serializer/XmlDeserializationVisitor.php b/src/JMS/Serializer/XmlDeserializationVisitor.php index a604ea5fb..ec387d140 100644 --- a/src/JMS/Serializer/XmlDeserializationVisitor.php +++ b/src/JMS/Serializer/XmlDeserializationVisitor.php @@ -151,6 +151,27 @@ public function visitDouble($data, array $type, Context $context) public function visitArray($data, array $type, Context $context) { + if (null === $this->currentMetadata && $context->getMetadataStack()->count()) { + $this->setCurrentMetadata($context->getMetadataStack()->top()); + } + + // 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..770678fa5 --- /dev/null +++ b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php @@ -0,0 +1,58 @@ + + * + * 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; + + public function __construct(array $list) + { + $this->list = $list; + } + + 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', + ] + ); + } +} 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..9dced49ef --- /dev/null +++ b/tests/Serializer/xml/array_key_values_with_type_1.xml @@ -0,0 +1,7 @@ + + + + + + + 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..0b3e69c5c --- /dev/null +++ b/tests/Serializer/xml/array_key_values_with_type_2.xml @@ -0,0 +1,8 @@ + + + + + + + + From 5e9af2a5634807f45b8aaec5bc355b6dd376cf80 Mon Sep 17 00:00:00 2001 From: Franziska Dyckhoff Date: Fri, 24 Nov 2017 18:46:41 +0100 Subject: [PATCH 2/4] add testcase with multiple arrays --- .../Fixtures/ObjectWithXmlKeyValuePairsWithType.php | 12 +++++++++++- .../Serializer/xml/array_key_values_with_type_1.xml | 1 + .../Serializer/xml/array_key_values_with_type_2.xml | 3 +++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php index 770678fa5..f9c437974 100644 --- a/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php +++ b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php @@ -30,9 +30,16 @@ class ObjectWithXmlKeyValuePairsWithType */ private $list; - public function __construct(array $list) + /** + * @var array + * @Type("array") + */ + private $list2; + + public function __construct(array $list, array $list2 = []) { $this->list = $list; + $this->list2 = $list2; } public static function create1() @@ -52,6 +59,9 @@ public static function create2() 'key_01' => 'One', 'key_02' => 'Two', 'key_03' => 'Three', + ], + [ + 'Four', ] ); } diff --git a/tests/Serializer/xml/array_key_values_with_type_1.xml b/tests/Serializer/xml/array_key_values_with_type_1.xml index 9dced49ef..7b3bfc964 100644 --- a/tests/Serializer/xml/array_key_values_with_type_1.xml +++ b/tests/Serializer/xml/array_key_values_with_type_1.xml @@ -4,4 +4,5 @@ + diff --git a/tests/Serializer/xml/array_key_values_with_type_2.xml b/tests/Serializer/xml/array_key_values_with_type_2.xml index 0b3e69c5c..a5a518b65 100644 --- a/tests/Serializer/xml/array_key_values_with_type_2.xml +++ b/tests/Serializer/xml/array_key_values_with_type_2.xml @@ -5,4 +5,7 @@ + + + From 78dcf46b99da6be2f926e57677b3340b23a02ca5 Mon Sep 17 00:00:00 2001 From: Franziska Dyckhoff Date: Fri, 24 Nov 2017 19:12:37 +0100 Subject: [PATCH 3/4] revert current metadata before return --- .../Serializer/XmlDeserializationVisitor.php | 21 ++++++++++++++++++- .../ObjectWithXmlKeyValuePairsWithType.php | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/JMS/Serializer/XmlDeserializationVisitor.php b/src/JMS/Serializer/XmlDeserializationVisitor.php index ec387d140..00175a06d 100644 --- a/src/JMS/Serializer/XmlDeserializationVisitor.php +++ b/src/JMS/Serializer/XmlDeserializationVisitor.php @@ -151,8 +151,11 @@ public function visitDouble($data, array $type, Context $context) public function visitArray($data, array $type, Context $context) { + $metadata = null; if (null === $this->currentMetadata && $context->getMetadataStack()->count()) { - $this->setCurrentMetadata($context->getMetadataStack()->top()); + if ($metadata = $context->getMetadataStack()->top()) { + $this->setCurrentMetadata($metadata); + } } // handle key-value-pairs @@ -169,6 +172,10 @@ public function visitArray($data, array $type, Context $context) $result[$k] = $this->navigator->accept($v, $entryType, $context); } + if($metadata) { + $this->revertCurrentMetadata(); + } + return $result; } @@ -189,6 +196,10 @@ public function visitArray($data, array $type, Context $context) } if (!count($nodes)) { + if($metadata) { + $this->revertCurrentMetadata(); + } + if (null === $this->result) { return $this->result = array(); } @@ -211,6 +222,10 @@ public function visitArray($data, array $type, Context $context) $result[] = $this->navigator->accept($v, $type['params'][0], $context); } + if($metadata) { + $this->revertCurrentMetadata(); + } + return $result; case 2: @@ -235,6 +250,10 @@ public function visitArray($data, array $type, Context $context) $result[$k] = $this->navigator->accept($v, $entryType, $context); } + if($metadata) { + $this->revertCurrentMetadata(); + } + return $result; default: diff --git a/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php index f9c437974..f6ebc5534 100644 --- a/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php +++ b/tests/Fixtures/ObjectWithXmlKeyValuePairsWithType.php @@ -32,7 +32,7 @@ class ObjectWithXmlKeyValuePairsWithType /** * @var array - * @Type("array") + * @Type("array") */ private $list2; From 805286b095ab642b89f607256afcf6426be6c280 Mon Sep 17 00:00:00 2001 From: Franziska Dyckhoff Date: Fri, 24 Nov 2017 20:18:12 +0100 Subject: [PATCH 4/4] set metadata for key-value pairs in navigator --- src/JMS/Serializer/GraphNavigator.php | 9 ++++++++ .../Serializer/XmlDeserializationVisitor.php | 23 ------------------- 2 files changed, 9 insertions(+), 23 deletions(-) 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 00175a06d..28145f6f5 100644 --- a/src/JMS/Serializer/XmlDeserializationVisitor.php +++ b/src/JMS/Serializer/XmlDeserializationVisitor.php @@ -151,13 +151,6 @@ public function visitDouble($data, array $type, Context $context) public function visitArray($data, array $type, Context $context) { - $metadata = null; - if (null === $this->currentMetadata && $context->getMetadataStack()->count()) { - if ($metadata = $context->getMetadataStack()->top()) { - $this->setCurrentMetadata($metadata); - } - } - // handle key-value-pairs if (null !== $this->currentMetadata && $this->currentMetadata->xmlKeyValuePairs) { if (2 !== count($type['params'])) { @@ -172,10 +165,6 @@ public function visitArray($data, array $type, Context $context) $result[$k] = $this->navigator->accept($v, $entryType, $context); } - if($metadata) { - $this->revertCurrentMetadata(); - } - return $result; } @@ -196,10 +185,6 @@ public function visitArray($data, array $type, Context $context) } if (!count($nodes)) { - if($metadata) { - $this->revertCurrentMetadata(); - } - if (null === $this->result) { return $this->result = array(); } @@ -222,10 +207,6 @@ public function visitArray($data, array $type, Context $context) $result[] = $this->navigator->accept($v, $type['params'][0], $context); } - if($metadata) { - $this->revertCurrentMetadata(); - } - return $result; case 2: @@ -250,10 +231,6 @@ public function visitArray($data, array $type, Context $context) $result[$k] = $this->navigator->accept($v, $entryType, $context); } - if($metadata) { - $this->revertCurrentMetadata(); - } - return $result; default: