Ensure the class discriminator mechanism works with serialization groups as well
This commit is contained in:
parent
fd8fd3df47
commit
c91b7afe35
@ -16,6 +16,7 @@ use Symfony\Component\PropertyAccess\PropertyAccess;
|
|||||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||||
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
|
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
|
||||||
use Symfony\Component\Serializer\Exception\RuntimeException;
|
use Symfony\Component\Serializer\Exception\RuntimeException;
|
||||||
|
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
|
||||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface;
|
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface;
|
||||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||||
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
|
||||||
@ -131,4 +132,24 @@ class ObjectNormalizer extends AbstractObjectNormalizer
|
|||||||
// Properties not found are ignored
|
// Properties not found are ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getAllowedAttributes($classOrObject, array $context, $attributesAsString = false)
|
||||||
|
{
|
||||||
|
if (false === $allowedAttributes = parent::getAllowedAttributes($classOrObject, $context, $attributesAsString)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->classDiscriminatorResolver && null !== $discriminatorMapping = $this->classDiscriminatorResolver->getMappingForMappedObject($classOrObject)) {
|
||||||
|
$allowedAttributes[] = $attributesAsString ? $discriminatorMapping->getTypeProperty() : new AttributeMetadata($discriminatorMapping->getTypeProperty());
|
||||||
|
|
||||||
|
foreach ($discriminatorMapping->getTypesMapping() as $class) {
|
||||||
|
$allowedAttributes = array_merge($allowedAttributes, parent::getAllowedAttributes($class, $context, $attributesAsString));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $allowedAttributes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@ use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @DiscriminatorMap(typeProperty="type", mapping={
|
* @DiscriminatorMap(typeProperty="type", mapping={
|
||||||
* "first"="Symfony\Component\Serializer\Tests\Fixtures\AbstractDummyFirstChild",
|
* "one"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne",
|
||||||
* "second"="Symfony\Component\Serializer\Tests\Fixtures\AbstractDummySecondChild"
|
* "two"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo"
|
||||||
* })
|
* })
|
||||||
*
|
*
|
||||||
* @author Samuel Roze <samuel.roze@gmail.com>
|
* @author Samuel Roze <samuel.roze@gmail.com>
|
||||||
|
@ -11,10 +11,17 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Serializer\Tests\Fixtures;
|
namespace Symfony\Component\Serializer\Tests\Fixtures;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Samuel Roze <samuel.roze@gmail.com>
|
* @author Samuel Roze <samuel.roze@gmail.com>
|
||||||
*/
|
*/
|
||||||
class DummyMessageNumberOne implements DummyMessageInterface
|
class DummyMessageNumberOne implements DummyMessageInterface
|
||||||
{
|
{
|
||||||
public $one;
|
public $one;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Groups({"two"})
|
||||||
|
*/
|
||||||
|
public $two;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Samuel Roze <samuel.roze@gmail.com>
|
||||||
|
*/
|
||||||
|
class DummyMessageNumberTwo implements DummyMessageInterface
|
||||||
|
{
|
||||||
|
}
|
@ -11,11 +11,14 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Serializer\Tests;
|
namespace Symfony\Component\Serializer\Tests;
|
||||||
|
|
||||||
|
use Doctrine\Common\Annotations\AnnotationReader;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
|
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
|
||||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
|
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
|
||||||
use Symfony\Component\Serializer\Mapping\ClassMetadata;
|
use Symfony\Component\Serializer\Mapping\ClassMetadata;
|
||||||
|
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
|
||||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||||
|
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
|
||||||
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
|
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
|
||||||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
|
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||||
@ -398,11 +401,9 @@ class SerializerTest extends TestCase
|
|||||||
$example = new DummyMessageNumberOne();
|
$example = new DummyMessageNumberOne();
|
||||||
$example->one = 1;
|
$example->one = 1;
|
||||||
|
|
||||||
$jsonData = '{"message-type":"one","one":1}';
|
$jsonData = '{"type":"one","one":1,"two":null}';
|
||||||
|
|
||||||
$discriminatorResolver = new ClassDiscriminatorFromClassMetadata($this->metadataFactoryMockForDummyInterface());
|
|
||||||
$serializer = new Serializer(array(new ObjectNormalizer(null, null, null, null, $discriminatorResolver)), array('json' => new JsonEncoder()));
|
|
||||||
|
|
||||||
|
$serializer = $this->serializerWithClassDiscriminator();
|
||||||
$deserialized = $serializer->deserialize($jsonData, DummyMessageInterface::class, 'json');
|
$deserialized = $serializer->deserialize($jsonData, DummyMessageInterface::class, 'json');
|
||||||
$this->assertEquals($example, $deserialized);
|
$this->assertEquals($example, $deserialized);
|
||||||
|
|
||||||
@ -410,51 +411,48 @@ class SerializerTest extends TestCase
|
|||||||
$this->assertEquals($jsonData, $serialized);
|
$this->assertEquals($jsonData, $serialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDeserializeAndSerializeInterfacedObjectsWithTheClassMetadataDiscriminatorResolverAndGroups()
|
||||||
|
{
|
||||||
|
$example = new DummyMessageNumberOne();
|
||||||
|
$example->two = 2;
|
||||||
|
|
||||||
|
$serializer = $this->serializerWithClassDiscriminator();
|
||||||
|
$deserialized = $serializer->deserialize('{"type":"one","one":1,"two":2}', DummyMessageInterface::class, 'json', array(
|
||||||
|
'groups' => array('two'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->assertEquals($example, $deserialized);
|
||||||
|
|
||||||
|
$serialized = $serializer->serialize($deserialized, 'json', array(
|
||||||
|
'groups' => array('two'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->assertEquals('{"two":2,"type":"one"}', $serialized);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \Symfony\Component\Serializer\Exception\RuntimeException
|
* @expectedException \Symfony\Component\Serializer\Exception\RuntimeException
|
||||||
* @expectedExceptionMessage The type "second" has no mapped class for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface"
|
* @expectedExceptionMessage The type "second" has no mapped class for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface"
|
||||||
*/
|
*/
|
||||||
public function testExceptionWhenTypeIsNotKnownInDiscriminator()
|
public function testExceptionWhenTypeIsNotKnownInDiscriminator()
|
||||||
{
|
{
|
||||||
$discriminatorResolver = new ClassDiscriminatorFromClassMetadata($this->metadataFactoryMockForDummyInterface());
|
$this->serializerWithClassDiscriminator()->deserialize('{"type":"second","one":1}', DummyMessageInterface::class, 'json');
|
||||||
$serializer = new Serializer(array(new ObjectNormalizer(null, null, null, null, $discriminatorResolver)), array('json' => new JsonEncoder()));
|
|
||||||
$serializer->deserialize('{"message-type":"second","one":1}', DummyMessageInterface::class, 'json');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \Symfony\Component\Serializer\Exception\RuntimeException
|
* @expectedException \Symfony\Component\Serializer\Exception\RuntimeException
|
||||||
* @expectedExceptionMessage Type property "message-type" not found for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface"
|
* @expectedExceptionMessage Type property "type" not found for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface"
|
||||||
*/
|
*/
|
||||||
public function testExceptionWhenTypeIsNotInTheBodyToDeserialiaze()
|
public function testExceptionWhenTypeIsNotInTheBodyToDeserialiaze()
|
||||||
{
|
{
|
||||||
$discriminatorResolver = new ClassDiscriminatorFromClassMetadata($this->metadataFactoryMockForDummyInterface());
|
$this->serializerWithClassDiscriminator()->deserialize('{"one":1}', DummyMessageInterface::class, 'json');
|
||||||
$serializer = new Serializer(array(new ObjectNormalizer(null, null, null, null, $discriminatorResolver)), array('json' => new JsonEncoder()));
|
|
||||||
$serializer->deserialize('{"one":1}', DummyMessageInterface::class, 'json');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function metadataFactoryMockForDummyInterface()
|
private function serializerWithClassDiscriminator()
|
||||||
{
|
{
|
||||||
$factoryMock = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock();
|
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
|
||||||
$factoryMock->method('hasMetadataFor')->will($this->returnValueMap(array(
|
|
||||||
array(
|
|
||||||
DummyMessageInterface::class,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
)));
|
|
||||||
|
|
||||||
$factoryMock->method('getMetadataFor')->will($this->returnValueMap(array(
|
return new Serializer(array(new ObjectNormalizer($classMetadataFactory, null, null, null, new ClassDiscriminatorFromClassMetadata($classMetadataFactory))), array('json' => new JsonEncoder()));
|
||||||
array(
|
|
||||||
DummyMessageInterface::class,
|
|
||||||
new ClassMetadata(
|
|
||||||
DummyMessageInterface::class,
|
|
||||||
new ClassDiscriminatorMapping('message-type', array(
|
|
||||||
'one' => DummyMessageNumberOne::class,
|
|
||||||
))
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)));
|
|
||||||
|
|
||||||
return $factoryMock;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user