From d775dde53475c95f17645436dadcb6df0b0d91cd Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sat, 24 May 2025 22:22:45 +0200 Subject: [PATCH] [Routing] Fix inline default `null` --- src/Symfony/Component/Routing/Route.php | 2 +- .../Component/Routing/Tests/RouteTest.php | 71 +++++++++++-------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/Symfony/Component/Routing/Route.php b/src/Symfony/Component/Routing/Route.php index 1ed484f71237..621a4239fcf7 100644 --- a/src/Symfony/Component/Routing/Route.php +++ b/src/Symfony/Component/Routing/Route.php @@ -420,7 +420,7 @@ private function extractInlineDefaultsAndRequirements(string $pattern): string $pattern = preg_replace_callback('#\{(!?)([\w\x80-\xFF]++)(:([\w\x80-\xFF]++)(\.[\w\x80-\xFF]++)?)?(<.*?>)?(\?[^\}]*+)?\}#', function ($m) use (&$mapping) { if (isset($m[7][0])) { - $this->setDefault($m[2], '?' !== $m[6] ? substr($m[7], 1) : null); + $this->setDefault($m[2], '?' !== $m[7] ? substr($m[7], 1) : null); } if (isset($m[6][0])) { $this->setRequirement($m[2], substr($m[6], 1, -1)); diff --git a/src/Symfony/Component/Routing/Tests/RouteTest.php b/src/Symfony/Component/Routing/Tests/RouteTest.php index b58358a3ef31..3472804249f5 100644 --- a/src/Symfony/Component/Routing/Tests/RouteTest.php +++ b/src/Symfony/Component/Routing/Tests/RouteTest.php @@ -226,37 +226,48 @@ public function testSerialize() $this->assertNotSame($route, $unserialized); } - public function testInlineDefaultAndRequirement() + /** + * @dataProvider provideInlineDefaultAndRequirementCases + */ + public function testInlineDefaultAndRequirement(Route $route, string $expectedPath, string $expectedHost, array $expectedDefaults, array $expectedRequirements) + { + self::assertSame($expectedPath, $route->getPath()); + self::assertSame($expectedHost, $route->getHost()); + self::assertSame($expectedDefaults, $route->getDefaults()); + self::assertSame($expectedRequirements, $route->getRequirements()); + } + + public static function provideInlineDefaultAndRequirementCases(): iterable { - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', null), new Route('/foo/{bar?}')); - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?baz}')); - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?baz}')); - $this->assertEquals((new Route('/foo/{!bar}'))->setDefault('bar', 'baz'), new Route('/foo/{!bar?baz}')); - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?}', ['bar' => 'baz'])); - - $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '.*'), new Route('/foo/{bar<.*>}')); - $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '>'), new Route('/foo/{bar<>>}')); - $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '\d+'), new Route('/foo/{bar<.*>}', [], ['bar' => '\d+'])); - $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '[a-z]{2}'), new Route('/foo/{bar<[a-z]{2}>}')); - $this->assertEquals((new Route('/foo/{!bar}'))->setRequirement('bar', '\d+'), new Route('/foo/{!bar<\d+>}')); - - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', null)->setRequirement('bar', '.*'), new Route('/foo/{bar<.*>?}')); - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', '<>')->setRequirement('bar', '>'), new Route('/foo/{bar<>>?<>}')); - - $this->assertEquals((new Route('/{foo}/{!bar}'))->setDefaults(['bar' => '<>', 'foo' => '\\'])->setRequirements(['bar' => '\\', 'foo' => '.']), new Route('/{foo<.>?\}/{!bar<\>?<>}')); - - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', null), (new Route('/'))->setHost('{bar?}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', 'baz'), (new Route('/'))->setHost('{bar?baz}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', 'baz'), (new Route('/'))->setHost('{bar?baz}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', null), (new Route('/', ['bar' => 'baz']))->setHost('{bar?}')); - - $this->assertEquals((new Route('/'))->setHost('{bar}')->setRequirement('bar', '.*'), (new Route('/'))->setHost('{bar<.*>}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setRequirement('bar', '>'), (new Route('/'))->setHost('{bar<>>}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setRequirement('bar', '.*'), (new Route('/', [], ['bar' => '\d+']))->setHost('{bar<.*>}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setRequirement('bar', '[a-z]{2}'), (new Route('/'))->setHost('{bar<[a-z]{2}>}')); - - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', null)->setRequirement('bar', '.*'), (new Route('/'))->setHost('{bar<.*>?}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', '<>')->setRequirement('bar', '>'), (new Route('/'))->setHost('{bar<>>?<>}')); + yield [new Route('/foo/{bar?}'), '/foo/{bar}', '', ['bar' => null], []]; + yield [new Route('/foo/{bar?baz}'), '/foo/{bar}', '', ['bar' => 'baz'], []]; + yield [new Route('/foo/{bar?baz}'), '/foo/{bar}', '', ['bar' => 'baz'], []]; + yield [new Route('/foo/{!bar?baz}'), '/foo/{!bar}', '', ['bar' => 'baz'], []]; + yield [new Route('/foo/{bar?}', ['bar' => 'baz']), '/foo/{bar}', '', ['bar' => 'baz'], []]; + + yield [new Route('/foo/{bar<.*>}'), '/foo/{bar}', '', [], ['bar' => '.*']]; + yield [new Route('/foo/{bar<>>}'), '/foo/{bar}', '', [], ['bar' => '>']]; + yield [new Route('/foo/{bar<.*>}', [], ['bar' => '\d+']), '/foo/{bar}', '', [], ['bar' => '\d+']]; + yield [new Route('/foo/{bar<[a-z]{2}>}'), '/foo/{bar}', '', [], ['bar' => '[a-z]{2}']]; + yield [new Route('/foo/{!bar<\d+>}'), '/foo/{!bar}', '', [], ['bar' => '\d+']]; + + yield [new Route('/foo/{bar<.*>?}'), '/foo/{bar}', '', ['bar' => null], ['bar' => '.*']]; + yield [new Route('/foo/{bar<>>?<>}'), '/foo/{bar}', '', ['bar' => '<>'], ['bar' => '>']]; + + yield [new Route('/{foo<.>?\}/{!bar<\>?<>}'), '/{foo}/{!bar}', '', ['foo' => '\\', 'bar' => '<>'], ['foo' => '.', 'bar' => '\\']]; + + yield [new Route('/', host: '{bar?}'), '/', '{bar}', ['bar' => null], []]; + yield [new Route('/', host: '{bar?baz}'), '/', '{bar}', ['bar' => 'baz'], []]; + yield [new Route('/', host: '{bar?baz}'), '/', '{bar}', ['bar' => 'baz'], []]; + yield [new Route('/', ['bar' => 'baz'], host: '{bar?}'), '/', '{bar}', ['bar' => null], []]; + + yield [new Route('/', host: '{bar<.*>}'), '/', '{bar}', [], ['bar' => '.*']]; + yield [new Route('/', host: '{bar<>>}'), '/', '{bar}', [], ['bar' => '>']]; + yield [new Route('/', [], ['bar' => '\d+'], host: '{bar<.*>}'), '/', '{bar}', [], ['bar' => '.*']]; + yield [new Route('/', host: '{bar<[a-z]{2}>}'), '/', '{bar}', [], ['bar' => '[a-z]{2}']]; + + yield [new Route('/', host: '{bar<.*>?}'), '/', '{bar}', ['bar' => null], ['bar' => '.*']]; + yield [new Route('/', host: '{bar<>>?<>}'), '/', '{bar}', ['bar' => '<>'], ['bar' => '>']]; } /**