[FrameworkBundle] allow turning routes to utf8 mode by default

This commit is contained in:
Nicolas Grekas 2018-06-29 14:29:05 +02:00
parent 7135aa4338
commit 8f359cc047
7 changed files with 63 additions and 1 deletions

View File

@ -37,6 +37,14 @@ Form
{% endfor %} {% endfor %}
``` ```
FrameworkBundle
---------------
* The `framework.router.utf8` configuration option has been added. If your app's charset
is UTF-8 (see kernel's `getCharset()` method), it is recommended to set it to `true`:
this will generate 404s for non-UTF-8 URLs, which are incompatible with you app anyway,
and will allow dumping optimized routers and using Unicode classes in requirements.
Security Security
-------- --------

View File

@ -452,6 +452,7 @@ class Configuration implements ConfigurationInterface
) )
->defaultTrue() ->defaultTrue()
->end() ->end()
->booleanNode('utf8')->defaultFalse()->end()
->end() ->end()
->end() ->end()
->end() ->end()

View File

@ -687,6 +687,9 @@ class FrameworkExtension extends Extension
$loader->load('routing.xml'); $loader->load('routing.xml');
if ($config['utf8']) {
$container->getDefinition('routing.loader')->replaceArgument(2, array('utf8' => true));
}
if (!interface_exists(ContainerBagInterface::class)) { if (!interface_exists(ContainerBagInterface::class)) {
$container->getDefinition('router.default') $container->getDefinition('router.default')
->replaceArgument(0, new Reference('service_container')) ->replaceArgument(0, new Reference('service_container'))

View File

@ -48,6 +48,7 @@
<service id="routing.loader" class="Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader" public="true"> <service id="routing.loader" class="Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader" public="true">
<argument type="service" id="controller_name_converter" /> <argument type="service" id="controller_name_converter" />
<argument type="service" id="routing.resolver" /> <argument type="service" id="routing.resolver" />
<argument type="collection" />
</service> </service>
<service id="router.default" class="Symfony\Bundle\FrameworkBundle\Routing\Router"> <service id="router.default" class="Symfony\Bundle\FrameworkBundle\Routing\Router">

View File

@ -28,14 +28,16 @@ class DelegatingLoader extends BaseDelegatingLoader
{ {
protected $parser; protected $parser;
private $loading = false; private $loading = false;
private $defaultOptions;
/** /**
* @param ControllerNameParser $parser A ControllerNameParser instance * @param ControllerNameParser $parser A ControllerNameParser instance
* @param LoaderResolverInterface $resolver A LoaderResolverInterface instance * @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
*/ */
public function __construct(ControllerNameParser $parser, LoaderResolverInterface $resolver) public function __construct(ControllerNameParser $parser, LoaderResolverInterface $resolver, array $defaultOptions = array())
{ {
$this->parser = $parser; $this->parser = $parser;
$this->defaultOptions = $defaultOptions;
parent::__construct($resolver); parent::__construct($resolver);
} }
@ -73,6 +75,9 @@ class DelegatingLoader extends BaseDelegatingLoader
} }
foreach ($collection->all() as $route) { foreach ($collection->all() as $route) {
if ($this->defaultOptions) {
$route->setOptions($route->getOptions() + $this->defaultOptions);
}
if (!is_string($controller = $route->getDefault('_controller'))) { if (!is_string($controller = $route->getDefault('_controller'))) {
continue; continue;
} }

View File

@ -226,6 +226,7 @@ class ConfigurationTest extends TestCase
'http_port' => 80, 'http_port' => 80,
'https_port' => 443, 'https_port' => 443,
'strict_requirements' => true, 'strict_requirements' => true,
'utf8' => false,
), ),
'session' => array( 'session' => array(
'enabled' => false, 'enabled' => false,

View File

@ -22,6 +22,49 @@ class DelegatingLoaderTest extends TestCase
$this->assertTrue(true, '__construct() takes a ControllerNameParser and LoaderResolverInterface respectively as its first and second argument.'); $this->assertTrue(true, '__construct() takes a ControllerNameParser and LoaderResolverInterface respectively as its first and second argument.');
} }
public function testLoadDefaultOptions()
{
$controllerNameParser = $this->getMockBuilder(ControllerNameParser::class)
->disableOriginalConstructor()
->getMock();
$loaderResolver = $this->getMockBuilder(LoaderResolverInterface::class)
->disableOriginalConstructor()
->getMock();
$loader = $this->getMockBuilder(LoaderInterface::class)->getMock();
$loaderResolver->expects($this->once())
->method('resolve')
->willReturn($loader);
$routeCollection = new RouteCollection();
$routeCollection->add('foo', new Route('/', array(), array(), array('utf8' => false)));
$routeCollection->add('bar', new Route('/', array(), array(), array('foo' => 123)));
$loader->expects($this->once())
->method('load')
->willReturn($routeCollection);
$delegatingLoader = new DelegatingLoader($controllerNameParser, $loaderResolver, array('utf8' => true));
$loadedRouteCollection = $delegatingLoader->load('foo');
$this->assertCount(2, $loadedRouteCollection);
$expected = array(
'compiler_class' => 'Symfony\Component\Routing\RouteCompiler',
'utf8' => false,
);
$this->assertSame($expected, $routeCollection->get('foo')->getOptions());
$expected = array(
'compiler_class' => 'Symfony\Component\Routing\RouteCompiler',
'foo' => 123,
'utf8' => true,
);
$this->assertSame($expected, $routeCollection->get('bar')->getOptions());
}
/** /**
* @group legacy * @group legacy
* @expectedDeprecation Referencing controllers with foo:bar:baz is deprecated since Symfony 4.1, use "some_parsed::controller" instead. * @expectedDeprecation Referencing controllers with foo:bar:baz is deprecated since Symfony 4.1, use "some_parsed::controller" instead.