Skip to content

Commit ee87080

Browse files
Merge branch '4.4'
* 4.4: (53 commits) Fix Twig 1.x compatibility Deprecating templateExists method [Translator] Improve farsi(persian) translations for Form [Validator] Fix Changelog for symfony#31511 [Lock][Console] bump lock requirement in console [Lock] minor: add missing alias for PersistenStoreInterface Improve fa translations Dynamic bundle assets [Lock] rename and deprecate Factory into LockFactory [Debug] Restoring back the state of the Debug component (1st step) Spell "triggering" properly [Lock] Fix tests Added tests to cover the possibility of having scalars as services. fixed CS [Lock] Split \"StoreInterface\" into multiple interfaces with less responsability [VarDumper] Let browsers trigger their own search on double CMD/CTRL + F hit [Validator] Allow to use property paths to get limits in range constraint Fix missing deprecations fixed tests on old PHP versions [FrameworkBundle] Inform the user when save_path will be ignored ...
2 parents 201aa43 + 37d0e32 commit ee87080

8 files changed

+139
-7
lines changed

Extractor/ObjectPropertyListExtractor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ final class ObjectPropertyListExtractor implements ObjectPropertyListExtractorIn
2121
private $propertyListExtractor;
2222
private $objectClassResolver;
2323

24-
public function __construct(PropertyListExtractorInterface $propertyListExtractor, ?callable $objectClassResolver = null)
24+
public function __construct(PropertyListExtractorInterface $propertyListExtractor, callable $objectClassResolver = null)
2525
{
2626
$this->propertyListExtractor = $propertyListExtractor;
2727
$this->objectClassResolver = $objectClassResolver;

Normalizer/AbstractObjectNormalizer.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,13 +311,14 @@ public function denormalize($data, $class, string $format = null, array $context
311311

312312
$reflectionClass = new \ReflectionClass($class);
313313
$object = $this->instantiateObject($normalizedData, $class, $context, $reflectionClass, $allowedAttributes, $format);
314+
$resolvedClass = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object);
314315

315316
foreach ($normalizedData as $attribute => $value) {
316317
if ($this->nameConverter) {
317-
$attribute = $this->nameConverter->denormalize($attribute, $class, $format, $context);
318+
$attribute = $this->nameConverter->denormalize($attribute, $resolvedClass, $format, $context);
318319
}
319320

320-
if ((false !== $allowedAttributes && !\in_array($attribute, $allowedAttributes)) || !$this->isAllowedAttribute($class, $attribute, $format, $context)) {
321+
if ((false !== $allowedAttributes && !\in_array($attribute, $allowedAttributes)) || !$this->isAllowedAttribute($resolvedClass, $attribute, $format, $context)) {
321322
if (!($context[self::ALLOW_EXTRA_ATTRIBUTES] ?? $this->defaultContext[self::ALLOW_EXTRA_ATTRIBUTES])) {
322323
$extraAttributes[] = $attribute;
323324
}
@@ -332,7 +333,7 @@ public function denormalize($data, $class, string $format = null, array $context
332333
}
333334
}
334335

335-
$value = $this->validateAndDenormalize($class, $attribute, $value, $format, $context);
336+
$value = $this->validateAndDenormalize($resolvedClass, $attribute, $value, $format, $context);
336337
try {
337338
$this->setAttributeValue($object, $attribute, $value, $format, $context);
338339
} catch (InvalidArgumentException $e) {

Tests/Fixtures/AbstractDummyFirstChild.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,23 @@ class AbstractDummyFirstChild extends AbstractDummy
1515
{
1616
public $bar;
1717

18+
/** @var DummyFirstChildQuux|null */
19+
public $quux;
20+
1821
public function __construct($foo = null, $bar = null)
1922
{
2023
parent::__construct($foo);
2124

2225
$this->bar = $bar;
2326
}
27+
28+
public function getQuux(): ?DummyFirstChildQuux
29+
{
30+
return $this->quux;
31+
}
32+
33+
public function setQuux(DummyFirstChildQuux $quux): void
34+
{
35+
$this->quux = $quux;
36+
}
2437
}

Tests/Fixtures/AbstractDummySecondChild.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,23 @@ class AbstractDummySecondChild extends AbstractDummy
1515
{
1616
public $baz;
1717

18+
/** @var DummySecondChildQuux|null */
19+
public $quux;
20+
1821
public function __construct($foo = null, $baz = null)
1922
{
2023
parent::__construct($foo);
2124

2225
$this->baz = $baz;
2326
}
27+
28+
public function getQuux(): ?DummySecondChildQuux
29+
{
30+
return $this->quux;
31+
}
32+
33+
public function setQuux(DummySecondChildQuux $quux): void
34+
{
35+
$this->quux = $quux;
36+
}
2437
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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 DummyFirstChildQuux
15+
{
16+
/**
17+
* @var string
18+
*/
19+
private $value;
20+
21+
public function __construct(string $value)
22+
{
23+
$this->value = $value;
24+
}
25+
26+
public function getValue(): string
27+
{
28+
return $this->value;
29+
}
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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 DummySecondChildQuux
15+
{
16+
/**
17+
* @var string
18+
*/
19+
private $value;
20+
21+
public function __construct(string $value)
22+
{
23+
$this->value = $value;
24+
}
25+
26+
public function getValue(): string
27+
{
28+
return $this->value;
29+
}
30+
}

Tests/Normalizer/AbstractObjectNormalizerTest.php

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,22 @@
1616
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
1717
use Symfony\Component\PropertyInfo\Type;
1818
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
19+
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
20+
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
21+
use Symfony\Component\Serializer\Mapping\ClassMetadata;
1922
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
23+
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
2024
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
2125
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
2226
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
2327
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
28+
use Symfony\Component\Serializer\Serializer;
2429
use Symfony\Component\Serializer\SerializerAwareInterface;
2530
use Symfony\Component\Serializer\SerializerInterface;
31+
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummy;
32+
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummyFirstChild;
33+
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummySecondChild;
34+
use Symfony\Component\Serializer\Tests\Fixtures\DummySecondChildQuux;
2635

2736
class AbstractObjectNormalizerTest extends TestCase
2837
{
@@ -147,6 +156,39 @@ private function getDenormalizerForDummyCollection()
147156
return $denormalizer;
148157
}
149158

159+
public function testDenormalizeWithDiscriminatorMapUsesCorrectClassname()
160+
{
161+
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
162+
$loaderMock = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock();
163+
$loaderMock->method('hasMetadataFor')->willReturnMap([
164+
[
165+
AbstractDummy::class,
166+
true,
167+
],
168+
]);
169+
170+
$loaderMock->method('getMetadataFor')->willReturnMap([
171+
[
172+
AbstractDummy::class,
173+
new ClassMetadata(
174+
AbstractDummy::class,
175+
new ClassDiscriminatorMapping('type', [
176+
'first' => AbstractDummyFirstChild::class,
177+
'second' => AbstractDummySecondChild::class,
178+
])
179+
),
180+
],
181+
]);
182+
183+
$discriminatorResolver = new ClassDiscriminatorFromClassMetadata($loaderMock);
184+
$normalizer = new AbstractObjectNormalizerDummy($factory, null, new PhpDocExtractor(), $discriminatorResolver);
185+
$serializer = new Serializer([$normalizer]);
186+
$normalizer->setSerializer($serializer);
187+
$normalizedData = $normalizer->denormalize(['foo' => 'foo', 'baz' => 'baz', 'quux' => ['value' => 'quux'], 'type' => 'second'], AbstractDummy::class);
188+
189+
$this->assertInstanceOf(DummySecondChildQuux::class, $normalizedData->quux);
190+
}
191+
150192
/**
151193
* Test that additional attributes throw an exception if no metadata factory is specified.
152194
*
@@ -180,7 +222,7 @@ protected function setAttributeValue($object, $attribute, $value, $format = null
180222

181223
protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = [])
182224
{
183-
return \in_array($attribute, ['foo', 'baz']);
225+
return \in_array($attribute, ['foo', 'baz', 'quux', 'value']);
184226
}
185227

186228
public function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, string $format = null)

Tests/SerializerTest.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Doctrine\Common\Annotations\AnnotationReader;
1515
use PHPUnit\Framework\TestCase;
16+
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
1617
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
1718
use Symfony\Component\Serializer\Encoder\JsonEncoder;
1819
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
@@ -34,6 +35,7 @@
3435
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummy;
3536
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummyFirstChild;
3637
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummySecondChild;
38+
use Symfony\Component\Serializer\Tests\Fixtures\DummyFirstChildQuux;
3739
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface;
3840
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne;
3941
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo;
@@ -382,6 +384,7 @@ public function testDeserializeObjectConstructorWithObjectTypeHint()
382384
public function testDeserializeAndSerializeAbstractObjectsWithTheClassMetadataDiscriminatorResolver()
383385
{
384386
$example = new AbstractDummyFirstChild('foo-value', 'bar-value');
387+
$example->setQuux(new DummyFirstChildQuux('quux'));
385388

386389
$loaderMock = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock();
387390
$loaderMock->method('hasMetadataFor')->willReturnMap([
@@ -405,9 +408,9 @@ public function testDeserializeAndSerializeAbstractObjectsWithTheClassMetadataDi
405408
]);
406409

407410
$discriminatorResolver = new ClassDiscriminatorFromClassMetadata($loaderMock);
408-
$serializer = new Serializer([new ObjectNormalizer(null, null, null, null, $discriminatorResolver)], ['json' => new JsonEncoder()]);
411+
$serializer = new Serializer([new ObjectNormalizer(null, null, null, new PhpDocExtractor(), $discriminatorResolver)], ['json' => new JsonEncoder()]);
409412

410-
$jsonData = '{"type":"first","bar":"bar-value","foo":"foo-value"}';
413+
$jsonData = '{"type":"first","quux":{"value":"quux"},"bar":"bar-value","foo":"foo-value"}';
411414

412415
$deserialized = $serializer->deserialize($jsonData, AbstractDummy::class, 'json');
413416
$this->assertEquals($example, $deserialized);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy