From 3fd7f5334f1454fce50a74b2f466eeeab01de828 Mon Sep 17 00:00:00 2001 From: gr1ev0us Date: Sun, 19 Feb 2017 15:54:33 +0300 Subject: [PATCH 1/3] Issue-21617 Xml encoder throws exception for valid data * add tests for bool and object encoding * fix encoding for object in array and field --- .../Serializer/Encoder/XmlEncoder.php | 7 +- .../Tests/Encoder/XmlEncoderTest.php | 110 +++++++++++++++++- 2 files changed, 111 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php index 671ab97852ff1..0bd85b0247961 100644 --- a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php @@ -369,7 +369,10 @@ private function buildXml(\DOMNode $parentNode, $data, $xmlRootNodeName = null) if (is_array($data) || ($data instanceof \Traversable && !$this->serializer->supportsNormalization($data, $this->format))) { foreach ($data as $key => $data) { //Ah this is the magic @ attribute types. - if (0 === strpos($key, '@') && is_scalar($data) && $this->isElementNameValid($attributeName = substr($key, 1))) { + if (0 === strpos($key, '@') && $this->isElementNameValid($attributeName = substr($key, 1))) { + if (!is_scalar($data)) { + $data = $this->serializer->normalize($data, $this->format, $this->context); + } $parentNode->setAttribute($attributeName, $data); } elseif ($key === '#') { $append = $this->selectNodeType($parentNode, $data); @@ -474,7 +477,7 @@ private function selectNodeType(\DOMNode $node, $val) } elseif ($val instanceof \Traversable) { $this->buildXml($node, $val); } elseif (is_object($val)) { - return $this->buildXml($node, $this->serializer->normalize($val, $this->format, $this->context)); + return $this->selectNodeType($node, $this->serializer->normalize($val, $this->format, $this->context)); } elseif (is_numeric($val)) { return $this->appendText($node, (string) $val); } elseif (is_string($val) && $this->needsCdataWrapping($val)) { diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 1c9ed79e35d62..1c4a5a95274a9 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -11,19 +11,29 @@ namespace Symfony\Component\Serializer\Tests\Encoder; +use DateTime; use PHPUnit\Framework\TestCase; -use Symfony\Component\Serializer\Tests\Fixtures\Dummy; -use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy; -use Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy; use Symfony\Component\Serializer\Encoder\XmlEncoder; -use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Serializer\Normalizer\CustomNormalizer; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Serializer; +use Symfony\Component\Serializer\Tests\Fixtures\Dummy; +use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy; +use Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy; class XmlEncoderTest extends TestCase { + /** + * @var XmlEncoder + */ private $encoder; + /** + * @var string + */ + private $exampleDateTimeString = '2017-02-19T15:16:08+0300'; + protected function setUp() { $this->encoder = new XmlEncoder(); @@ -524,4 +534,96 @@ protected function getObject() return $obj; } + + /** + * @test + */ + public function testEncodeXmlWithBoolValue() + { + $expectedXml = ' +10 +'; + + $actualXml = $this->encoder->encode(array('foo' => true, 'bar' => false), 'xml'); + + $this->assertEquals($expectedXml, $actualXml); + } + + /** + * @test + */ + public function testEncodeXmlWithDateTimeObjectValue() + { + $xmlEncoder = $this->createXmlEncoderWithDateTimeNormalizer(); + + $actualXml = $xmlEncoder->encode(array('dateTime' => new DateTime($this->exampleDateTimeString)), 'xml'); + + $this->assertEquals($this->createXmlWithDateTime(), $actualXml); + } + + /** + * @test + */ + public function testEncodeXmlWithDateTimeObjectField() + { + $xmlEncoder = $this->createXmlEncoderWithDateTimeNormalizer(); + + $actualXml = $xmlEncoder->encode(array('foo' => array('@dateTime' => new DateTime($this->exampleDateTimeString))), 'xml'); + + $this->assertEquals($this->createXmlWithDateTimeField(), $actualXml); + } + + /** + * @return XmlEncoder + */ + private function createXmlEncoderWithDateTimeNormalizer() + { + $encoder = new XmlEncoder(); + $serializer = new Serializer(array($this->createMockDateTimeNormalizer()), array('xml' => new XmlEncoder())); + $encoder->setSerializer($serializer); + + return $encoder; + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|NormalizerInterface + */ + private function createMockDateTimeNormalizer() + { + $mock = $this->getMockBuilder('\Symfony\Component\Serializer\Normalizer\CustomNormalizer')->getMock(); + + $mock + ->expects($this->once()) + ->method('normalize') + ->with(new DateTime($this->exampleDateTimeString), 'xml', array()) + ->willReturn($this->exampleDateTimeString); + + $mock + ->expects($this->once()) + ->method('supportsNormalization') + ->with(new DateTime($this->exampleDateTimeString), 'xml') + ->willReturn(true); + + return $mock; + } + + /** + * @return string + */ + private function createXmlWithDateTime() + { + return sprintf(' +%s +', $this->exampleDateTimeString); + } + + /** + * @return string + */ + private function createXmlWithDateTimeField() + { + return sprintf(' + +', $this->exampleDateTimeString); + } } From 175bc9076f23d0bd076bd95bbfad354ec704e3cc Mon Sep 17 00:00:00 2001 From: gr1ev0us Date: Wed, 22 Feb 2017 00:04:43 +0300 Subject: [PATCH 2/3] Issue-21617 Review fix --- .../Tests/Encoder/XmlEncoderTest.php | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 1c4a5a95274a9..1d181f936fbfb 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Serializer\Tests\Encoder; -use DateTime; use PHPUnit\Framework\TestCase; use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Exception\UnexpectedValueException; @@ -29,9 +28,6 @@ class XmlEncoderTest extends TestCase */ private $encoder; - /** - * @var string - */ private $exampleDateTimeString = '2017-02-19T15:16:08+0300'; protected function setUp() @@ -535,40 +531,33 @@ protected function getObject() return $obj; } - /** - * @test - */ public function testEncodeXmlWithBoolValue() { - $expectedXml = ' + $expectedXml = <<<'XML' + 10 -'; + +XML; $actualXml = $this->encoder->encode(array('foo' => true, 'bar' => false), 'xml'); $this->assertEquals($expectedXml, $actualXml); } - /** - * @test - */ public function testEncodeXmlWithDateTimeObjectValue() { $xmlEncoder = $this->createXmlEncoderWithDateTimeNormalizer(); - $actualXml = $xmlEncoder->encode(array('dateTime' => new DateTime($this->exampleDateTimeString)), 'xml'); + $actualXml = $xmlEncoder->encode(array('dateTime' => new \DateTime($this->exampleDateTimeString)), 'xml'); $this->assertEquals($this->createXmlWithDateTime(), $actualXml); } - /** - * @test - */ public function testEncodeXmlWithDateTimeObjectField() { $xmlEncoder = $this->createXmlEncoderWithDateTimeNormalizer(); - $actualXml = $xmlEncoder->encode(array('foo' => array('@dateTime' => new DateTime($this->exampleDateTimeString))), 'xml'); + $actualXml = $xmlEncoder->encode(array('foo' => array('@dateTime' => new \DateTime($this->exampleDateTimeString))), 'xml'); $this->assertEquals($this->createXmlWithDateTimeField(), $actualXml); } @@ -595,13 +584,13 @@ private function createMockDateTimeNormalizer() $mock ->expects($this->once()) ->method('normalize') - ->with(new DateTime($this->exampleDateTimeString), 'xml', array()) + ->with(new \DateTime($this->exampleDateTimeString), 'xml', array()) ->willReturn($this->exampleDateTimeString); $mock ->expects($this->once()) ->method('supportsNormalization') - ->with(new DateTime($this->exampleDateTimeString), 'xml') + ->with(new \DateTime($this->exampleDateTimeString), 'xml') ->willReturn(true); return $mock; From 88bfde57f243c8c006814fd095a89196bac0b911 Mon Sep 17 00:00:00 2001 From: gr1ev0us Date: Mon, 27 Feb 2017 23:21:20 +0300 Subject: [PATCH 3/3] Issue-21617 Review fix --- .../Component/Serializer/Tests/Encoder/XmlEncoderTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 1d181f936fbfb..e455e2d224e8c 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -12,14 +12,14 @@ namespace Symfony\Component\Serializer\Tests\Encoder; use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\Tests\Fixtures\Dummy; +use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy; +use Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy; use Symfony\Component\Serializer\Encoder\XmlEncoder; +use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Serializer\Normalizer\CustomNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -use Symfony\Component\Serializer\Serializer; -use Symfony\Component\Serializer\Tests\Fixtures\Dummy; -use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy; -use Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy; class XmlEncoderTest extends TestCase {