Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ffb4266

Browse files
committed
[Serializer] Encode empty objects as objects, not arrays
Allows Normalizers to return a representation of an empty object that the encoder recognizes as such.
1 parent 9ad492f commit ffb4266

8 files changed

Lines changed: 102 additions & 3 deletions

File tree

src/Symfony/Component/Serializer/Encoder/XmlEncoder.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
1515
use Symfony\Component\Serializer\SerializerAwareInterface;
1616
use Symfony\Component\Serializer\SerializerAwareTrait;
17+
use Symfony\Component\Serializer\Util\EmptyObject;
1718

1819
/**
1920
* Encodes XML data.
@@ -469,6 +470,8 @@ private function selectNodeType(\DOMNode $node, $val): bool
469470
$node->appendChild($child);
470471
} elseif ($val instanceof \Traversable) {
471472
$this->buildXml($node, $val);
473+
} elseif ($val instanceof EmptyObject) {
474+
// Do nothing
472475
} elseif (\is_object($val)) {
473476
return $this->selectNodeType($node, $this->serializer->normalize($val, $this->format, $this->context));
474477
} elseif (is_numeric($val)) {

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface;
2525
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
2626
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
27+
use Symfony\Component\Serializer\Util\EmptyObject;
2728

2829
/**
2930
* Base class for a normalizer dealing with objects.
@@ -119,6 +120,10 @@ public function normalize($object, $format = null, array $context = array())
119120
$data = $this->updateData($data, $attribute, $this->serializer->normalize($attributeValue, $format, $this->createChildContext($context, $attribute)));
120121
}
121122

123+
if (!count($data)) {
124+
return new EmptyObject();
125+
}
126+
122127
return $data;
123128
}
124129

src/Symfony/Component/Serializer/Serializer.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
2828
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
2929
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
30+
use Symfony\Component\Serializer\Util\EmptyObject;
3031

3132
/**
3233
* Serializer serializes and deserializes data.
@@ -138,7 +139,7 @@ public function normalize($data, $format = null, array $context = array())
138139
return $normalizer->normalize($data, $format, $context);
139140
}
140141

141-
if (null === $data || is_scalar($data)) {
142+
if (null === $data || is_scalar($data) || $data instanceof EmptyObject) {
142143
return $data;
143144
}
144145

src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
2424
use Symfony\Component\Serializer\SerializerAwareInterface;
2525
use Symfony\Component\Serializer\SerializerInterface;
26+
use Symfony\Component\Serializer\Util\EmptyObject;
2627

2728
class AbstractObjectNormalizerTest extends TestCase
2829
{
@@ -161,12 +162,21 @@ public function testExtraAttributesException()
161162
'allow_extra_attributes' => false,
162163
));
163164
}
165+
166+
public function testNormalizeEmptyObject()
167+
{
168+
$normalizer = new AbstractObjectNormalizerDummy();
169+
$normalizedData = $normalizer->normalize(new EmptyDummy());
170+
171+
$this->assertEquals(new EmptyObject(), $normalizedData);
172+
}
164173
}
165174

166175
class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer
167176
{
168177
protected function extractAttributes($object, $format = null, array $context = array())
169178
{
179+
return [];
170180
}
171181

172182
protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
@@ -196,6 +206,8 @@ class Dummy
196206
public $baz;
197207
}
198208

209+
class EmptyDummy {}
210+
199211
class AbstractObjectNormalizerWithMetadata extends AbstractObjectNormalizer
200212
{
201213
public function __construct()

src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy;
3030
use Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy;
3131
use Symfony\Component\Serializer\Tests\Fixtures\SiblingHolder;
32+
use Symfony\Component\Serializer\Util\EmptyObject;
3233

3334
/**
3435
* @author Kévin Dunglas <[email protected]>
@@ -319,7 +320,7 @@ public function testNormalizeNoPropertyInGroup()
319320
$obj = new GroupDummy();
320321
$obj->setFoo('foo');
321322

322-
$this->assertEquals(array(), $this->normalizer->normalize($obj, null, array('groups' => array('notExist'))));
323+
$this->assertEquals(new EmptyObject(), $this->normalizer->normalize($obj, null, array('groups' => array('notExist'))));
323324
}
324325

325326
public function testGroupsNormalizeWithNameConverter()

src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy;
2525
use Symfony\Component\Serializer\Tests\Fixtures\PropertyCircularReferenceDummy;
2626
use Symfony\Component\Serializer\Tests\Fixtures\PropertySiblingHolder;
27+
use Symfony\Component\Serializer\Util\EmptyObject;
2728

2829
class PropertyNormalizerTest extends TestCase
2930
{
@@ -154,7 +155,7 @@ public function testIgnoredAttributes()
154155
$obj->setBar('bar');
155156

156157
$this->assertEquals(
157-
array(),
158+
new EmptyObject(),
158159
$this->normalizer->normalize($obj, 'any')
159160
);
160161
}

src/Symfony/Component/Serializer/Tests/SerializerTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
use Doctrine\Common\Annotations\AnnotationReader;
1515
use PHPUnit\Framework\TestCase;
1616
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
17+
use Symfony\Component\Serializer\Encoder\CsvEncoder;
1718
use Symfony\Component\Serializer\Encoder\JsonEncoder;
19+
use Symfony\Component\Serializer\Encoder\XmlEncoder;
20+
use Symfony\Component\Serializer\Encoder\YamlEncoder;
1821
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
1922
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
2023
use Symfony\Component\Serializer\Mapping\ClassMetadata;
@@ -182,6 +185,48 @@ public function testSerializeArrayOfScalars()
182185
$this->assertEquals(json_encode($data), $result);
183186
}
184187

188+
public function testSerializeEmpty()
189+
{
190+
$serializer = new Serializer(array(new ObjectNormalizer()), array('json' => new JsonEncoder()));
191+
$data = array('foo' => new \stdClass());
192+
$result = $serializer->serialize($data, 'json');
193+
$this->assertEquals('{"foo":{}}', $result);
194+
}
195+
196+
public function testSerializeEmptyYaml()
197+
{
198+
$serializer = new Serializer(array(new ObjectNormalizer()), array('yaml' => new YamlEncoder()));
199+
$data = array('foo' => new \stdClass());
200+
$result = $serializer->serialize($data, 'yaml');
201+
$this->assertEquals('{ foo: null }', $result);
202+
}
203+
204+
public function testSerializeEmptyXml()
205+
{
206+
$serializer = new Serializer(array(new ObjectNormalizer()), array('xml' => new XmlEncoder()));
207+
$data = array('foo' => new \stdClass());
208+
$result = $serializer->serialize($data, 'xml');
209+
$this->assertEquals(<<<'XML'
210+
<?xml version="1.0"?>
211+
<response><foo/></response>
212+
213+
XML
214+
, $result);
215+
}
216+
217+
public function testSerializeEmptyCsv()
218+
{
219+
$serializer = new Serializer(array(new ObjectNormalizer()), array('csv' => new CsvEncoder()));
220+
$data = array('foo' => new \stdClass(), 'bar' => new \stdClass());
221+
$result = $serializer->serialize($data, 'csv');
222+
$this->assertEquals(<<<'CSV'
223+
foo,bar
224+
,
225+
226+
CSV
227+
, $result);
228+
}
229+
185230
/**
186231
* @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException
187232
*/
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Util;
13+
14+
/**
15+
* Represents an empty object that has already been normalized
16+
* Used to make sure you get {} instead of [] in the output
17+
*
18+
* @author Fred Cox <[email protected]>
19+
*/
20+
class EmptyObject
21+
{
22+
/**
23+
* This value is used by the CsvEncoder
24+
*
25+
* @return string
26+
*/
27+
public function __toString()
28+
{
29+
return '';
30+
}
31+
}

0 commit comments

Comments
 (0)