Skip to content

Commit 5d6ce1f

Browse files
author
Jan Gantzert
committed
feature symfony#52850 [Serializer] add support for stdclass
1 parent 91588b3 commit 5d6ce1f

File tree

4 files changed

+115
-3
lines changed

4 files changed

+115
-3
lines changed

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ protected function getAttributes(object $object, ?string $format, array $context
270270
array_unshift($attributes, $mapping->getTypeProperty());
271271
}
272272

273-
if ($context['cache_key'] && \stdClass::class !== $class) {
273+
if ($context['cache_key'] && \stdClass::class !== $class && !$object instanceof \stdClass) {
274274
$this->attributesCache[$key] = $attributes;
275275
}
276276

@@ -347,7 +347,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
347347

348348
$attributeContext = $this->getAttributeDenormalizationContext($resolvedClass, $attribute, $context);
349349

350-
if ((false !== $allowedAttributes && !\in_array($attribute, $allowedAttributes, true)) || !$this->isAllowedAttribute($resolvedClass, $attribute, $format, $context)) {
350+
if ((false !== $allowedAttributes && !\in_array($attribute, $allowedAttributes, true)) || !$this->isAllowedAttribute($resolvedClass, $attribute, $format, $context) && !($object instanceOf \stdClass)) {
351351
if (!($context[self::ALLOW_EXTRA_ATTRIBUTES] ?? $this->defaultContext[self::ALLOW_EXTRA_ATTRIBUTES])) {
352352
$extraAttributes[] = $attribute;
353353
}

src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public function getSupportedTypes(?string $format): array
6464

6565
protected function extractAttributes(object $object, ?string $format = null, array $context = []): array
6666
{
67-
if (\stdClass::class === $object::class) {
67+
if ($object instanceof \stdClass) {
6868
return array_keys((array) $object);
6969
}
7070

@@ -141,6 +141,12 @@ protected function getAttributeValue(object $object, string $attribute, ?string
141141

142142
protected function setAttributeValue(object $object, string $attribute, mixed $value, ?string $format = null, array $context = []): void
143143
{
144+
if ($object instanceof \stdClass && !property_exists($object, $attribute)) {
145+
$object->{$attribute} = $value;
146+
147+
return;
148+
}
149+
144150
try {
145151
$this->propertyAccessor->setValue($object, $attribute, $value);
146152
} catch (NoSuchPropertyException) {

src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use PHPUnit\Framework\MockObject\MockObject;
1616
use PHPUnit\Framework\TestCase;
1717
use Symfony\Component\PropertyAccess\Exception\InvalidTypeException;
18+
use Symfony\Component\PropertyAccess\PropertyAccess;
1819
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
1920
use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor;
2021
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
@@ -286,6 +287,100 @@ public function testConstructorWithObjectDenormalizeUsingPropertyInfoExtractor()
286287
$this->assertEquals('bar', $obj->bar);
287288
}
288289

290+
public function testConstructorWithObjectDenormalizeForStdClass()
291+
{
292+
$data = [
293+
'foo' => ['bar' => 'baz'],
294+
'oof' => 'rab',
295+
];
296+
297+
$obj = $this->normalizer->denormalize($data, \stdClass::class, 'any');
298+
299+
$expected = new \stdClass();
300+
$expected->foo = ['bar' => 'baz'];
301+
$expected->oof = 'rab';
302+
303+
self::assertEquals($expected, $obj);
304+
}
305+
306+
public function testConstructorWithObjectDenormalizeForExtendingStdClass()
307+
{
308+
$data = [
309+
'foo' => ['bar' => 'baz'],
310+
'oof' => 'rab',
311+
];
312+
313+
$obj = $this->normalizer->denormalize($data, ObjectDummyThatExtendsStdClass::class, 'any');
314+
315+
$expected = new ObjectDummyThatExtendsStdClass();
316+
$expected->foo = ['bar' => 'baz'];
317+
$expected->oof = 'rab';
318+
319+
self::assertEquals($expected, $obj);
320+
}
321+
322+
public function testNormalizeWithObjectFromStdClass()
323+
{
324+
$propertyAccess = PropertyAccess::createPropertyAccessorBuilder();
325+
$propertyAccess->disableExceptionOnInvalidPropertyPath();
326+
$propertyAccess->disableExceptionOnInvalidIndex();
327+
$this->normalizer = new ObjectNormalizer(null, null, $propertyAccess->getPropertyAccessor(), null, null, null, []);
328+
329+
$o1 = new ObjectDummyThatExtendsStdClass();
330+
$o1->foo = 'f';
331+
$o1->bar = 'b';
332+
333+
$this->assertSame(['foo' => 'f', 'bar' => 'b'], $this->normalizer->normalize($o1));
334+
335+
$o2 = new ObjectDummyThatExtendsStdClass();
336+
$o2->baz = 'baz';
337+
338+
$this->assertSame(['baz' => 'baz'], $this->normalizer->normalize($o2));
339+
}
340+
341+
public function testNormalizeWithObjectFromStdClassAndIdenticalPropertyNameAndValue()
342+
{
343+
$propertyAccess = PropertyAccess::createPropertyAccessorBuilder();
344+
$propertyAccess->disableExceptionOnInvalidPropertyPath();
345+
$propertyAccess->disableExceptionOnInvalidIndex();
346+
$this->normalizer = new ObjectNormalizer(null, null, $propertyAccess->getPropertyAccessor(), null, null, null, []);
347+
348+
$o2 = new ObjectDummyThatExtendsStdClass();
349+
$o2->baz = 'baz';
350+
351+
$this->assertSame(['baz' => 'baz'], $this->normalizer->normalize($o2));
352+
}
353+
354+
public function testNormalizeWithObjectExtendingStdClass()
355+
{
356+
$propertyAccess = PropertyAccess::createPropertyAccessorBuilder();
357+
$propertyAccess->disableExceptionOnInvalidPropertyPath();
358+
$propertyAccess->disableExceptionOnInvalidIndex();
359+
$this->normalizer = new ObjectNormalizer(null, null, $propertyAccess->getPropertyAccessor(), null, null, null, []);
360+
361+
$o2 = new ObjectDummyWithPropertyThatExtendsStdClass();
362+
$o2->baz = 'baz';
363+
$o2->foo = 'bar';
364+
365+
$this->assertSame(['foo' => 'bar', 'baz' => 'baz',], $this->normalizer->normalize($o2));
366+
}
367+
368+
public function testDenormalizeObjectForExtendingStdClass()
369+
{
370+
$data = [
371+
'foo' => 'bar',
372+
'oof' => 'rab',
373+
];
374+
375+
$obj = $this->normalizer->denormalize($data, ObjectDummyWithPropertyThatExtendsStdClass::class, 'any');
376+
377+
$expected = new ObjectDummyWithPropertyThatExtendsStdClass();
378+
$expected->foo = 'bar';
379+
$expected->oof = 'rab';
380+
381+
self::assertEquals($expected, $obj);
382+
}
383+
289384
public function testConstructorWithObjectTypeHintDenormalize()
290385
{
291386
$data = [
@@ -1245,3 +1340,13 @@ class ObjectDummyWithIgnoreAttributeAndPrivateProperty
12451340

12461341
private $private = 'private';
12471342
}
1343+
1344+
class ObjectDummyThatExtendsStdClass extends \stdClass
1345+
{
1346+
}
1347+
1348+
class ObjectDummyWithPropertyThatExtendsStdClass extends \stdClass
1349+
{
1350+
public string $foo;
1351+
}
1352+

src/Symfony/Component/Serializer/Tests/SerializerTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ public function testDeserializeAndSerializeNestedInterfacedObjectsWithTheClassMe
515515
public function testDeserializeAndSerializeNestedAbstractAndInterfacedObjectsWithTheClassMetadataDiscriminator()
516516
{
517517
$example = new DummyMessageNumberThree();
518+
$example->type = 'three';
518519

519520
$serializer = $this->serializerWithClassDiscriminator();
520521

0 commit comments

Comments
 (0)