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

Skip to content

Commit 8752cba

Browse files
committed
Add a normalizer that support JsonSerializable objects
Handles circular references
1 parent 1b85799 commit 8752cba

File tree

7 files changed

+216
-0
lines changed

7 files changed

+216
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Component\Config\FileLocator;
2626
use Symfony\Component\Serializer\Normalizer\DataUriNormalizer;
2727
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
28+
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
2829
use Symfony\Component\Validator\Validation;
2930

3031
/**
@@ -914,6 +915,13 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
914915
$definition->addTag('serializer.normalizer', array('priority' => -910));
915916
}
916917

918+
if (class_exists('Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer')) {
919+
// Run before serializer.normalizer.object
920+
$definition = $container->register('serializer.normalizer.json', JsonSerializableNormalizer::class);
921+
$definition->setPublic(false);
922+
$definition->addTag('serializer.normalizer', array('priority' => -900));
923+
}
924+
917925
$loader->load('serializer.xml');
918926
$chainLoader = $container->getDefinition('serializer.mapping.chain_loader');
919927

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\DependencyInjection\Reference;
2121
use Symfony\Component\Serializer\Normalizer\DataUriNormalizer;
2222
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
23+
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
2324

2425
abstract class FrameworkExtensionTest extends TestCase
2526
{
@@ -485,6 +486,21 @@ public function testDateTimeNormalizerRegistered()
485486
$this->assertEquals(-910, $tag[0]['priority']);
486487
}
487488

489+
public function testJsonNormalizerRegistered()
490+
{
491+
if (!class_exists('Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer')) {
492+
$this->markTestSkipped('The JsonSerializableNormalizer has been introduced in the Serializer Component version 3.1.');
493+
}
494+
495+
$container = $this->createContainerFromFile('full');
496+
497+
$definition = $container->getDefinition('serializer.normalizer.json');
498+
$tag = $definition->getTag('serializer.normalizer');
499+
500+
$this->assertEquals(JsonSerializableNormalizer::class, $definition->getClass());
501+
$this->assertEquals(-900, $tag[0]['priority']);
502+
}
503+
488504
public function testAssetHelperWhenAssetsAreEnabled()
489505
{
490506
$container = $this->createContainerFromFile('full');

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"symfony/form": "~2.8|~3.0",
4747
"symfony/expression-language": "~2.8|~3.0",
4848
"symfony/process": "~2.8|~3.0",
49+
"symfony/serializer": "~2.8|^3.1",
4950
"symfony/validator": "~2.8|~3.0",
5051
"symfony/yaml": "~2.8|~3.0",
5152
"symfony/property-info": "~2.8|~3.0",

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
3.1.0
5+
-----
6+
7+
* added support for serializing objects that implement `JsonSerializable`
8+
49
2.7.0
510
-----
611

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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\Normalizer;
13+
14+
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
15+
use Symfony\Component\Serializer\Exception\LogicException;
16+
17+
/**
18+
* A normalizer that uses an objects own JsonSerializable implementation.
19+
*
20+
* @author Fred Cox <[email protected]>
21+
*/
22+
class JsonSerializableNormalizer extends AbstractNormalizer
23+
{
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
public function normalize($object, $format = null, array $context = array())
28+
{
29+
if ($this->isCircularReference($object, $context)) {
30+
return $this->handleCircularReference($object);
31+
}
32+
33+
if (!$object instanceof \JsonSerializable) {
34+
throw new InvalidArgumentException(sprintf('The object must implement "%s".', \JsonSerializable::class));
35+
}
36+
37+
if (!$this->serializer instanceof NormalizerInterface) {
38+
throw new LogicException('Cannot normalize object because injected serializer is not a normalizer');
39+
}
40+
41+
return $this->serializer->normalize($object->jsonSerialize(), $format, $context);
42+
}
43+
44+
/**
45+
* {@inheritdoc}
46+
*/
47+
public function supportsNormalization($data, $format = null)
48+
{
49+
return $data instanceof \JsonSerializable;
50+
}
51+
52+
/**
53+
* {@inheritdoc}
54+
*/
55+
public function supportsDenormalization($data, $type, $format = null)
56+
{
57+
return false;
58+
}
59+
60+
/**
61+
* {@inheritdoc}
62+
*/
63+
public function denormalize($data, $class, $format = null, array $context = array())
64+
{
65+
throw new LogicException(sprintf('Cannot denormalize with "%s".', \JsonSerializable::class));
66+
}
67+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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\Tests\Fixtures;
13+
14+
class JsonSerializableDummy implements \JsonSerializable
15+
{
16+
public function jsonSerialize()
17+
{
18+
return array(
19+
'foo' => 'a',
20+
'bar' => 'b',
21+
'baz' => 'c',
22+
'qux' => $this,
23+
);
24+
}
25+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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\Tests\Normalizer;
13+
14+
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
15+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
16+
use Symfony\Component\Serializer\SerializerInterface;
17+
use Symfony\Component\Serializer\Tests\Fixtures\JsonSerializableDummy;
18+
19+
/**
20+
* @author Fred Cox <[email protected]>
21+
*/
22+
class JsonSerializableNormalizerTest extends \PHPUnit_Framework_TestCase
23+
{
24+
/**
25+
* @var JsonSerializableNormalizer
26+
*/
27+
private $normalizer;
28+
29+
/**
30+
* @var \PHPUnit_Framework_MockObject_MockObject|SerializerInterface
31+
*/
32+
private $serializer;
33+
34+
protected function setUp()
35+
{
36+
$this->serializer = $this->getMock(JsonSerializerNormalizer::class);
37+
$this->normalizer = new JsonSerializableNormalizer();
38+
$this->normalizer->setSerializer($this->serializer);
39+
}
40+
41+
public function testSupportNormalization()
42+
{
43+
$this->assertTrue($this->normalizer->supportsNormalization(new JsonSerializableDummy()));
44+
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
45+
}
46+
47+
public function testNormalize()
48+
{
49+
$this->serializer
50+
->expects($this->once())
51+
->method('normalize')
52+
->will($this->returnCallback(function($data) {
53+
$this->assertArraySubset(array('foo' => 'a', 'bar' => 'b', 'baz' => 'c'), $data);
54+
55+
return 'string_object';
56+
}))
57+
;
58+
59+
$this->assertEquals('string_object', $this->normalizer->normalize(new JsonSerializableDummy()));
60+
}
61+
62+
/**
63+
* @expectedException \Symfony\Component\Serializer\Exception\CircularReferenceException
64+
*/
65+
public function testCircularNormalize()
66+
{
67+
$this->normalizer->setCircularReferenceLimit(1);
68+
69+
$this->serializer
70+
->expects($this->once())
71+
->method('normalize')
72+
->will($this->returnCallback(function($data, $format, $context) {
73+
$this->normalizer->normalize($data['qux'], $format, $context);
74+
75+
return 'string_object';
76+
}))
77+
;
78+
79+
$this->assertEquals('string_object', $this->normalizer->normalize(new JsonSerializableDummy()));
80+
}
81+
82+
/**
83+
* @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException
84+
* @expectedExceptionMessage The object must implement "JsonSerializable".
85+
*/
86+
public function testInvalidDataThrowException()
87+
{
88+
$this->normalizer->normalize(new \stdClass());
89+
}
90+
}
91+
92+
abstract class JsonSerializerNormalizer implements SerializerInterface, NormalizerInterface
93+
{
94+
}

0 commit comments

Comments
 (0)