From 25c3e134a2af7caf72e8efd8ccdb6dd6d2c78ba7 Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Thu, 28 Aug 2025 22:24:24 +0200 Subject: [PATCH] [LiveComponent] Fix new URL generation when using `LiveProp` with custom `fieldName` --- .../src/Metadata/LiveComponentMetadata.php | 2 +- .../Component/ComponentWithUrlBoundProps.php | 11 ++++++ .../AddLiveAttributesSubscriberTest.php | 2 + .../EventListener/LiveUrlSubscriberTest.php | 37 +++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/LiveComponent/src/Metadata/LiveComponentMetadata.php b/src/LiveComponent/src/Metadata/LiveComponentMetadata.php index 91b895afe5f..a0758284981 100644 --- a/src/LiveComponent/src/Metadata/LiveComponentMetadata.php +++ b/src/LiveComponent/src/Metadata/LiveComponentMetadata.php @@ -75,7 +75,7 @@ public function getAllUrlMappings(object $component): array foreach ($this->getAllLivePropsMetadata($component) as $livePropMetadata) { if ($livePropMetadata->urlMapping()) { - $urlMappings[$livePropMetadata->getName()] = $livePropMetadata->urlMapping(); + $urlMappings[$livePropMetadata->calculateFieldName($component, $livePropMetadata->getName())] = $livePropMetadata->urlMapping(); } } diff --git a/src/LiveComponent/tests/Fixtures/Component/ComponentWithUrlBoundProps.php b/src/LiveComponent/tests/Fixtures/Component/ComponentWithUrlBoundProps.php index 1ee8b268326..2f28a4cfff1 100644 --- a/src/LiveComponent/tests/Fixtures/Component/ComponentWithUrlBoundProps.php +++ b/src/LiveComponent/tests/Fixtures/Component/ComponentWithUrlBoundProps.php @@ -33,6 +33,12 @@ class ComponentWithUrlBoundProps #[LiveProp(url: true)] public array $arrayProp = []; + #[LiveProp(url: new UrlMapping(as: 'arr_alias'))] + public array $arrayPropAlias = []; + + #[LiveProp(writable: true, fieldName: 'getArrayFieldName()', url: true)] + public array $arrayPropFieldName = []; + #[LiveProp] public ?string $unboundProp = null; @@ -113,4 +119,9 @@ public function updateLiveProp(#[LiveArg] string $propName, #[LiveArg] mixed $pr $this->{$propName} = $propValue; } + + public function getArrayFieldName(): string + { + return 'arr_field_name'; + } } diff --git a/src/LiveComponent/tests/Functional/EventListener/AddLiveAttributesSubscriberTest.php b/src/LiveComponent/tests/Functional/EventListener/AddLiveAttributesSubscriberTest.php index 1ded114e149..61c276d128d 100644 --- a/src/LiveComponent/tests/Functional/EventListener/AddLiveAttributesSubscriberTest.php +++ b/src/LiveComponent/tests/Functional/EventListener/AddLiveAttributesSubscriberTest.php @@ -144,6 +144,8 @@ public function testQueryStringMappingAttribute() 'objectPropWithSerializerForHydration' => ['name' => 'objectPropWithSerializerForHydration'], 'propertyWithModifierAndAlias' => ['name' => 'alias_p'], 'pathPropForAnotherController' => ['name' => 'pathPropForAnotherController'], + 'arrayPropAlias' => ['name' => 'arr_alias'], + 'arr_field_name' => ['name' => 'arr_field_name'], ]; $this->assertEquals($expected, $queryMapping); diff --git a/src/LiveComponent/tests/Functional/EventListener/LiveUrlSubscriberTest.php b/src/LiveComponent/tests/Functional/EventListener/LiveUrlSubscriberTest.php index 97d85be7532..91224e668f1 100644 --- a/src/LiveComponent/tests/Functional/EventListener/LiveUrlSubscriberTest.php +++ b/src/LiveComponent/tests/Functional/EventListener/LiveUrlSubscriberTest.php @@ -118,6 +118,7 @@ public function getTestData(): iterable 'propValue' => 'bar', ], ]; + yield 'Changes in prop, with two path params but only one prop' => [ 'previousLocation' => '/route_with_two_path_params_but_one_prop/foo/30', 'expectedLocation' => '/route_with_two_path_params_but_one_prop/bar/30', @@ -140,6 +141,42 @@ public function getTestData(): iterable ], ]; + yield 'Change in query (array)' => [ + 'previousLocation' => '/route_with_prop/foo', + 'expectedLocation' => '/route_with_prop/foo?arrayProp%5B0%5D=hello&arrayProp%5B1%5D=world', + 'initialComponentData' => [ + 'pathProp' => 'foo', + ], + 'args' => [ + 'propName' => 'arrayProp', + 'propValue' => ['hello', 'world'], + ], + ]; + + yield 'Change in query (array & alias)' => [ + 'previousLocation' => '/route_with_prop/foo', + 'expectedLocation' => '/route_with_prop/foo?arr_alias%5B0%5D=hello&arr_alias%5B1%5D=world', + 'initialComponentData' => [ + 'pathProp' => 'foo', + ], + 'args' => [ + 'propName' => 'arrayPropAlias', + 'propValue' => ['hello', 'world'], + ], + ]; + + yield 'Change in query (array & field name)' => [ + 'previousLocation' => '/route_with_prop/foo', + 'expectedLocation' => '/route_with_prop/foo?arr_field_name%5B0%5D=hello&arr_field_name%5B1%5D=world', + 'initialComponentData' => [ + 'pathProp' => 'foo', + ], + 'args' => [ + 'propName' => 'arrayPropFieldName', + 'propValue' => ['hello', 'world'], + ], + ]; + yield 'Changes in props and query' => [ 'previousLocation' => '/route_with_prop/foo', 'expectedLocation' => '/route_with_prop/baz?q=foo+bar',