Skip to content

Commit 8e3cabe

Browse files
committed
bug #1583 [LiveComponent] Fix collections hydration with serializer (squrious)
This PR was squashed before being merged into the 2.x branch. Discussion ---------- [LiveComponent] Fix collections hydration with serializer | Q | A | |--------------|-----| | Bug fix? | yes | | New feature? | no | | Issues | N/A | | License | MIT | Hello! I encountered issues when trying to hydrate a `LiveProp` as a collection of objects, using the Symfony Serializer. Given `phpdocumentor/reflection-dockblock` is installed in the project, and I have the following component: ```php #[AsLiveComponent] class MyComponent { /** * `@var` MyDto[] */ #[LiveProp(useSerializerForHydration: true)] public array $prop = []; } ``` Then I should be able to hydrate `$prop` as a collection of `MyDto`. However, the `LiveComponentHydrator` doesn't consider the collection type when `useSerializerForHydration` is enabled, and tries to deserialize to `array` type, throwing the following exception: ``` Symfony\Component\Serializer\Exception\NotNormalizableValueException : Could not denormalize object of type "array", no supporting normalizer found. ``` So here is a proposal to fix the issue. Cheers! Commits ------- 7a8bc4f [LiveComponent] Fix collections hydration with serializer
2 parents cae0f0e + 7a8bc4f commit 8e3cabe

File tree

3 files changed

+50
-2
lines changed

3 files changed

+50
-2
lines changed

src/LiveComponent/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 2.17.0
44

55
- Add `modifier` option in `LiveProp` so options can be modified at runtime.
6+
- Fix collections hydration with serializer in LiveComponents
67

78
## 2.16.0
89

src/LiveComponent/src/LiveComponentHydrator.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,22 @@ public function hydrateValue(mixed $value, LivePropMetadata $propMetadata, objec
256256
throw new \LogicException(sprintf('The LiveProp "%s" on component "%s" has "useSerializerForHydration: true", but the given serializer does not implement DenormalizerInterface.', $propMetadata->getName(), $parentObject::class));
257257
}
258258

259-
if (null === $propMetadata->getType()) {
259+
if ($propMetadata->collectionValueType()) {
260+
$builtInType = $propMetadata->collectionValueType()->getBuiltinType();
261+
if (Type::BUILTIN_TYPE_OBJECT === $builtInType) {
262+
$type = $propMetadata->collectionValueType()->getClassName().'[]';
263+
} else {
264+
$type = $builtInType.'[]';
265+
}
266+
} else {
267+
$type = $propMetadata->getType();
268+
}
269+
270+
if (null === $type) {
260271
throw new \LogicException(sprintf('The "%s::%s" object should be hydrated with the Serializer, but no type could be guessed.', $parentObject::class, $propMetadata->getName()));
261272
}
262273

263-
return $this->serializer->denormalize($value, $propMetadata->getType(), 'json', $propMetadata->serializationContext());
274+
return $this->serializer->denormalize($value, $type, 'json', $propMetadata->serializationContext());
264275
}
265276

266277
if ($propMetadata->collectionValueType() && Type::BUILTIN_TYPE_OBJECT === $propMetadata->collectionValueType()->getBuiltinType()) {

src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,42 @@ public function mount()
10311031
;
10321032
}];
10331033

1034+
yield 'Collection: using serializer (de)hydrates correctly' => [function () {
1035+
return HydrationTest::create(new class() {
1036+
/** @var \Symfony\UX\LiveComponent\Tests\Fixtures\Dto\Temperature[] */
1037+
#[LiveProp(useSerializerForHydration: true)]
1038+
public array $temperatures = [];
1039+
1040+
/**
1041+
* @var string[]
1042+
*/
1043+
#[LiveProp(useSerializerForHydration: true)]
1044+
public array $tags = [];
1045+
})
1046+
->mountWith([
1047+
'temperatures' => [
1048+
new Temperature(10, 'C'),
1049+
new Temperature(20, 'C'),
1050+
],
1051+
'tags' => ['foo', 'bar'],
1052+
])
1053+
->assertDehydratesTo([
1054+
'temperatures' => [
1055+
['degrees' => 10, 'uom' => 'C'],
1056+
['degrees' => 20, 'uom' => 'C'],
1057+
],
1058+
'tags' => ['foo', 'bar'],
1059+
])
1060+
->assertObjectAfterHydration(function (object $object) {
1061+
self::assertSame(10, $object->temperatures[0]->degrees);
1062+
self::assertSame('C', $object->temperatures[0]->uom);
1063+
self::assertSame(20, $object->temperatures[1]->degrees);
1064+
self::assertSame('C', $object->temperatures[1]->uom);
1065+
self::assertSame(['foo', 'bar'], $object->tags);
1066+
})
1067+
;
1068+
}];
1069+
10341070
yield 'Updating non-writable path is rejected' => [function () {
10351071
$product = new ProductFixtureEntity();
10361072
$product->name = 'original name';

0 commit comments

Comments
 (0)