如何防止Symfony探查器访问或执行侦听器

时间:2014-08-18 10:11:55

标签: php symfony events profiler before-filter

我的用户拥有countTasks属性,具有相应的setter和getter:

class User implements UserInterface, \Serializable
{
    /**
     * @var integer
     */
    private $countTasks;
}

我希望此属性始终显示在应用程序的导航栏中(红色的“14”数字):

nav bar with countTasks property

显然,应该为每个控制器设置此属性。 (实际上,只针对渲染导航栏的每一个,但这不是这种情况)。因此,应用程序应为每个控制器计算当前登录用户的任务。

我在Symfony食谱中找到了一个相关主题:How to Setup before and after Filters,我设法实现了它:

Acme\TestBundle\EventListener\UserListener.php

namespace Acme\TestBundle\EventListener;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;

class UserListener
{
    public function onKernelController(FilterControllerEvent $event)
    {
        $controller = $event->getController();

        if ( ! is_array($controller)) {
            return;
        }

        $securityContext = $controller[0]->get('security.context');

        // now count tasks, but only if a user logged-in
        if ($securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED') or $securityContext->isGranted('IS_AUTHENTICATED_FULLY'))
        {
            $user = $securityContext->getToken()->getUser();

            // ...
            // countig tasks and setting $countTasks var
            // ...
            $user->setCountTasks($countTasks);
        }
    }
}

services.yml

services:
    acme.user.before_controller:
        class: Acme\TestBundle\EventListener\UserListener
        tags:
            - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }

它按预期工作,我可以在Twig模板中拉出属性,如下所示:

{{ app.user.countTasks }}

它在prod env中的预期效果 然而,在开发人员中,探查器会抛出UndefinedMethodException

  

UndefinedMethodException:尝试在... \ src \ Acme \ TestBundle \ EventListener \ UserListener.php第18行的类“Symfony \ Bundle \ WebProfilerBundle \ Controller \ ProfilerController”上调用方法“get”。

第18行是这一行:

$securityContext = $controller[0]->get('security.context');

作为快速补丁,我添加了额外的检查(第18行之前),以防止探查器执行进一步的逻辑:

    if (is_a($controller[0], '\Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController'))
    {
        return;
    }

    $securityContext = $controller[0]->get('security.context');

它已经成功了。但我担心这不是正确的方法。我也担心我在分析器中丢失了部分调试信息。

我对我的担忧是对的吗?你能指点我一个更好的方法来阻止探查器执行这个监听器吗?在配置中某种程度?

2 个答案:

答案 0 :(得分:2)

即使在Symfony的文档How to Setup before and after Filters中,第29行也是instanceof condition is being evaluated

我会说,如果医生正在这样做,你自己做得很安全(除非另有说明,但事实并非如此)。

答案 1 :(得分:1)

一开始我试图反过来解决这个问题。在测试期间,我发现我必须排除其他一些核心控制器。当然,我应该只允许所需的控制器,而不是阻止不需要的控制器。

我最终创建了一个空接口UserTasksAwareController

namespace Acme\TestBundle\Controller;

interface UserTasksAwareController
{}

UserListener.php中确定有效性检查:

if ( ! $controllers[0] instanceof UserTasksAwareController) {
    return;
}

并在处理显示countTasks属性的每个其他控制器中实现它,如下所示:

class UserController extends Controller implements UserTasksAwareController

所以,当你忘记编程接口而不是实现时,我遇到的问题只是另一个问题。