diff --git a/src/Symfony/Component/Routing/Route.php b/src/Symfony/Component/Routing/Route.php index 03ec76e0dd..de98e1d763 100644 --- a/src/Symfony/Component/Routing/Route.php +++ b/src/Symfony/Component/Routing/Route.php @@ -376,6 +376,10 @@ class Route implements \Serializable */ public function addDefaults(array $defaults) { + if (isset($defaults['_locale']) && $this->isLocalized()) { + unset($defaults['_locale']); + } + foreach ($defaults as $name => $default) { $this->defaults[$name] = $default; } @@ -418,6 +422,10 @@ class Route implements \Serializable */ public function setDefault($name, $default) { + if ('_locale' === $name && $this->isLocalized()) { + return $this; + } + $this->defaults[$name] = $default; $this->compiled = null; @@ -461,6 +469,10 @@ class Route implements \Serializable */ public function addRequirements(array $requirements) { + if (isset($requirements['_locale']) && $this->isLocalized()) { + unset($requirements['_locale']); + } + foreach ($requirements as $key => $regex) { $this->requirements[$key] = $this->sanitizeRequirement($key, $regex); } @@ -503,6 +515,10 @@ class Route implements \Serializable */ public function setRequirement($key, $regex) { + if ('_locale' === $key && $this->isLocalized()) { + return $this; + } + $this->requirements[$key] = $this->sanitizeRequirement($key, $regex); $this->compiled = null; @@ -577,4 +593,9 @@ class Route implements \Serializable return $regex; } + + private function isLocalized(): bool + { + return isset($this->defaults['_locale']) && isset($this->defaults['_canonical_route']) && ($this->requirements['_locale'] ?? null) === preg_quote($this->defaults['_locale'], RouteCompiler::REGEX_DELIMITER); + } } diff --git a/src/Symfony/Component/Routing/Tests/RouteTest.php b/src/Symfony/Component/Routing/Tests/RouteTest.php index 6add1337ed..4c767f9d95 100644 --- a/src/Symfony/Component/Routing/Tests/RouteTest.php +++ b/src/Symfony/Component/Routing/Tests/RouteTest.php @@ -271,4 +271,65 @@ class RouteTest extends TestCase $this->assertEquals($route, $unserialized); $this->assertNotSame($route, $unserialized); } + + /** + * @dataProvider provideNonLocalizedRoutes + */ + public function testLocaleDefaultWithNonLocalizedRoutes(Route $route) + { + $this->assertNotSame('fr', $route->getDefault('_locale')); + $route->setDefault('_locale', 'fr'); + $this->assertSame('fr', $route->getDefault('_locale')); + } + + /** + * @dataProvider provideLocalizedRoutes + */ + public function testLocaleDefaultWithLocalizedRoutes(Route $route) + { + $expected = $route->getDefault('_locale'); + $this->assertIsString($expected); + $this->assertNotSame('fr', $expected); + $route->setDefault('_locale', 'fr'); + $this->assertSame($expected, $route->getDefault('_locale')); + } + + /** + * @dataProvider provideNonLocalizedRoutes + */ + public function testLocaleRequirementWithNonLocalizedRoutes(Route $route) + { + $this->assertNotSame('fr', $route->getRequirement('_locale')); + $route->setRequirement('_locale', 'fr'); + $this->assertSame('fr', $route->getRequirement('_locale')); + } + + /** + * @dataProvider provideLocalizedRoutes + */ + public function testLocaleRequirementWithLocalizedRoutes(Route $route) + { + $expected = $route->getRequirement('_locale'); + $this->assertIsString($expected); + $this->assertNotSame('fr', $expected); + $route->setRequirement('_locale', 'fr'); + $this->assertSame($expected, $route->getRequirement('_locale')); + } + + public function provideNonLocalizedRoutes() + { + return [ + [(new Route('/foo'))], + [(new Route('/foo'))->setDefault('_locale', 'en')], + [(new Route('/foo'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'foo')], + [(new Route('/foo'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'foo')->setRequirement('_locale', 'foobar')], + ]; + } + + public function provideLocalizedRoutes() + { + return [ + [(new Route('/foo'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'foo')->setRequirement('_locale', 'en')], + ]; + } }