Skip to content

Commit 9426209

Browse files
committed
bug #2730 [LiveComponent] fix: LiveComponentHydrator::hydrateValue() cannot hydrate null values (nikophil)
This PR was merged into the 2.x branch. Discussion ---------- [LiveComponent] fix: `LiveComponentHydrator::hydrateValue()` cannot hydrate null values Hello, such live prop cannot currently be hydrated by `LiveComponentHydrator::hydrateValue()` because nullability is not handled and the serializer is asked to deserialize `null` into `MyDTO` ```php #[LiveProp(writable: true, useSerializerForHydration: true)] public ?MyDTO $myDTO = null; ``` this PR fixes this problem NB: all the failures in the CI are unrelated to this fix Commits ------- 8d88ccb fix: allow LiveComponentHydrator::hydrateValue() to hydrate null values
2 parents e8a2f04 + 8d88ccb commit 9426209

File tree

3 files changed

+35
-0
lines changed

3 files changed

+35
-0
lines changed

src/LiveComponent/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Add support for [Symfony UID](https://symfony.com/doc/current/components/uid.html) hydration/dehydration
66
- `ComponentWithFormTrait` now correctly checks for a `TranslatableInterface` placeholder for `<select>` elements
7+
- Fix `LiveComponentHydrator::hydrateValue()` to hydrate null values
78

89
## 2.23.0
910

src/LiveComponent/src/LiveComponentHydrator.php

+4
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ public function hydrateValue(mixed $value, LivePropMetadata $propMetadata, objec
282282
throw new \LogicException(\sprintf('The "%s::%s" object should be hydrated with the Serializer, but no type could be guessed.', $parentObject::class, $propMetadata->getName()));
283283
}
284284

285+
if (null === $value && $propMetadata->allowsNull()) {
286+
return null;
287+
}
288+
285289
return $this->serializer->denormalize($value, $type, 'json', $propMetadata->serializationContext());
286290
}
287291

src/LiveComponent/tests/Unit/LiveComponentHydratorTest.php

+30
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
1616
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
17+
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
18+
use Symfony\Component\Serializer\Serializer;
19+
use Symfony\UX\LiveComponent\Attribute\LiveProp;
1720
use Symfony\UX\LiveComponent\LiveComponentHydrator;
1821
use Symfony\UX\LiveComponent\Metadata\LiveComponentMetadataFactory;
22+
use Symfony\UX\LiveComponent\Metadata\LivePropMetadata;
1923

2024
final class LiveComponentHydratorTest extends TestCase
2125
{
@@ -32,4 +36,30 @@ public function testConstructWithEmptySecret(): void
3236
'',
3337
);
3438
}
39+
40+
public function testItCanHydrateWithNullValues()
41+
{
42+
$hydrator = new LiveComponentHydrator(
43+
[],
44+
$this->createMock(PropertyAccessorInterface::class),
45+
$this->createMock(LiveComponentMetadataFactory::class),
46+
new Serializer(normalizers: [new ObjectNormalizer()]),
47+
'foo',
48+
);
49+
50+
$hydratedValue = $hydrator->hydrateValue(
51+
null,
52+
new LivePropMetadata('foo', new LiveProp(useSerializerForHydration: true), typeName: Foo::class, isBuiltIn: false, allowsNull: true, collectionValueType: null),
53+
parentObject: new \stdClass() // not relevant in this test
54+
);
55+
56+
self::assertNull($hydratedValue);
57+
}
58+
}
59+
60+
class Foo
61+
{
62+
public function __construct(private int $id)
63+
{
64+
}
3565
}

0 commit comments

Comments
 (0)