Skip to content

Commit e05cd38

Browse files
committed
[Live] support (de)hydrating Enum's
1 parent 9aa183d commit e05cd38

File tree

5 files changed

+114
-2
lines changed

5 files changed

+114
-2
lines changed

src/LiveComponent/src/LiveComponentHydrator.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,15 @@ public function hydrate(object $component, array $data, string $componentName):
166166
}
167167

168168
$value = $dehydratedValue;
169+
$type = $property->getType() instanceof \ReflectionNamedType ? $property->getType() : null;
169170

170171
if ($method = $liveProp->hydrateMethod()) {
171172
// TODO: Error checking
172173
$value = $component->$method($dehydratedValue);
173-
} elseif ($property->getType() instanceof \ReflectionNamedType && !$property->getType()->isBuiltin()) {
174-
$value = $this->normalizer->denormalize($value, $property->getType()->getName(), 'json', [self::LIVE_CONTEXT => true]);
174+
} elseif (!$value && $type && $type->allowsNull()) {
175+
$value = null;
176+
} elseif ($value && $type && !$type->isBuiltin()) {
177+
$value = $this->normalizer->denormalize($value, $type->getName(), 'json', [self::LIVE_CONTEXT => true]);
175178
}
176179

177180
foreach ($liveProp->exposed() as $exposedProperty) {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Symfony\UX\LiveComponent\Tests\Fixtures\Component;
4+
5+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
6+
use Symfony\UX\LiveComponent\Attribute\LiveProp;
7+
use Symfony\UX\LiveComponent\DefaultActionTrait;
8+
use Symfony\UX\LiveComponent\Tests\Fixtures\Enum\Priority;
9+
use Symfony\UX\LiveComponent\Tests\Fixtures\Enum\Status;
10+
11+
#[AsLiveComponent('with_enum')]
12+
final class WithEnums
13+
{
14+
use DefaultActionTrait;
15+
16+
#[LiveProp(writable: true)]
17+
public ?Priority $priority = null;
18+
19+
#[LiveProp(writable: true)]
20+
public ?Status $status = null;
21+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Symfony\UX\LiveComponent\Tests\Fixtures\Enum;
4+
5+
enum Priority: int
6+
{
7+
case HIGH = 10;
8+
case LOW = 1;
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Symfony\UX\LiveComponent\Tests\Fixtures\Enum;
4+
5+
enum Status: string
6+
{
7+
case PENDING = 'pending';
8+
case ACTIVE = 'active';
9+
}

src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
use Symfony\UX\LiveComponent\Tests\Fixtures\Component\Component3;
1818
use Symfony\UX\LiveComponent\Tests\Fixtures\Component\ComponentWithArrayProp;
1919
use Symfony\UX\LiveComponent\Tests\Fixtures\Entity\Entity1;
20+
use Symfony\UX\LiveComponent\Tests\Fixtures\Enum\Priority;
21+
use Symfony\UX\LiveComponent\Tests\Fixtures\Enum\Status;
2022
use Symfony\UX\LiveComponent\Tests\LiveComponentTestHelper;
2123
use Zenstruck\Foundry\Test\Factories;
2224
use Zenstruck\Foundry\Test\ResetDatabase;
@@ -279,4 +281,72 @@ public function testCanDehydrateAndHydrateComponentsWithEmptyAttributes(): void
279281

280282
$this->assertSame([], $mounted->getAttributes()->all());
281283
}
284+
285+
/**
286+
* @requires PHP >= 8.1
287+
*/
288+
public function testCanHydrateEnums(): void
289+
{
290+
$mounted = $this->mountComponent('with_enum', ['priority' => Priority::HIGH, 'status' => Status::ACTIVE]);
291+
292+
$dehydrated = $this->dehydrateComponent($mounted);
293+
294+
$this->assertSame(10, $dehydrated['priority']);
295+
$this->assertSame('active', $dehydrated['status']);
296+
297+
$mounted = $this->hydrateComponent($this->getComponent('with_enum'), $dehydrated, $mounted->getName());
298+
299+
$this->assertSame(Priority::HIGH, $mounted->getComponent()->priority);
300+
$this->assertSame(Status::ACTIVE, $mounted->getComponent()->status);
301+
302+
$dehydrated['priority'] = Priority::LOW->value;
303+
$dehydrated['status'] = Status::PENDING->value;
304+
305+
$mounted = $this->hydrateComponent($this->getComponent('with_enum'), $dehydrated, $mounted->getName());
306+
307+
$this->assertSame(Priority::LOW, $mounted->getComponent()->priority);
308+
$this->assertSame(Status::PENDING, $mounted->getComponent()->status);
309+
}
310+
311+
/**
312+
* @requires PHP >= 8.1
313+
*/
314+
public function testCanHydrateEnumsThatAreNull(): void
315+
{
316+
$mounted = $this->mountComponent('with_enum');
317+
318+
$dehydrated = $this->dehydrateComponent($mounted);
319+
320+
$this->assertNull($dehydrated['priority']);
321+
$this->assertNull($dehydrated['status']);
322+
323+
$mounted = $this->hydrateComponent($this->getComponent('with_enum'), $dehydrated, $mounted->getName());
324+
325+
$this->assertNull($mounted->getComponent()->priority);
326+
$this->assertNull($mounted->getComponent()->status);
327+
328+
$dehydrated['priority'] = Priority::LOW->value;
329+
$dehydrated['status'] = Status::PENDING->value;
330+
331+
$mounted = $this->hydrateComponent($this->getComponent('with_enum'), $dehydrated, $mounted->getName());
332+
333+
$this->assertSame(Priority::LOW, $mounted->getComponent()->priority);
334+
$this->assertSame(Status::PENDING, $mounted->getComponent()->status);
335+
336+
$dehydrated['priority'] = null;
337+
$dehydrated['status'] = null;
338+
339+
$mounted = $this->hydrateComponent($this->getComponent('with_enum'), $dehydrated, $mounted->getName());
340+
341+
$this->assertNull($mounted->getComponent()->priority);
342+
$this->assertNull($mounted->getComponent()->status);
343+
344+
$dehydrated['priority'] = '';
345+
$dehydrated['status'] = '';
346+
347+
$mounted = $this->hydrateComponent($this->getComponent('with_enum'), $dehydrated, $mounted->getName());
348+
349+
$this->assertNull($mounted->getComponent()->priority);
350+
$this->assertNull($mounted->getComponent()->status);
351+
}
282352
}

0 commit comments

Comments
 (0)