Skip to content

Commit 889fa6a

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 c3fd60d commit 889fa6a

File tree

11 files changed

+111
-5
lines changed

11 files changed

+111
-5
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function encode($data, $format, array $context = array())
5353
{
5454
$handle = fopen('php://temp,', 'w+');
5555

56-
if (!\is_array($data)) {
56+
if (!(\is_array($data) || $data instanceof \Traversable)) {
5757
$data = array(array($data));
5858
} elseif (empty($data)) {
5959
$data = array(array());
@@ -185,10 +185,10 @@ public function supportsDecoding($format)
185185
/**
186186
* Flattens an array and generates keys including the path.
187187
*/
188-
private function flatten(array $array, array &$result, string $keySeparator, string $parentKey = '', bool $escapeFormulas = false)
188+
private function flatten($array, array &$result, string $keySeparator, string $parentKey = '', bool $escapeFormulas = false)
189189
{
190190
foreach ($array as $key => $value) {
191-
if (\is_array($value)) {
191+
if (\is_array($value) || $value instanceof \Traversable) {
192192
$this->flatten($value, $result, $keySeparator, $parentKey.$key.$keySeparator, $escapeFormulas);
193193
} else {
194194
if ($escapeFormulas && \in_array(substr($value, 0, 1), $this->formulasStartCharacters, true)) {
@@ -219,7 +219,7 @@ private function getCsvOptions(array $context)
219219
/**
220220
* @return string[]
221221
*/
222-
private function extractHeaders(array $data)
222+
private function extractHeaders($data)
223223
{
224224
$headers = array();
225225
$flippedHeaders = array();

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Serializer\Exception\RuntimeException;
1515
use Symfony\Component\Yaml\Dumper;
1616
use Symfony\Component\Yaml\Parser;
17+
use Symfony\Component\Yaml\Yaml;
1718

1819
/**
1920
* Encodes YAML data.
@@ -46,6 +47,10 @@ public function encode($data, $format, array $context = array())
4647
{
4748
$context = array_merge($this->defaultContext, $context);
4849

50+
if (isset($context['array_objects'])) {
51+
$context['yaml_flags'] |= Yaml::DUMP_OBJECT_AS_MAP;
52+
}
53+
4954
return $this->dumper->dump($data, $context['yaml_inline'], $context['yaml_indent'], $context['yaml_flags']);
5055
}
5156

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ public function normalize($object, $format = null, array $context = array())
119119
$data = $this->updateData($data, $attribute, $this->serializer->normalize($attributeValue, $format, $this->createChildContext($context, $attribute)), $class, $format, $context);
120120
}
121121

122+
if (isset($context['array_objects']) && !\count($data)) {
123+
return new \ArrayObject();
124+
}
125+
122126
return $data;
123127
}
124128

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ interface NormalizerInterface
2929
* @param string $format Format the normalization result will be encoded as
3030
* @param array $context Context options for the normalizer
3131
*
32-
* @return array|string|int|float|bool
32+
* @return array|string|int|float|bool|\ArrayObject
3333
*
3434
* @throws InvalidArgumentException Occurs when the object given is not an attempted type for the normalizer
3535
* @throws CircularReferenceException Occurs when the normalizer detects a circular reference when no circular

src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,43 @@ public function testEncodeFormulasWithSettingsPassedInContext()
276276
)));
277277
}
278278

279+
public function testEncodeArrayObject()
280+
{
281+
$value = new \ArrayObject(array('foo' => 'hello', 'bar' => 'hey ho'));
282+
283+
$this->assertEquals(<<<'CSV'
284+
foo,bar
285+
hello,"hey ho"
286+
287+
CSV
288+
, $this->encoder->encode($value, 'csv'));
289+
290+
$value = new \ArrayObject();
291+
292+
$this->assertEquals("\n", $this->encoder->encode($value, 'csv'));
293+
}
294+
295+
public function testEncodeNestedArrayObject()
296+
{
297+
$value = new \ArrayObject(array('foo' => new \ArrayObject(array('nested' => 'value')), 'bar' => new \ArrayObject(array('another' => 'word'))));
298+
299+
$this->assertEquals(<<<'CSV'
300+
foo.nested,bar.another
301+
value,word
302+
303+
CSV
304+
, $this->encoder->encode($value, 'csv'));
305+
}
306+
307+
public function testEncodeEmptyArrayObject()
308+
{
309+
$value = new \ArrayObject();
310+
$this->assertEquals("\n", $this->encoder->encode($value, 'csv'));
311+
312+
$value = array('foo' => new \ArrayObject());
313+
$this->assertEquals("\n\n", $this->encoder->encode($value, 'csv'));
314+
}
315+
279316
public function testSupportsDecoding()
280317
{
281318
$this->assertTrue($this->encoder->supportsDecoding('csv'));

src/Symfony/Component/Serializer/Tests/Encoder/JsonEncodeTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public function encodeProvider()
4646
return array(
4747
array(array(), '[]', array()),
4848
array(array(), '{}', array('json_encode_options' => JSON_FORCE_OBJECT)),
49+
array(new \ArrayObject(), '{}', array()),
50+
array(new \ArrayObject(array('foo' => 'bar')), '{"foo":"bar"}', array()),
4951
);
5052
}
5153

src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,26 @@ public function testEncodeScalar()
4747
$this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
4848
}
4949

50+
public function testEncodeArrayObject()
51+
{
52+
$obj = new \ArrayObject(array('foo' => 'bar'));
53+
54+
$expected = '<?xml version="1.0"?>'."\n".
55+
'<response><foo>bar</foo></response>'."\n";
56+
57+
$this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
58+
}
59+
60+
public function testEncodeEmptyArrayObject()
61+
{
62+
$obj = new \ArrayObject();
63+
64+
$expected = '<?xml version="1.0"?>'."\n".
65+
'<response/>'."\n";
66+
67+
$this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
68+
}
69+
5070
public function testSetRootNodeName()
5171
{
5272
$obj = new ScalarDummy();

src/Symfony/Component/Serializer/Tests/Encoder/YamlEncoderTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public function testEncode()
2828

2929
$this->assertEquals('foo', $encoder->encode('foo', 'yaml'));
3030
$this->assertEquals('{ foo: 1 }', $encoder->encode(array('foo' => 1), 'yaml'));
31+
$this->assertEquals('null', $encoder->encode(new \ArrayObject(array('foo' => 1)), 'yaml'));
32+
$this->assertEquals('{ foo: 1 }', $encoder->encode(new \ArrayObject(array('foo' => 1)), 'yaml', array('array_objects' => true)));
3133
}
3234

3335
public function testSupportsEncoding()

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,24 @@ public function testExtraAttributesException()
161161
'allow_extra_attributes' => false,
162162
));
163163
}
164+
165+
public function testNormalizeEmptyObject()
166+
{
167+
$normalizer = new AbstractObjectNormalizerDummy();
168+
169+
$normalizedData = $normalizer->normalize(new EmptyDummy());
170+
$this->assertEquals(array(), $normalizedData);
171+
172+
$normalizedData = $normalizer->normalize(new EmptyDummy(), 'any', array('array_objects' => true));
173+
$this->assertEquals(new \ArrayObject(), $normalizedData);
174+
}
164175
}
165176

166177
class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer
167178
{
168179
protected function extractAttributes($object, $format = null, array $context = array())
169180
{
181+
return array();
170182
}
171183

172184
protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
@@ -196,6 +208,10 @@ class Dummy
196208
public $baz;
197209
}
198210

211+
class EmptyDummy
212+
{
213+
}
214+
199215
class AbstractObjectNormalizerWithMetadata extends AbstractObjectNormalizer
200216
{
201217
public function __construct()

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ public function testIgnoredAttributes()
157157
array(),
158158
$this->normalizer->normalize($obj, 'any')
159159
);
160+
161+
$this->assertEquals(
162+
new \ArrayObject(),
163+
$this->normalizer->normalize($obj, 'any', array('array_objects' => true))
164+
);
160165
}
161166

162167
public function testGroupsNormalize()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy