Supports nested "abstract" object while serializing and de-serializing
This commit is contained in:
parent
10f7dcc5dc
commit
ec4b04b2d5
@ -294,7 +294,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
|
||||
*/
|
||||
private function validateAndDenormalize(string $currentClass, string $attribute, $data, ?string $format, array $context)
|
||||
{
|
||||
if (null === $this->propertyTypeExtractor || null === $types = $this->propertyTypeExtractor->getTypes($currentClass, $attribute)) {
|
||||
if (null === $types = $this->getTypes($currentClass, $attribute)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
@ -357,6 +357,36 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
|
||||
throw new NotNormalizableValueException(sprintf('The type of the "%s" attribute for class "%s" must be one of "%s" ("%s" given).', $attribute, $currentClass, implode('", "', array_keys($expectedTypes)), gettype($data)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Type[]|null
|
||||
*/
|
||||
private function getTypes(string $currentClass, string $attribute)
|
||||
{
|
||||
if (null === $this->propertyTypeExtractor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null !== $types = $this->propertyTypeExtractor->getTypes($currentClass, $attribute)) {
|
||||
return $types;
|
||||
}
|
||||
|
||||
if (null !== $this->classDiscriminatorResolver && null !== $discriminatorMapping = $this->classDiscriminatorResolver->getMappingForClass($currentClass)) {
|
||||
if ($discriminatorMapping->getTypeProperty() === $attribute) {
|
||||
return array(
|
||||
new Type(Type::BUILTIN_TYPE_STRING),
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($discriminatorMapping->getTypesMapping() as $mappedClass) {
|
||||
if (null !== $types = $this->propertyTypeExtractor->getTypes($mappedClass, $attribute)) {
|
||||
return $types;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an attribute and apply the name converter if necessary.
|
||||
*
|
||||
|
@ -22,4 +22,19 @@ class DummyMessageNumberTwo implements DummyMessageInterface
|
||||
* @Groups({"two"})
|
||||
*/
|
||||
public $three;
|
||||
|
||||
/**
|
||||
* @var DummyMessageNumberOne
|
||||
*/
|
||||
private $nested;
|
||||
|
||||
public function setNested(DummyMessageNumberOne $nested)
|
||||
{
|
||||
$this->nested = $nested;
|
||||
}
|
||||
|
||||
public function getNested(): DummyMessageNumberOne
|
||||
{
|
||||
return $this->nested;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Serializer\Tests;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
|
||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
|
||||
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
|
||||
use Symfony\Component\Serializer\Mapping\ClassMetadata;
|
||||
@ -35,6 +36,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummyFirstChild;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummySecondChild;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy;
|
||||
use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy;
|
||||
use Symfony\Component\Serializer\Tests\Normalizer\TestNormalizer;
|
||||
@ -430,6 +432,22 @@ class SerializerTest extends TestCase
|
||||
$this->assertEquals('{"two":2,"type":"one"}', $serialized);
|
||||
}
|
||||
|
||||
public function testDeserializeAndSerializeNestedInterfacedObjectsWithTheClassMetadataDiscriminator()
|
||||
{
|
||||
$nested = new DummyMessageNumberOne();
|
||||
$nested->one = 'foo';
|
||||
|
||||
$example = new DummyMessageNumberTwo();
|
||||
$example->setNested($nested);
|
||||
|
||||
$serializer = $this->serializerWithClassDiscriminator();
|
||||
|
||||
$serialized = $serializer->serialize($example, 'json');
|
||||
$deserialized = $serializer->deserialize($serialized, DummyMessageInterface::class, 'json');
|
||||
|
||||
$this->assertEquals($example, $deserialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Serializer\Exception\RuntimeException
|
||||
* @expectedExceptionMessage The type "second" has no mapped class for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface"
|
||||
@ -452,7 +470,7 @@ class SerializerTest extends TestCase
|
||||
{
|
||||
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
|
||||
|
||||
return new Serializer(array(new ObjectNormalizer($classMetadataFactory, null, null, null, new ClassDiscriminatorFromClassMetadata($classMetadataFactory))), array('json' => new JsonEncoder()));
|
||||
return new Serializer(array(new ObjectNormalizer($classMetadataFactory, null, null, new ReflectionExtractor(), new ClassDiscriminatorFromClassMetadata($classMetadataFactory))), array('json' => new JsonEncoder()));
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user