Add a normalizer that support JsonSerializable objects
Handles circular references
This commit is contained in:
parent
1b85799602
commit
a6788813fa
@ -25,6 +25,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Serializer\Normalizer\DataUriNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
|
||||
use Symfony\Component\Validator\Validation;
|
||||
|
||||
/**
|
||||
@ -914,6 +915,13 @@ class FrameworkExtension extends Extension
|
||||
$definition->addTag('serializer.normalizer', array('priority' => -910));
|
||||
}
|
||||
|
||||
if (class_exists('Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer')) {
|
||||
// Run before serializer.normalizer.object
|
||||
$definition = $container->register('serializer.normalizer.json_serializable', JsonSerializableNormalizer::class);
|
||||
$definition->setPublic(false);
|
||||
$definition->addTag('serializer.normalizer', array('priority' => -900));
|
||||
}
|
||||
|
||||
$loader->load('serializer.xml');
|
||||
$chainLoader = $container->getDefinition('serializer.mapping.chain_loader');
|
||||
|
||||
|
@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Serializer\Normalizer\DataUriNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
|
||||
|
||||
abstract class FrameworkExtensionTest extends TestCase
|
||||
{
|
||||
@ -485,6 +486,21 @@ abstract class FrameworkExtensionTest extends TestCase
|
||||
$this->assertEquals(-910, $tag[0]['priority']);
|
||||
}
|
||||
|
||||
public function testJsonNormalizerRegistered()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer')) {
|
||||
$this->markTestSkipped('The JsonSerializableNormalizer has been introduced in the Serializer Component version 3.1.');
|
||||
}
|
||||
|
||||
$container = $this->createContainerFromFile('full');
|
||||
|
||||
$definition = $container->getDefinition('serializer.normalizer.json');
|
||||
$tag = $definition->getTag('serializer.normalizer');
|
||||
|
||||
$this->assertEquals(JsonSerializableNormalizer::class, $definition->getClass());
|
||||
$this->assertEquals(-900, $tag[0]['priority']);
|
||||
}
|
||||
|
||||
public function testAssetHelperWhenAssetsAreEnabled()
|
||||
{
|
||||
$container = $this->createContainerFromFile('full');
|
||||
|
@ -46,6 +46,7 @@
|
||||
"symfony/form": "~2.8|~3.0",
|
||||
"symfony/expression-language": "~2.8|~3.0",
|
||||
"symfony/process": "~2.8|~3.0",
|
||||
"symfony/serializer": "~2.8|^3.0",
|
||||
"symfony/validator": "~2.8|~3.0",
|
||||
"symfony/yaml": "~2.8|~3.0",
|
||||
"symfony/property-info": "~2.8|~3.0",
|
||||
|
@ -1,6 +1,11 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
3.1.0
|
||||
-----
|
||||
|
||||
* added support for serializing objects that implement `JsonSerializable`
|
||||
|
||||
2.7.0
|
||||
-----
|
||||
|
||||
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* A normalizer that uses an objects own JsonSerializable implementation.
|
||||
*
|
||||
* @author Fred Cox <mcfedr@gmail.com>
|
||||
*/
|
||||
class JsonSerializableNormalizer extends AbstractNormalizer
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = null, array $context = array())
|
||||
{
|
||||
if ($this->isCircularReference($object, $context)) {
|
||||
return $this->handleCircularReference($object);
|
||||
}
|
||||
|
||||
if (!$object instanceof \JsonSerializable) {
|
||||
throw new InvalidArgumentException(sprintf('The object must implement "%s".', \JsonSerializable::class));
|
||||
}
|
||||
|
||||
if (!$this->serializer instanceof NormalizerInterface) {
|
||||
throw new LogicException('Cannot normalize object because injected serializer is not a normalizer');
|
||||
}
|
||||
|
||||
return $this->serializer->normalize($object->jsonSerialize(), $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsNormalization($data, $format = null)
|
||||
{
|
||||
return $data instanceof \JsonSerializable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsDenormalization($data, $type, $format = null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function denormalize($data, $class, $format = null, array $context = array())
|
||||
{
|
||||
throw new LogicException(sprintf('Cannot denormalize with "%s".', \JsonSerializable::class));
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Tests\Fixtures;
|
||||
|
||||
class JsonSerializableDummy implements \JsonSerializable
|
||||
{
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return array(
|
||||
'foo' => 'a',
|
||||
'bar' => 'b',
|
||||
'baz' => 'c',
|
||||
'qux' => $this,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Serializer\Tests\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\JsonSerializableDummy;
|
||||
|
||||
/**
|
||||
* @author Fred Cox <mcfedr@gmail.com>
|
||||
*/
|
||||
class JsonSerializableNormalizerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var JsonSerializableNormalizer
|
||||
*/
|
||||
private $normalizer;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject|SerializerInterface
|
||||
*/
|
||||
private $serializer;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->serializer = $this->getMock(JsonSerializerNormalizer::class);
|
||||
$this->normalizer = new JsonSerializableNormalizer();
|
||||
$this->normalizer->setSerializer($this->serializer);
|
||||
}
|
||||
|
||||
public function testSupportNormalization()
|
||||
{
|
||||
$this->assertTrue($this->normalizer->supportsNormalization(new JsonSerializableDummy()));
|
||||
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
|
||||
}
|
||||
|
||||
public function testNormalize()
|
||||
{
|
||||
$this->serializer
|
||||
->expects($this->once())
|
||||
->method('normalize')
|
||||
->will($this->returnCallback(function($data) {
|
||||
$this->assertArraySubset(array('foo' => 'a', 'bar' => 'b', 'baz' => 'c'), $data);
|
||||
|
||||
return 'string_object';
|
||||
}))
|
||||
;
|
||||
|
||||
$this->assertEquals('string_object', $this->normalizer->normalize(new JsonSerializableDummy()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Serializer\Exception\CircularReferenceException
|
||||
*/
|
||||
public function testCircularNormalize()
|
||||
{
|
||||
$this->normalizer->setCircularReferenceLimit(1);
|
||||
|
||||
$this->serializer
|
||||
->expects($this->once())
|
||||
->method('normalize')
|
||||
->will($this->returnCallback(function($data, $format, $context) {
|
||||
$this->normalizer->normalize($data['qux'], $format, $context);
|
||||
|
||||
return 'string_object';
|
||||
}))
|
||||
;
|
||||
|
||||
$this->assertEquals('string_object', $this->normalizer->normalize(new JsonSerializableDummy()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessage The object must implement "JsonSerializable".
|
||||
*/
|
||||
public function testInvalidDataThrowException()
|
||||
{
|
||||
$this->normalizer->normalize(new \stdClass());
|
||||
}
|
||||
}
|
||||
|
||||
abstract class JsonSerializerNormalizer implements SerializerInterface, NormalizerInterface
|
||||
{
|
||||
}
|
Reference in New Issue
Block a user