From 39a284338a4167cbd580f3977e5c12180ca3b84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Buliard?= Date: Tue, 5 Aug 2025 23:26:43 +0200 Subject: [PATCH] [LiveComponent] Fix `#[LiveProp(writable: true, url: true)]` that was not updated as a query parameter --- src/LiveComponent/src/Util/UrlFactory.php | 29 +++++++++++++------ src/LiveComponent/tests/Fixtures/Kernel.php | 2 +- .../tests/Unit/Util/UrlFactoryTest.php | 17 +++++++++-- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/LiveComponent/src/Util/UrlFactory.php b/src/LiveComponent/src/Util/UrlFactory.php index da25ecf9763..b0d92436730 100644 --- a/src/LiveComponent/src/Util/UrlFactory.php +++ b/src/LiveComponent/src/Util/UrlFactory.php @@ -36,14 +36,8 @@ public function createFromPreviousAndProps( return null; } - // Make sure to handle only path and query - $previousUrl = $parsed['path'] ?? ''; - if (isset($parsed['query'])) { - $previousUrl .= '?'.$parsed['query']; - } - try { - $newUrl = $this->createPath($previousUrl, $pathMappedProps); + $newUrl = $this->createPath($parsed['path'] ?? '', $pathMappedProps); } catch (ResourceNotFoundException|MethodNotAllowedException|MissingMandatoryParametersException) { return null; } @@ -60,10 +54,27 @@ public function createFromPreviousAndProps( private function createPath(string $previousUrl, array $props): string { - return $this->router->generate( - $this->router->match($previousUrl)['_route'] ?? '', + $newPath = $this->router->generate( + $this->matchRoute($previousUrl), $props ); + + return $newPath; + } + + private function matchRoute(string $previousUrl): string + { + $context = $this->router->getContext(); + $tmpContext = clone $context; + $tmpContext->setMethod('GET'); + $this->router->setContext($tmpContext); + try { + $match = $this->router->match($previousUrl); + } finally { + $this->router->setContext($context); + } + + return $match['_route'] ?? ''; } private function replaceQueryString($url, array $props): string diff --git a/src/LiveComponent/tests/Fixtures/Kernel.php b/src/LiveComponent/tests/Fixtures/Kernel.php index 2038fd4f1d5..1d45f78dc0f 100644 --- a/src/LiveComponent/tests/Fixtures/Kernel.php +++ b/src/LiveComponent/tests/Fixtures/Kernel.php @@ -217,7 +217,7 @@ protected function configureRoutes(RoutingConfigurator $routes): void $routes->add('homepage', '/')->controller('kernel::index'); $routes->add('alternate_live_route', '/alt/{_live_component}/{_live_action}')->defaults(['_live_action' => 'get']); $routes->add('localized_route', '/locale/{_locale}/{_live_component}/{_live_action}')->defaults(['_live_action' => 'get']); - $routes->add('route_with_prop', '/route_with_prop/{pathProp}'); + $routes->add('route_with_prop', '/route_with_prop/{pathProp}')->methods(['GET']); $routes->add('route_with_alias_prop', '/route_with_alias_prop/{pathAlias}'); } } diff --git a/src/LiveComponent/tests/Unit/Util/UrlFactoryTest.php b/src/LiveComponent/tests/Unit/Util/UrlFactoryTest.php index 07fe93ee400..76d46a710b7 100644 --- a/src/LiveComponent/tests/Unit/Util/UrlFactoryTest.php +++ b/src/LiveComponent/tests/Unit/Util/UrlFactoryTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\MissingMandatoryParametersException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; +use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouterInterface; use Symfony\UX\LiveComponent\Util\UrlFactory; @@ -40,10 +41,10 @@ public static function provideTestCreate(): \Generator yield 'keep_url_with_query_parameters' => [ 'input' => ['previousUrl' => 'https://symfony.com/foo/bar?prop1=val1&prop2=val2'], - '/foo/bar?prop1=val1&prop2=val2', + 'expectedUrl' => '/foo/bar?prop1=val1&prop2=val2', 'routerStubData' => [ - 'previousUrl' => '/foo/bar?prop1=val1&prop2=val2', - 'newUrl' => '/foo/bar?prop1=val1&prop2=val2', + 'previousUrl' => '/foo/bar', + 'newUrl' => '/foo/bar', ], ]; @@ -61,6 +62,10 @@ public static function provideTestCreate(): \Generator 'queryMappedProps' => ['prop1' => 'val1', 'prop2' => 'val2'], ], 'expectedUrl' => '/foo/bar?prop1=val1&prop3=oldValue&prop2=val2', + 'routerStubData' => [ + 'previousUrl' => '/foo/bar', + 'newUrl' => '/foo/bar', + ], ]; yield 'add_path_parameters' => [ @@ -178,7 +183,13 @@ private function createRouterStub( array $props = [], ): RouterInterface { $matchedRoute = 'default'; + $context = $this->createMock(RequestContext::class); $router = $this->createMock(RouterInterface::class); + $router->expects(self::once()) + ->method('getContext') + ->willReturn($context); + $router->expects(self::exactly(2)) + ->method('setContext'); $router->expects(self::once()) ->method('match') ->with($previousUrl)