Skip to content

Commit 1459271

Browse files
committed
Merge branch '6.4' into 7.0
* 6.4: (29 commits) fix tests add missing method fix merge fix test fix merge fix test change test to use a real ObjectManager [Mailer] Document the usage of custom headers in Infobip bridge [SecurityBundle] Add `provider` XML attribute to the authenticators it’s missing from [DoctrineBridge] Test reset with a true manager Sync php-cs-fixer config file with 7.2 [HttpClient] Fix parsing SSE [Notifier] Fix thread key in GoogleChat bridge [HttpKernel][Security] Fix accessing session for stateless request [Serializer] Fix `ObjectNormalizer` with property path test handling of special "value" constraint option [PhpUnitBridge] Add missing import [FrameworkBundle] Fix setting default context for certain normalizers [57251] Missing translations for Romanian (ro) [ErrorHandler] Fix rendered exception code highlighting on PHP 8.3 ...
2 parents 267299e + 240a7bb commit 1459271

File tree

6 files changed

+126
-6
lines changed

6 files changed

+126
-6
lines changed

Normalizer/AbstractObjectNormalizer.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -552,8 +552,22 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
552552
return $data;
553553
}
554554

555-
if (('is_'.$builtinType)($data)) {
556-
return $data;
555+
switch ($builtinType) {
556+
case Type::BUILTIN_TYPE_ARRAY:
557+
case Type::BUILTIN_TYPE_BOOL:
558+
case Type::BUILTIN_TYPE_CALLABLE:
559+
case Type::BUILTIN_TYPE_FLOAT:
560+
case Type::BUILTIN_TYPE_INT:
561+
case Type::BUILTIN_TYPE_ITERABLE:
562+
case Type::BUILTIN_TYPE_NULL:
563+
case Type::BUILTIN_TYPE_OBJECT:
564+
case Type::BUILTIN_TYPE_RESOURCE:
565+
case Type::BUILTIN_TYPE_STRING:
566+
if (('is_'.$builtinType)($data)) {
567+
return $data;
568+
}
569+
570+
break;
557571
}
558572
} catch (NotNormalizableValueException|InvalidArgumentException $e) {
559573
if (!$isUnionType && !$isNullable) {

Normalizer/ObjectNormalizer.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,15 +177,19 @@ protected function isAllowedAttribute($classOrObject, string $attribute, ?string
177177

178178
if ($context['_read_attributes'] ?? true) {
179179
if (!isset(self::$isReadableCache[$class.$attribute])) {
180-
self::$isReadableCache[$class.$attribute] = $this->propertyInfoExtractor->isReadable($class, $attribute) || $this->hasAttributeAccessorMethod($class, $attribute);
180+
self::$isReadableCache[$class.$attribute] = (\is_object($classOrObject) && $this->propertyAccessor->isReadable($classOrObject, $attribute)) || $this->propertyInfoExtractor->isReadable($class, $attribute) || $this->hasAttributeAccessorMethod($class, $attribute);
181181
}
182182

183183
return self::$isReadableCache[$class.$attribute];
184184
}
185185

186186
if (!isset(self::$isWritableCache[$class.$attribute])) {
187-
self::$isWritableCache[$class.$attribute] = $this->propertyInfoExtractor->isWritable($class, $attribute)
188-
|| (($writeInfo = $this->writeInfoExtractor->getWriteInfo($class, $attribute)) && PropertyWriteInfo::TYPE_NONE !== $writeInfo->getType());
187+
if (str_contains($attribute, '.')) {
188+
self::$isWritableCache[$class.$attribute] = true;
189+
} else {
190+
self::$isWritableCache[$class.$attribute] = $this->propertyInfoExtractor->isWritable($class, $attribute)
191+
|| (($writeInfo = $this->writeInfoExtractor->getWriteInfo($class, $attribute)) && PropertyWriteInfo::TYPE_NONE !== $writeInfo->getType());
192+
}
189193
}
190194

191195
return self::$isWritableCache[$class.$attribute];

Tests/DeserializeNestedArrayOfObjectsTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ class ZooWithKeyTypes
156156
public $animalsString = [];
157157
/** @var array<int|string, Animal> */
158158
public $animalsUnion = [];
159-
/** @var \stdClass<Animal> */
159+
/** @var \Traversable<Animal> */
160160
public $animalsGenerics = [];
161161
}
162162

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Symfony\Component\Serializer\Tests\Normalizer\ObjectOuter:
2+
attributes:
3+
inner.foo:
4+
serialized_name: inner_foo
5+
groups: [ 'read' ]

Tests/Normalizer/AbstractObjectNormalizerTest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,26 @@ public function testNormalizationWithMaxDepthOnStdclassObjectDoesNotThrowWarning
10761076

10771077
$this->assertSame(['string' => 'yes'], $normalized);
10781078
}
1079+
1080+
/**
1081+
* @dataProvider provideBooleanTypesData
1082+
*/
1083+
public function testDenormalizeBooleanTypesWithNotMatchingData(array $data, string $type)
1084+
{
1085+
$normalizer = new AbstractObjectNormalizerWithMetadataAndPropertyTypeExtractors();
1086+
1087+
$this->expectException(NotNormalizableValueException::class);
1088+
1089+
$normalizer->denormalize($data, $type);
1090+
}
1091+
1092+
public function provideBooleanTypesData()
1093+
{
1094+
return [
1095+
[['foo' => true], FalsePropertyDummy::class],
1096+
[['foo' => false], TruePropertyDummy::class],
1097+
];
1098+
}
10791099
}
10801100

10811101
class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer
@@ -1344,6 +1364,18 @@ class XmlScalarDummy
13441364
public $value;
13451365
}
13461366

1367+
class FalsePropertyDummy
1368+
{
1369+
/** @var false */
1370+
public $foo;
1371+
}
1372+
1373+
class TruePropertyDummy
1374+
{
1375+
/** @var true */
1376+
public $foo;
1377+
}
1378+
13471379
class SerializerCollectionDummy implements SerializerInterface, DenormalizerInterface
13481380
{
13491381
private array $normalizers;
@@ -1487,3 +1519,33 @@ public function __construct(
14871519
) {
14881520
}
14891521
}
1522+
1523+
class AbstractObjectNormalizerWithMetadataAndPropertyTypeExtractors extends AbstractObjectNormalizer
1524+
{
1525+
public function __construct()
1526+
{
1527+
parent::__construct(new ClassMetadataFactory(new AttributeLoader()), null, new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]));
1528+
}
1529+
1530+
public function getSupportedTypes(?string $format): array
1531+
{
1532+
return ['*' => false];
1533+
}
1534+
1535+
protected function extractAttributes(object $object, ?string $format = null, array $context = []): array
1536+
{
1537+
return [];
1538+
}
1539+
1540+
protected function getAttributeValue(object $object, string $attribute, ?string $format = null, array $context = []): mixed
1541+
{
1542+
return null;
1543+
}
1544+
1545+
protected function setAttributeValue(object $object, string $attribute, $value, ?string $format = null, array $context = []): void
1546+
{
1547+
if (property_exists($object, $attribute)) {
1548+
$object->$attribute = $value;
1549+
}
1550+
}
1551+
}

Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
2626
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
2727
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
28+
use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
2829
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;
2930
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
3031
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
@@ -887,6 +888,40 @@ public function testDenormalizeWithIgnoreAttributeAndPrivateProperties()
887888

888889
$this->assertEquals($expected, $obj);
889890
}
891+
892+
public function testNormalizeWithPropertyPath()
893+
{
894+
$classMetadataFactory = new ClassMetadataFactory(new YamlFileLoader(__DIR__.'/../Fixtures/property-path-mapping.yaml'));
895+
$normalizer = new ObjectNormalizer($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory));
896+
897+
$dummyInner = new ObjectInner();
898+
$dummyInner->foo = 'foo';
899+
$dummy = new ObjectOuter();
900+
$dummy->setInner($dummyInner);
901+
902+
$this->assertSame(['inner_foo' => 'foo'], $normalizer->normalize($dummy, 'json', ['groups' => 'read']));
903+
}
904+
905+
public function testDenormalizeWithPropertyPath()
906+
{
907+
$classMetadataFactory = new ClassMetadataFactory(new YamlFileLoader(__DIR__.'/../Fixtures/property-path-mapping.yaml'));
908+
$normalizer = new ObjectNormalizer($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory));
909+
910+
$dummy = new ObjectOuter();
911+
$dummy->setInner(new ObjectInner());
912+
913+
$obj = $normalizer->denormalize(['inner_foo' => 'foo'], ObjectOuter::class, 'json', [
914+
'object_to_populate' => $dummy,
915+
'groups' => 'read',
916+
]);
917+
918+
$expectedInner = new ObjectInner();
919+
$expectedInner->foo = 'foo';
920+
$expected = new ObjectOuter();
921+
$expected->setInner($expectedInner);
922+
923+
$this->assertEquals($expected, $obj);
924+
}
890925
}
891926

892927
class ProxyObjectDummy extends ObjectDummy

0 commit comments

Comments
 (0)