[Routing] Add fallback to cultureless locale for internationalized routes

This commit is contained in:
Thomas Calvet 2018-07-15 16:11:16 +02:00 committed by Nicolas Grekas
parent 4b92b96796
commit fd2e3c36fb
4 changed files with 84 additions and 12 deletions

View File

@ -1,6 +1,11 @@
CHANGELOG
=========
4.2.0
-----
* added fallback to cultureless locale for internationalized routes
4.0.0
-----

View File

@ -113,10 +113,17 @@ EOF;
?? $this->context->getParameter('_locale')
?: $this->defaultLocale;
if (null !== $locale && (self::$declaredRoutes[$name.'.'.$locale][1]['_canonical_route'] ?? null) === $name) {
unset($parameters['_locale']);
$name .= '.'.$locale;
} elseif (!isset(self::$declaredRoutes[$name])) {
if (null !== $locale) {
do {
if ((self::$declaredRoutes[$name.'.'.$locale][1]['_canonical_route'] ?? null) === $name) {
unset($parameters['_locale']);
$name .= '.'.$locale;
break;
}
} while (false !== $locale = strstr($locale, '_', true));
}
if (!isset(self::$declaredRoutes[$name])) {
throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
}

View File

@ -112,13 +112,21 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
*/
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
{
$route = null;
$locale = $parameters['_locale']
?? $this->context->getParameter('_locale')
?: $this->defaultLocale;
if (null !== $locale && null !== ($route = $this->routes->get($name.'.'.$locale)) && $route->getDefault('_canonical_route') === $name) {
unset($parameters['_locale']);
} elseif (null === $route = $this->routes->get($name)) {
if (null !== $locale) {
do {
if (null !== ($route = $this->routes->get($name.'.'.$locale)) && $route->getDefault('_canonical_route') === $name) {
unset($parameters['_locale']);
break;
}
} while (false !== $locale = strstr($locale, '_', true));
}
if (null === $route = $route ?? $this->routes->get($name)) {
throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
}

View File

@ -46,8 +46,8 @@ class PhpGeneratorDumperTest extends TestCase
$this->routeCollection = new RouteCollection();
$this->generatorDumper = new PhpGeneratorDumper($this->routeCollection);
$this->testTmpFilepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_generator.'.$this->getName().'.php';
$this->largeTestTmpFilepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_generator.'.$this->getName().'.large.php';
$this->testTmpFilepath = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'php_generator.'.$this->getName().'.php';
$this->largeTestTmpFilepath = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'php_generator.'.$this->getName().'.large.php';
@unlink($this->testTmpFilepath);
@unlink($this->largeTestTmpFilepath);
}
@ -84,19 +84,20 @@ class PhpGeneratorDumperTest extends TestCase
$this->assertEquals('/app.php/testing2', $relativeUrlWithoutParameter);
}
public function testDumpWithLocalizedRoutes()
public function testDumpWithSimpleLocalizedRoutes()
{
$this->routeCollection->add('test', (new Route('/foo')));
$this->routeCollection->add('test.en', (new Route('/testing/is/fun'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'test'));
$this->routeCollection->add('test.nl', (new Route('/testen/is/leuk'))->setDefault('_locale', 'nl')->setDefault('_canonical_route', 'test'));
$code = $this->generatorDumper->dump(array(
'class' => 'LocalizedProjectUrlGenerator',
'class' => 'SimpleLocalizedProjectUrlGenerator',
));
file_put_contents($this->testTmpFilepath, $code);
include $this->testTmpFilepath;
$context = new RequestContext('/app.php');
$projectUrlGenerator = new \LocalizedProjectUrlGenerator($context, null, 'en');
$projectUrlGenerator = new \SimpleLocalizedProjectUrlGenerator($context, null, 'en');
$urlWithDefaultLocale = $projectUrlGenerator->generate('test');
$urlWithSpecifiedLocale = $projectUrlGenerator->generate('test', array('_locale' => 'nl'));
@ -109,6 +110,57 @@ class PhpGeneratorDumperTest extends TestCase
$this->assertEquals('/app.php/testen/is/leuk', $urlWithSpecifiedLocale);
$this->assertEquals('/app.php/testing/is/fun', $urlWithEnglishContext);
$this->assertEquals('/app.php/testen/is/leuk', $urlWithDutchContext);
// test with full route name
$this->assertEquals('/app.php/testing/is/fun', $projectUrlGenerator->generate('test.en'));
$context->setParameter('_locale', 'de_DE');
// test that it fall backs to another route when there is no matching localized route
$this->assertEquals('/app.php/foo', $projectUrlGenerator->generate('test'));
}
/**
* @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
* @expectedExceptionMessage Unable to generate a URL for the named route "test" as such route does not exist.
*/
public function testDumpWithRouteNotFoundLocalizedRoutes()
{
$this->routeCollection->add('test.en', (new Route('/testing/is/fun'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'test'));
$code = $this->generatorDumper->dump(array(
'class' => 'RouteNotFoundLocalizedProjectUrlGenerator',
));
file_put_contents($this->testTmpFilepath, $code);
include $this->testTmpFilepath;
$projectUrlGenerator = new \RouteNotFoundLocalizedProjectUrlGenerator(new RequestContext('/app.php'), null, 'pl_PL');
$projectUrlGenerator->generate('test');
}
public function testDumpWithFallbackLocaleLocalizedRoutes()
{
$this->routeCollection->add('test.en', (new Route('/testing/is/fun'))->setDefault('_canonical_route', 'test'));
$this->routeCollection->add('test.nl', (new Route('/testen/is/leuk'))->setDefault('_canonical_route', 'test'));
$this->routeCollection->add('test.fr', (new Route('/tester/est/amusant'))->setDefault('_canonical_route', 'test'));
$code = $this->generatorDumper->dump(array(
'class' => 'FallbackLocaleLocalizedProjectUrlGenerator',
));
file_put_contents($this->testTmpFilepath, $code);
include $this->testTmpFilepath;
$context = new RequestContext('/app.php');
$context->setParameter('_locale', 'en_GB');
$projectUrlGenerator = new \FallbackLocaleLocalizedProjectUrlGenerator($context, null, null);
// test with context _locale
$this->assertEquals('/app.php/testing/is/fun', $projectUrlGenerator->generate('test'));
// test with parameters _locale
$this->assertEquals('/app.php/testen/is/leuk', $projectUrlGenerator->generate('test', array('_locale' => 'nl_BE')));
$projectUrlGenerator = new \FallbackLocaleLocalizedProjectUrlGenerator(new RequestContext('/app.php'), null, 'fr_CA');
// test with default locale
$this->assertEquals('/app.php/tester/est/amusant', $projectUrlGenerator->generate('test'));
}
public function testDumpWithTooManyRoutes()