-
-
Notifications
You must be signed in to change notification settings - Fork 413
[LiveComponent] Hydration fails on arrays of entities whose identifier is an UUID (object) #3410
Description
When using arrays of entities as a LiveProp in a component (as described here in the docs) the dehydration fails, if the object's identifiers are object values like some kind of Uuid/Symfony\Component\Uid\AbstractUid. The corresponding error is thrown here:
ux/src/LiveComponent/src/LiveComponentHydrator.php
Lines 599 to 601 in 21b1bb6
| if (!$this->isValueValidDehydratedValue($value)) { | |
| throw new \LogicException(throw new \LogicException(\sprintf('Unable to dehydrate value of type "%s" for property "%s" on component "%s". Change this to a simpler type of an object that can be dehydrated. Or set the hydrateWith/dehydrateWith options in LiveProp or set "useSerializerForHydration: true" on the LiveProp to use the serializer.', get_debug_type($value), $propMetadata->getName(), $parentObject::class))); | |
| } |
When I only refer to a single object with an Uuid everything works. The reason for that is seemingly, that LiveComponentHydrator::isValueValidDehydratedValue() is only checked for values in lower levels, i.e. in two places:
- When
writableis explicitly set to an array of paths - When dehydrating an array/iterable
Since objects fail the check in this function, this causes the aforementioned exception.
Expected behavior
Arrays of entities with UUID object identifiers should be hydrated into an array of scalar values that can later be hydrated back correctly.
Actual behavior
The object identifiers fail a validity check which breaks the hydration flow for LiveComponent when the entity ID is a UUID object.
How to reproduce
<?php
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity]
class Product
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
private ?Uuid $id;
public function getId(): ?Uuid
{
return $this->id;
}
// ...
}<?php
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait;
#[AsLiveComponent]
class ProductList
{
use DefaultActionTrait;
/**
* @var Product[]
*/
#[LiveProp]
public array $products= [];
// ...
}Additional Notes
I worked around this now, by copying the DoctrineEntityHydrationExtension into my project and adding a conversion from AbstractUid to string in there, right below the recursive call for other entities:
// Dehydrate ID values in case they are other entities
$id = array_map(fn ($id) => \is_object($id) && $this->supports($id::class) ? $this->dehydrate($id) : $id, $id);
$id = array_map(fn ($id) => $id instanceof AbstractUid ? (string) $id : $id, $id); // <-- this is newThis works for now but I am not sure this is the best way to solve this in the long run. Another option would be to extend the check in LiveComponentHydrator::isValueValidDehydratedValue() to also allow for AbstractUid or even \Stringable.
If we settle on a viable solution, I can try to provide a corresponding PR.