diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php index 5aff910d62de..c52e9e8382a3 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php @@ -36,6 +36,7 @@ final class ObjectNormalizer extends AbstractObjectNormalizer protected PropertyAccessorInterface $propertyAccessor; protected $propertyInfoExtractor; + private $writeInfoExtractor; private readonly \Closure $objectClassResolver; @@ -51,6 +52,7 @@ public function __construct(?ClassMetadataFactoryInterface $classMetadataFactory $this->objectClassResolver = ($objectClassResolver ?? static fn ($class) => \is_object($class) ? $class::class : $class)(...); $this->propertyInfoExtractor = $propertyInfoExtractor ?: new ReflectionExtractor(); + $this->writeInfoExtractor = new ReflectionExtractor(); } public function getSupportedTypes(?string $format): array @@ -174,8 +176,15 @@ protected function isAllowedAttribute($classOrObject, string $attribute, ?string return $this->propertyInfoExtractor->isReadable($class, $attribute) || $this->hasAttributeAccessorMethod($class, $attribute); } - return $this->propertyInfoExtractor->isWritable($class, $attribute) - || ($writeInfo = $this->propertyInfoExtractor->getWriteInfo($class, $attribute)) && PropertyWriteInfo::TYPE_NONE !== $writeInfo->getType(); + if ($this->propertyInfoExtractor->isWritable($class, $attribute)) { + return true; + } + + if (($writeInfo = $this->writeInfoExtractor->getWriteInfo($class, $attribute)) && PropertyWriteInfo::TYPE_NONE !== $writeInfo->getType()) { + return true; + } + + return false; } private function hasAttributeAccessorMethod(string $class, string $attribute): bool diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php index c9bb6a297939..13c0dcc08d0e 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php @@ -214,8 +214,8 @@ public function testDecodeEmptyData() public function testMultipleEmptyHeaderNamesWithSeparator() { - $this->encoder->decode(',. -,', 'csv'); + $this->assertSame([['', [1 => '']]], $this->encoder->decode(',. +,', 'csv')); } public function testEncodeVariableStructure() diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index 9412cfce8b04..19bbcde2c710 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -269,6 +269,22 @@ public function testConstructorWithObjectDenormalize() $this->assertEquals('bar', $obj->bar); } + public function testConstructorWithObjectDenormalizeUsingPropertyInfoExtractor() + { + $serializer = $this->createMock(ObjectSerializerNormalizer::class); + $normalizer = new ObjectNormalizer(null, null, null, null, null, null, [], new PropertyInfoExtractor()); + $normalizer->setSerializer($serializer); + + $data = new \stdClass(); + $data->foo = 'foo'; + $data->bar = 'bar'; + $data->baz = true; + $data->fooBar = 'foobar'; + $obj = $normalizer->denormalize($data, ObjectConstructorDummy::class, 'any'); + $this->assertEquals('foo', $obj->getFoo()); + $this->assertEquals('bar', $obj->bar); + } + public function testConstructorWithObjectTypeHintDenormalize() { $data = [