Skip to content

Commit 5d03a74

Browse files
committed
Merge branch '7.0' into 7.1
* 7.0: (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 9a3acd7 + 1459271 commit 5d03a74

File tree

6 files changed

+96
-6
lines changed

6 files changed

+96
-6
lines changed

Normalizer/AbstractObjectNormalizer.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,22 @@ private function validateAndDenormalizeLegacy(array $types, string $currentClass
570570
return $data;
571571
}
572572

573-
if (('is_'.$builtinType)($data)) {
574-
return $data;
573+
switch ($builtinType) {
574+
case Type::BUILTIN_TYPE_ARRAY:
575+
case Type::BUILTIN_TYPE_BOOL:
576+
case Type::BUILTIN_TYPE_CALLABLE:
577+
case Type::BUILTIN_TYPE_FLOAT:
578+
case Type::BUILTIN_TYPE_INT:
579+
case Type::BUILTIN_TYPE_ITERABLE:
580+
case Type::BUILTIN_TYPE_NULL:
581+
case Type::BUILTIN_TYPE_OBJECT:
582+
case Type::BUILTIN_TYPE_RESOURCE:
583+
case Type::BUILTIN_TYPE_STRING:
584+
if (('is_'.$builtinType)($data)) {
585+
return $data;
586+
}
587+
588+
break;
575589
}
576590
} catch (NotNormalizableValueException|InvalidArgumentException $e) {
577591
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: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,26 @@ public function testDenormalizeMixedProperty()
11751175

11761176
$this->assertEquals($expected, $normalizer->denormalize(['foo' => 'bar'], MixedPropertyDummy::class));
11771177
}
1178+
1179+
/**
1180+
* @dataProvider provideBooleanTypesData
1181+
*/
1182+
public function testDenormalizeBooleanTypesWithNotMatchingData(array $data, string $type)
1183+
{
1184+
$normalizer = new AbstractObjectNormalizerWithMetadataAndPropertyTypeExtractors();
1185+
1186+
$this->expectException(NotNormalizableValueException::class);
1187+
1188+
$normalizer->denormalize($data, $type);
1189+
}
1190+
1191+
public function provideBooleanTypesData()
1192+
{
1193+
return [
1194+
[['foo' => true], FalsePropertyDummy::class],
1195+
[['foo' => false], TruePropertyDummy::class],
1196+
];
1197+
}
11781198
}
11791199

11801200
class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer
@@ -1448,6 +1468,18 @@ class XmlScalarDummy
14481468
public $value;
14491469
}
14501470

1471+
class FalsePropertyDummy
1472+
{
1473+
/** @var false */
1474+
public $foo;
1475+
}
1476+
1477+
class TruePropertyDummy
1478+
{
1479+
/** @var true */
1480+
public $foo;
1481+
}
1482+
14511483
class SerializerCollectionDummy implements SerializerInterface, DenormalizerInterface
14521484
{
14531485
private array $normalizers;

Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 35 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\AttributeLoader;
30+
use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
3031
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;
3132
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
3233
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
@@ -918,6 +919,40 @@ public function testDenormalizeWithIgnoreAttributeAndPrivateProperties()
918919

919920
$this->assertEquals($expected, $obj);
920921
}
922+
923+
public function testNormalizeWithPropertyPath()
924+
{
925+
$classMetadataFactory = new ClassMetadataFactory(new YamlFileLoader(__DIR__.'/../Fixtures/property-path-mapping.yaml'));
926+
$normalizer = new ObjectNormalizer($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory));
927+
928+
$dummyInner = new ObjectInner();
929+
$dummyInner->foo = 'foo';
930+
$dummy = new ObjectOuter();
931+
$dummy->setInner($dummyInner);
932+
933+
$this->assertSame(['inner_foo' => 'foo'], $normalizer->normalize($dummy, 'json', ['groups' => 'read']));
934+
}
935+
936+
public function testDenormalizeWithPropertyPath()
937+
{
938+
$classMetadataFactory = new ClassMetadataFactory(new YamlFileLoader(__DIR__.'/../Fixtures/property-path-mapping.yaml'));
939+
$normalizer = new ObjectNormalizer($classMetadataFactory, new MetadataAwareNameConverter($classMetadataFactory));
940+
941+
$dummy = new ObjectOuter();
942+
$dummy->setInner(new ObjectInner());
943+
944+
$obj = $normalizer->denormalize(['inner_foo' => 'foo'], ObjectOuter::class, 'json', [
945+
'object_to_populate' => $dummy,
946+
'groups' => 'read',
947+
]);
948+
949+
$expectedInner = new ObjectInner();
950+
$expectedInner->foo = 'foo';
951+
$expected = new ObjectOuter();
952+
$expected->setInner($expectedInner);
953+
954+
$this->assertEquals($expected, $obj);
955+
}
921956
}
922957

923958
class ProxyObjectDummy extends ObjectDummy

0 commit comments

Comments
 (0)