将自定义逻辑添加到内部Symfony类,如SwitchUserListener或TemplateGuesser

tim*_*hew 5 dependency-injection symfony symfony-2.3

我在向某些Symfony类添加自定义逻辑时遇到了问题.

SwitchUserListener

我想添加一个检查,用户无法切换到另一个用户,该用户拥有比初始用户更多的权限/角色.

第一次尝试

security_listeners.xml使用键覆盖参数: security.authentication.switchuser_listener.class但是我可以在哪里覆盖它?
在security.yml中,它不起作用:

security:
    ...
    authentication:
        switchuser_listener:
             class:  Symfony\Component\Security\Http\Firewall\SwitchUserListener
Run Code Online (Sandbox Code Playgroud)

第二次尝试

覆盖SwitchUserListner服务标识的服务:security.authentication.switchuser_listener

我在我的bundle的service.xml中创建了相同的服务,但我的类没有被使用/调用.

另一个想法是只覆盖类,但这只适用于bundle,但SwitchUserListener不在SecurityBundle中,它位于symfony组件目录中,在我看来,覆盖SecurityBundle是一个非常糟糕的主意

第三次尝试

现在我得到了解决方案:第一次我没有意识到调度程序在SwitchUserListener中为SWTICH_USER事件调用侦听器:

$switchEvent = new SwitchUserEvent($request, $token->getUser());
$this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent);
Run Code Online (Sandbox Code Playgroud)

所以我只需要为这个事件类型创建一个带有特殊标记的服务:

<tag name="kernel.event_listener" event="security.switch_user" method="onSecuritySwitchUser" />
Run Code Online (Sandbox Code Playgroud)

并检查给定的方法.

这似乎是另一个更好的解决方案.但仍有问题.在我的SwitchUserEvent监听器中,如果用户想要退出切换用户,我需要忽略我的自定义检查.所以我需要检查请求的路径:ignore if path containts '?switch_user=_exit'
但是路径(URL参数)可以改变:

# app/config/security.yml
security:
    firewalls:
        main:
            # ...
            switch_user: { role: ROLE_ADMIN, parameter: _want_to_be_this_user }
Run Code Online (Sandbox Code Playgroud)

但在我的包中我无法读取此参数,因为它不会被传递给service container.它将被传递给SwitchUserListner类的构造函数,并将作为私有属性保存在那里,永远不能从外部访问(没有Reflection).(发生在这里:SecurityExtension.php第591行)那么该怎么办?定义参数两次与DRY相反.用反射?

另一点是,每次我写一个订阅者类时都会触发事件.那么它的另一个/最佳解决方案是什么?
我问这个问题是因为我想在添加或覆盖某些symfony实习生组件的地方遇到类似的问题.

TemplateGuesser

我想修改TemplateGuesser:对于特定的包,所有具有注释@Tempalte的模板应该在控制器TestController#showAction位于此路径的位置定位tempate文件:

Resources/views/customDir/Test/show.html.twig
Run Code Online (Sandbox Code Playgroud)

因此,应将guesser放入并将所有内容放入另一个文件夹customDir中,而不是仅使用视图.当使用render具有特定模板的函数时,猜测者应该忽略注释.

我创建了自己的Guesser并覆盖了服务ID:sensio_framework_extra.view.guesser并且与SwitchUserListener此时相比,我的类被真正调用而不是原始的猜测器.为什么它在这里工作而不是在SwitchUserListener

这是一个很好的解决方案吗?我还试图添加第二个监听器,它调用TemplateGuesser,它的服务sensio_framework_extra.view.listener与类Sensio\Bundle\FrameworkExtraBundle\EventListener\TemplateListener但是没有用.

Dan*_*iro 0

每当您需要添加自定义逻辑或扩展框架行为时,您都可以使用和滥用容器配置。这意味着你可以覆盖 Symfony 定义的几乎所有服务,只需创建一个新类来扩展该服务 \xe2\x80\x93 或不扩展该服务,实际上 \xe2\x80\x93 并使用与您想要扩展或改变行为的原始服务。

\n\n

例如,Symfony 有一个基本模板猜测器,注册为服务sensio_framework_extra.view.guesser。如果您想扩展它或更改行为,您只需创建自己的类并使用原始服务 \xe2\x80\x93 的相同 id 进行注册,请记住,捆绑包加载顺序会影响具有相同 id 的服务定义,其中最后加载的一个就是将要创建的那个。

\n\n

这应该可以解决你的两个问题。

\n