Open jpvdw86 opened 10 months ago
Edit: Example is now more dynamic.
For anyone facing the same issue, I've resolved it by creating a specific CustomLiveCollectionTrait for this usecase. This initializes the correct object.
Example code:
#[AsLiveComponent]
class VehicleFinancialFormComponent extends AbstractController
{
use DefaultActionTrait;
use CustomLiveCollectionTrait;
#[LiveProp]
public ?FinancialsModel $financials = null;
protected function instantiateForm(): FormInterface
{
.....
}
services:
Symfony\UX\LiveComponent\Metadata\LiveComponentMetadataFactory: '@ux.live_component.metadata_factory'
trait CustomLiveCollectionTrait
{
use LiveCollectionTrait;
public function __construct(
private readonly LiveComponentMetadataFactory $liveComponentMetadataFactory,
private readonly PropertyAccessorInterface $propertyAccessor
) {
}
#[LiveAction]
public function addCollectionItem(#[LiveArg] string $name): void
{
$propertyPath = $this->fieldNameToPropertyPath($name, $this->formName);
$value = $this->initializeValue($propertyPath);
$data = $this->propertyAccessor->getValue($this->formValues, $propertyPath);
if (!\is_array($data)) {
$this->propertyAccessor->setValue($this->formValues, $propertyPath, []);
$data = [];
}
$index = [] !== $data ? max(array_keys($data)) + 1 : 0;
$this->propertyAccessor->setValue($this->formValues, $propertyPath."[$index]", $value);
}
private function deHydrateClass(string $className): array
{
$propertyData = [];
$class = new $className();
foreach ((new PropertyInfoExtractor([new ReflectionExtractor()]))->getProperties($class::class) as $property) {
$propValue = $this->propertyAccessor->getValue($class, $property);
$propertyData[$property] = $this->deHydrateValue($propValue);
}
return $propertyData;
}
private function deHydrateValue(mixed $value): mixed
{
if ($value instanceof \DateTimeInterface) {
return $value->format(\DateTimeInterface::RFC3339);
}
if ($value instanceof \BackedEnum) {
return $value->value;
}
if (\is_bool($value) || null === $value || is_numeric($value) || \is_string($value)) {
return $value;
}
throw new \LogicException(sprintf('Unable to dehydrate value of type "%s".', get_debug_type($value)));
}
private function initializeValue(string $propertyPath): array
{
$dataClass = $this->getForm()->getConfig()->getDataClass();
$property = str_replace(['[', ']'], '', $propertyPath);
$propMetadata = $this->liveComponentMetadataFactory->createLivePropMetadata(
$dataClass,
$property,
new \ReflectionProperty($dataClass, $property),
new LiveProp()
);
$collectionClass = $propMetadata->collectionValueType()?->getClassName();
if ($collectionClass) {
return $this->deHydrateClass($collectionClass);
}
return [];
}
}
if this is the right solution, then i will make a PR to change the existing LiveCollectionTrait. With usage of the already existing deHydrateValue function in this package.
Did it work "before" ? Do you know what changed ?
Did it work "before" ? Do you know what changed ?
Until 2.7 its works, but after migrating to the latest version. I got now 2 actual issues.
This all is about this change; "[BC BREAK]: LiveProp values are no longer automatically (de)hydrated through Symfony's serializer. Use LiveProp(useSerializerForHydration: true) to activate this. Also, a serializationContext option was added to LiveProp."
And useSerializerForHydratio:true don't fix every problem and result in other issues like circular references.
Ok, can we see this via another angle ?
This all is about this change; "[BC BREAK]: LiveProp values are no longer automatically (de)hydrated through Symfony's serializer. Use LiveProp(useSerializerForHydration: true) to activate this. Also, a serializationContext option was added to LiveProp."
So "before" 2.8, your values were dehydrated through the serializer and all worked as expected, and "after" 2.8 that did not work.
Can we see if there is something there to check / fix ?
When using the LiveCollectionType with a DTO as a data object, you now encounter the following error during the addCollectionItem live action.
This occurs because the new item is still null and, according to the $propMetadata, an object is expected.
Example code:
Component:
FinancialsDTO:
FormType
RecordFormType
RecordDto: