From 806bb8fa2d5ec8c6d09e4b995dfd3056542395b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 18 Aug 2021 10:37:20 +0200 Subject: [PATCH] [Serializer] Deprecate support for returning empty, iterable, countable, raw object when normalizing --- src/Symfony/Component/Serializer/CHANGELOG.md | 1 + .../Component/Serializer/Serializer.php | 4 + .../Serializer/Tests/SerializerTest.php | 91 ++++++++++++++++++- 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index 06674470d2996..5e92edee9a044 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Add support of PHP backed enumerations * Add support for serializing empty array as object + * Deprecate support for returning empty, iterable, countable, raw object when normalizing 5.3 --- diff --git a/src/Symfony/Component/Serializer/Serializer.php b/src/Symfony/Component/Serializer/Serializer.php index 29f829a3a6b0a..be2e2ce54fe18 100644 --- a/src/Symfony/Component/Serializer/Serializer.php +++ b/src/Symfony/Component/Serializer/Serializer.php @@ -168,6 +168,10 @@ public function normalize($data, string $format = null, array $context = []) if (is_countable($data) && 0 === \count($data)) { switch (true) { case ($context[AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS] ?? false) && \is_object($data): + if (!$data instanceof \ArrayObject) { + trigger_deprecation('symfony/serializer', '5.4', 'Returning empty object of class "%s" from "%s()" is deprecated. This class should extend "ArrayObject".', get_debug_type($data), __METHOD__); + } + return $data; case ($context[self::EMPTY_ARRAY_AS_OBJECT] ?? false) && \is_array($data): return new \ArrayObject(); diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 78a038ec8b7a2..c44cbf2acbeb6 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -606,6 +606,61 @@ public function testNormalizeEmptyArrayAsObjectAndPreserveEmptyArrayObject(Seria ])); } + /** + * @dataProvider provideObjectOrCollectionTests + * @group legacy + */ + public function testNormalizeWithCollectionLegacy(Serializer $serializer, array $data) + { + $data['g1'] = new BazLegacy([]); + $data['g2'] = new BazLegacy(['greg']); + $expected = '{"a1":[],"a2":{"k":"v"},"b1":[],"b2":{"k":"v"},"c1":{"nested":[]},"c2":{"nested":{"k":"v"}},"d1":{"nested":[]},"d2":{"nested":{"k":"v"}},"e1":{"map":[]},"e2":{"map":{"k":"v"}},"f1":{"map":[]},"f2":{"map":{"k":"v"}},"g1":{"list":[],"settings":[]},"g2":{"list":["greg"],"settings":[]}}'; + $this->assertSame($expected, $serializer->serialize($data, 'json')); + } + + /** + * @dataProvider provideObjectOrCollectionTests + * @group legacy + */ + public function testNormalizePreserveEmptyArrayObjectLegacy(Serializer $serializer, array $data) + { + $data['g1'] = new BazLegacy([]); + $data['g2'] = new BazLegacy(['greg']); + $expected = '{"a1":{},"a2":{"k":"v"},"b1":[],"b2":{"k":"v"},"c1":{"nested":{}},"c2":{"nested":{"k":"v"}},"d1":{"nested":[]},"d2":{"nested":{"k":"v"}},"e1":{"map":[]},"e2":{"map":{"k":"v"}},"f1":{"map":{}},"f2":{"map":{"k":"v"}},"g1":{"list":{"list":[]},"settings":[]},"g2":{"list":["greg"],"settings":[]}}'; + $this->assertSame($expected, $serializer->serialize($data, 'json', [ + AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS => true, + ])); + } + + /** + * @dataProvider provideObjectOrCollectionTests + * @group legacy + */ + public function testNormalizeEmptyArrayAsObjectLegacy(Serializer $serializer, array $data) + { + $data['g1'] = new BazLegacy([]); + $data['g2'] = new BazLegacy(['greg']); + $expected = '{"a1":[],"a2":{"k":"v"},"b1":{},"b2":{"k":"v"},"c1":{"nested":[]},"c2":{"nested":{"k":"v"}},"d1":{"nested":{}},"d2":{"nested":{"k":"v"}},"e1":{"map":{}},"e2":{"map":{"k":"v"}},"f1":{"map":[]},"f2":{"map":{"k":"v"}},"g1":{"list":[],"settings":{}},"g2":{"list":["greg"],"settings":{}}}'; + $this->assertSame($expected, $serializer->serialize($data, 'json', [ + Serializer::EMPTY_ARRAY_AS_OBJECT => true, + ])); + } + + /** + * @dataProvider provideObjectOrCollectionTests + * @group legacy + */ + public function testNormalizeEmptyArrayAsObjectAndPreserveEmptyArrayObjectLegacy(Serializer $serializer, array $data) + { + $data['g1'] = new BazLegacy([]); + $data['g2'] = new BazLegacy(['greg']); + $expected = '{"a1":{},"a2":{"k":"v"},"b1":{},"b2":{"k":"v"},"c1":{"nested":{}},"c2":{"nested":{"k":"v"}},"d1":{"nested":{}},"d2":{"nested":{"k":"v"}},"e1":{"map":{}},"e2":{"map":{"k":"v"}},"f1":{"map":{}},"f2":{"map":{"k":"v"}},"g1":{"list":{"list":[]},"settings":{}},"g2":{"list":["greg"],"settings":{}}}'; + $this->assertSame($expected, $serializer->serialize($data, 'json', [ + Serializer::EMPTY_ARRAY_AS_OBJECT => true, + AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS => true, + ])); + } + public function testNormalizeScalar() { $serializer = new Serializer([], ['json' => new JsonEncoder()]); @@ -791,7 +846,41 @@ public function __construct(array $list) } } -class DummyList implements \Countable, \IteratorAggregate +class DummyList extends \ArrayObject +{ + public $list; + + public function __construct(array $list) + { + $this->list = $list; + + $this->setFlags(\ArrayObject::STD_PROP_LIST); + } + + public function count(): int + { + return \count($this->list); + } + + public function getIterator(): \Traversable + { + return new \ArrayIterator($this->list); + } +} + +class BazLegacy +{ + public $list; + + public $settings = []; + + public function __construct(array $list) + { + $this->list = new DummyListLegacy($list); + } +} + +class DummyListLegacy implements \Countable, \IteratorAggregate { public $list;