如何通过条件来限制路由匹配

3.4 版本
维护中的版本

如同你看到的,创建出来的路由可以只匹配特定的路由通配符(通过正则表达式)、HTTP方法,或是主机名。但是路由系统通过使用“条件”(condition)还可以扩展到一种“近乎无限”的灵活性:

1
2
3
4
contact:
    path:     /contact
    defaults: { _controller: AcmeDemoBundle:Main:contact }
    condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'"
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">
 
    <route id="contact" path="/contact">
        <default key="_controller">AcmeDemoBundle:Main:contact</default>
        <condition>context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'</condition>
    </route>
</routes>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
 
$collection = new RouteCollection();
$collection->add('contact', new Route(
    '/contact', array(
        '_controller' => 'AcmeDemoBundle:Main:contact',
    ),
    array(),
    array(),
    '',
    array(),
    array(),
    'context.getMethod() in ["GET", "HEAD"] and request.headers.get("User-Agent") matches "/firefox/i"'
));
 
return $collection;

condition是一个表达式,你可以了解更多关于该表达式的语法。有了这个,该路由就不匹配了,除非HTTP方法是GET或HEAD,又或者User-Agent头是firefox

你可以在表达式中做出你所需要的任意复杂逻辑,利用传递到表达式的两个变量即可:

context:

一个RequestContext的实例,包含了被匹配的路由大部分的基础信息。


request:

symfony的Request对象。(参考Request

当生成一个URL时,毋须 顾及Conditions。

表达式被编译成PHP

在幕后,表达式被编译成原始的PHP,我们的例子会在缓存目录下生成如下PHP:

1
2
3
4
5
6
if (rtrim($pathinfo, '/contact') === '' && (
    in_array($context->getMethod(), array(0 => "GET", 1 => "HEAD"))
    && preg_match("/firefox/i", $request->headers->get("User-Agent"))
)) {
    // ...
}

正因为如此,condition键并没有在它提供幕后用于执行的PHP时,产生额外的开销。

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)