Symfony version(s) affected
7.4.5
Description
See this discussion for more details:
#63171
We cannot denormalize with magic __set method when properties do not exist
The code worked correctly until symfony/serializer 7.3.3
The bug that probably introduced in this PR #61571
Code:
abstract class TopicDto
{
private string $topicName;
private string|null $topicMessageKey;
private int $topicMessageOffset;
final public function setTopicInfo(string $name, string|null $key, int $offset): void
{
$this->topicName = $name;
$this->topicMessageKey = $key;
$this->topicMessageOffset = $offset;
}
public function getTopicName(): string
{
return $this->topicName;
}
public function getTopicMessageKey(): string|null
{
return $this->topicMessageKey;
}
public function getTopicMessageOffset(): int
{
return $this->topicMessageOffset;
}
}
class GenericDto extends TopicDto
{
public array $params = [];
public function __set(string $name, mixed $value): void
{
$this->params[$name] = $value;
}
public function __get(string $name)
{
return $this->params[$name] ?? null;
}
public function __isset(string $name): bool
{
return true;
}
public function getData(): array
{
return array_merge(
[
'topic' => $this->getTopicName(),
'topicMessageKey' => $this->getTopicMessageKey(),
'topicMessageOffset' => $this->getTopicMessageOffset(),
],
$this->params,
);
}
}
$metadataFactory = new ClassMetadataFactory(new AttributeLoader());
$serializer = new Serializer(
[
new ArrayDenormalizer(),
new DateTimeNormalizer(
[
DateTimeNormalizer::FORMAT_KEY => 'Y-m-d\TH:i:s',
DateTimeNormalizer::TIMEZONE_KEY => 'Europe/Zurich', // date_default_timezone_get(),
]
),
new ObjectNormalizer(
$metadataFactory,
new MetadataAwareNameConverter($metadataFactory),
PropertyAccess::createPropertyAccessor(), //PropertyAccess::createPropertyAccessorBuilder()->enableMagicSet()->getPropertyAccessor(),
new PropertyInfoExtractor(
[
new ReflectionExtractor(),
],
[
new PhpDocExtractor(),
new ReflectionExtractor(),
],
),
new ClassDiscriminatorFromClassMetadata($metadataFactory),
defaultContext: [AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => true]
),
],
);
$payload = ['param1' => 'test'];
$dto = $serializer->denormalize($payload, GenericDto::class, context: [AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => true]);
dd($dto);
Result:
Expected:
How to reproduce
https://github.com/alexandre-le-borgne/bug-symfony-denormalize-magic-properties
symfony serve
browse the index
Possible Solution
In Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php
Replace
return self::$isWritableCache[$class.$attribute] ??= str_contains($attribute, '.')
|| $this->propertyInfoExtractor->isWritable($class, $attribute)
|| !\in_array($this->writeInfoExtractor->getWriteInfo($class, $attribute)?->getType(), [null, PropertyWriteInfo::TYPE_NONE, PropertyWriteInfo::TYPE_PROPERTY], true);
by
return self::$isWritableCache[$class.$attribute] ??= str_contains($attribute, '.')
|| $this->propertyInfoExtractor->isWritable($class, $attribute)
|| !\in_array($this->writeInfoExtractor->getWriteInfo($class, $attribute)?->getType(), [null, PropertyWriteInfo::TYPE_NONE], true);
Additional Context
No response
Symfony version(s) affected
7.4.5
Description
See this discussion for more details:
#63171
We cannot denormalize with magic __set method when properties do not exist
The code worked correctly until symfony/serializer 7.3.3
The bug that probably introduced in this PR #61571
Code:
Result:
Expected:
How to reproduce
https://github.com/alexandre-le-borgne/bug-symfony-denormalize-magic-properties
symfony servebrowse the index
Possible Solution
In Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php
Replace
by
Additional Context
No response