如何使用Matchers来有条件地开启Profiler分析器

3.4 版本
维护中的版本

Symfony profiler(译注:框架web除错工具条中的调试分析器)仅在开发环境下被激活并且不影响你的程序性能。但是有时,在生产环境的某些条件下开启它可能有利于帮助你发现问题。这种行为要去实现Request Matchers

使用内置Matcher时 

请求匹配器(request matcher)是一个类,检查给定的Request实例是否匹配一组条件。Symfony提供了 built-in matcher 用来匹配路径和IP。例如,如果你只想在使用 168.0.0.1 这个IP来访问页面时才显示profiler,那么你应该使用以下配置:

1
2
3
4
5
6
# app/config/config.yml
framework:
    # ...
    profiler:
        matcher:
            ip: 168.0.0.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony
        http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
>
 
    <framework:config>
        <!-- ... -->
        <framework:profiler ip="168.0.0.1" />
    </framework:config>
</container>
1
2
3
4
5
6
7
// app/config/config.php
$container->loadFromExtension('framework', array(
    // ...
    'profiler' => array(
        'ip' => '168.0.0.1',
    ),
));

你也可以设置一个path选项来定义分析器被开启时所应基于的路径。例如,设置它为^/admin/,则分析器仅在/admin/开头的URL中才会开启。

创建自定义Matcher时 

利用“请求匹配器”这一概念,你可以在程序中定义一个自定义matcher,来有条件的开启分析器。要实现这个,先创建一个类去实现 RequestMatcherInterface 接口。这个接口需要一个方法:matches()。当请求不匹配条件时该方法返回 false ,否则是 true。因此,自定义的matcher必须返回 false 以关闭分析器,返回 true 则开启它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// src/AppBundle/Profiler/SuperAdminMatcher.php
namespace AppBundle\Profiler;
 
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
 
class SuperAdminMatcher implements RequestMatcherInterface
{
    protected $authorizationChecker;
 
    public function __construct(AuthorizationCheckerInterface $authorizationChecker)
    {
        $this->authorizationChecker = $authorizationChecker;
    }
 
    public function matches(Request $request)
    {
        return $this->authorizationChecker->isGranted('ROLE_SUPER_ADMIN');
    }
}

然后,配置一个新的服务并将其设为private,因为程序并不直接使用它:

1
2
3
4
5
6
# app/config/services.yml
services:
    app.super_admin_matcher:
        class: AppBundle\Profiler\SuperAdminMatcher
        arguments: ['@security.authorization_checker']
        public: false
1
2
3
4
5
6
<!-- app/config/services.xml -->
<services>
    <service id="app.profiler.matcher.super_admin"
        class="AppBundle\Profiler\SuperAdminMatcher" public="false">
        <argument type="service" id="security.authorization_checker" />
</services>
1
2
3
4
5
6
7
8
9
10
11
// app/config/services.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
 
$definition = new Definition(
    'AppBundle\Profiler\SuperAdminMatcher',
    array(new Reference('security.authorization_checker'))
);
$definition->setPublic(false);
 
$container->setDefinition('app.super_admin_matcher', $definition);

一旦服务被注册,剩下唯一要做的,就是配置profiler,让它把这个服务作为matcher:

1
2
3
4
5
6
# app/config/config.yml
framework:
    # ...
    profiler:
        matcher:
            service: app.super_admin_matcher
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony
        http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
>
 
    <framework:config>
        <!-- ... -->
        <framework:profiler service="app.super_admin_matcher" />
    </framework:config>
</container>
1
2
3
4
5
6
7
// app/config/config.php
$container->loadFromExtension('framework', array(
    // ...
    'profiler' => array(
        'service' => 'app.super_admin_matcher',
    ),
));

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

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