8000 [Serializer] Fix discriminator map not working with `AbstractNormaliz… · symfony/symfony@ce08608 · GitHub
[go: up one dir, main page]

Skip to content

Commit ce08608

Browse files
committed
[Serializer] Fix discriminator map not working with AbstractNormalizer::OBJECT_TO_POPULATE
1 parent 33357e6 commit ce08608

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,12 @@ private function getAttributeMetadata($objectOrClass, string $attribute): ?Attri
263263
*/
264264
protected function instantiateObject(array &$data, string $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, string $format = null)
265265
{
266+
if (null !== $object = $this->extractObjectToPopulate($class, $context, self::OBJECT_TO_POPULATE)) {
267+
unset($context[self::OBJECT_TO_POPULATE]);
268+
269+
return $object;
270+
}
271+
266272
if ($this->classDiscriminatorResolver && $mapping = $this->classDiscriminatorResolver->getMappingForClass($class)) {
267273
if (!isset($data[$mapping->getTypeProperty()])) {
268274
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Type property "%s" not found for the abstract object "%s".', $mapping->getTypeProperty(), $class), null, ['string'], isset($context['deserialization_path']) ? $context['deserialization_path'].'.'.$mapping->getTypeProperty() : $mapping->getTypeProperty(), false);

src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
2828
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
2929
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
30+
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
3031
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
3132
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
3233
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
@@ -36,6 +37,7 @@
3637
use Symfony\Component\Serializer\Tests\Fixtures\Annotations\AbstractDummy;
3738
use Symfony\Component\Serializer\Tests\Fixtures\Annotations\AbstractDummyFirstChild;
3839
use Symfony\Component\Serializer\Tests\Fixtures\Annotations\AbstractDummySecondChild;
40+
use Symfony\Component\Serializer\Tests\Fixtures\DummyFirstChildQuux;
3941
use Symfony\Component\Serializer\Tests\Fixtures\DummySecondChildQuux;
4042

4143
class AbstractObjectNormalizerTest extends TestCase
@@ -252,6 +254,61 @@ public function hasMetadataFor($value): bool
252254
$this->assertInstanceOf(DummySecondChildQuux::class, $normalizedData->quux);
253255
}
254256

257+
public function testDenormalizeWithDiscriminatorMapAndObjectToPopulateUsesCorrectClassname()
258+
{
259+
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
260+
261+
$loaderMock = new class() implements ClassMetadataFactoryInterface {
262+
public function getMetadataFor($value): ClassMetadataInterface
263+
{
264+
if (AbstractDummy::class === $value) {
265+
return new ClassMetadata(
266+
AbstractDummy::class,
267+
new ClassDiscriminatorMapping('type', [
268+
'first' => AbstractDummyFirstChild::class,
269+
'second' => AbstractDummySecondChild::class,
270+
])
271+
);
272+
}
273+
274+
throw new InvalidArgumentException();
275+
}
276+
277+
public function hasMetadataFor($value): bool
278+
{
279+
return AbstractDummy::class === $value;
280+
}
281+
};
282+
283+
$discriminatorResolver = new ClassDiscriminatorFromClassMetadata($loaderMock);
284+
$normalizer = new AbstractObjectNormalizerDummy($factory, null, new PhpDocExtractor(), $discriminatorResolver);
285+
$serializer = new Serializer([$normalizer]);
286+
$normalizer->setSerializer($serializer);
287+
288+
$data = [
289+
'foo' => 'foo',
290+
'quux' => ['value' => 'quux'],
291+
];
292+
293+
$normalizedData1 = $normalizer->denormalize($data + ['bar' => 'bar'], AbstractDummy::class, 'any', [
294+
AbstractNormalizer::OBJECT_TO_POPULATE => new AbstractDummyFirstChild('notfoo', 'notbar'),
295+
]);
296+
$this->assertInstanceOf(AbstractDummyFirstChild::class, $normalizedData1);
297+
$this->assertSame('foo', $normalizedData1->foo);
298+
$this->assertSame('notbar', $normalizedData1->bar);
299+
$this->assertInstanceOf(DummyFirstChildQuux::class, $normalizedData1->quux);
300+
$this->assertSame('quux', $normalizedData1->quux->getValue());
301+
302+
$normalizedData2 = $normalizer->denormalize($data + ['baz' => 'baz'], AbstractDummy::class, 'any', [
303+
AbstractNormalizer::OBJECT_TO_POPULATE => new AbstractDummySecondChild('notfoo', 'notbaz'),
304+
]);
305+
$this->assertInstanceOf(AbstractDummySecondChild::class, $normalizedData2);
306+
$this->assertSame('foo', $normalizedData2->foo);
307+
$this->assertSame('baz', $normalizedData2->baz);
308+
$this->assertInstanceOf(DummySecondChildQuux::class, $normalizedData2->quux);
309+
$this->assertSame('quux', $normalizedData2->quux->getValue());
310+
}
311+
255312
public function testDenormalizeWithNestedDiscriminatorMap()
256313
{
257314
$classDiscriminatorResolver = new class() implements ClassDiscriminatorResolverInterface {

0 commit comments

Comments
 (0)
0