Skip to content

Conversation

@kevinmade
Copy link

@kevinmade kevinmade commented Oct 28, 2025

Q A
Bug fix? no
New feature? yes
Deprecations? no
Documentation? no
Issues Fix #853
License MIT

This PR adds support for liveProp union types in Live Components. Previously, using a union type would throw an exception. With this change LiveComponentMetadataFactory will be able to create liveProp metadata for union types, but will only work in combination with a custom hydrate and dehydrate implementation.

@carsonbot carsonbot added Feature New Feature LiveComponent Status: Needs Review Needs to be reviewed labels Oct 28, 2025
Copy link
Member

@Kocal Kocal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi and thanks for the contribution!

This new feature needs to be covered with some tests, and the CHANGELOG.md must be updated too.

Also, you only support the TypeInfo path and not the legacy PropertyInfo path, but I think that's fine.

@carsonbot carsonbot added Status: Needs Work Additional work is needed and removed Status: Needs Review Needs to be reviewed labels Oct 29, 2025
@carsonbot carsonbot added Status: Needs Review Needs to be reviewed and removed Status: Needs Work Additional work is needed labels Oct 29, 2025
@kevinmade kevinmade requested a review from Kocal October 30, 2025 06:58

- Add support for `LiveProp` union types in Live Components.
`LiveComponentMetadataFactory` can now create `liveProp` metadata for union types.
Note: This feature only works when using a custom `hydrate` and `dehydrate` implementation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @kevinmade ! Could you add a test or two covering the cases "not supposed to work" (ie: when hydrate and/or dehydrate are missing ?)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought a hydrator and dehydrator were required for my change, but this had something to do with my own use case, where the union had a type that wasn't a hydratable. I’ve removed the note from the changelog and added a test.

Copy link
Member

@Kocal Kocal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests in LiveComponentHydratorTest::provideDehydrationHydrationTests data provider, so we can test the full dehydration/hydration process. Testing only the metadata factory is not enough.

Comment on lines +1639 to +1654
public function testObjectTypedLivePropCannotBeDehydrated()
{
$componentClass = new class {
#[LiveProp(writable: true)]
public object $object;
};

$component = new $componentClass();
$component->object = new class {
};

$this->expectException(\LogicException::class);
$this->expectExceptionMessageMatches('/The "object" property on component ".*" is missing its property-type. Add the ".*" type so the object can be hydrated later./');

$this->hydrator()->dehydrate($component, $this->createComponentAttributes(), $this->createLiveMetadata($component));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To move in \Symfony\UX\LiveComponent\Tests\Integration\LiveComponentHydratorTest::provideDehydrationHydrationTests

Comment on lines +47 to +62
public function testLivePropUnionType()
{
/** @var LiveComponentMetadataFactory $metadataFactory */
$metadataFactory = self::getContainer()->get('ux.live_component.metadata_factory');

$class = new \ReflectionClass(WithUnionIntersectionType::class);
$propsMetadata = $metadataFactory->createPropMetadatas($class);

$propsMetadataByName = [];
foreach ($propsMetadata as $propMetadata) {
$propsMetadataByName[$propMetadata->getName()] = $propMetadata;
}

$this->assertEquals('mixed', (string) $propsMetadataByName['unionProp']->getType());
$this->assertEquals('mixed', (string) $propsMetadataByName['intersectionProp']->getType());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes sense to have this test

Comment on lines +126 to +128
if ($reflectionType instanceof \ReflectionUnionType || $reflectionType instanceof \ReflectionIntersectionType) {
return new LivePropMetadata($property->getName(), $liveProp, Type::mixed());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we use Type::mixed() here, instead of $this->typeResolver->resolve($property) below?

@carsonbot carsonbot added Status: Needs Work Additional work is needed and removed Status: Needs Review Needs to be reviewed labels Dec 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature New Feature LiveComponent Status: Needs Work Additional work is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[LiveComponent] Support UnionTypes for LiveProps

4 participants