不能绑定内核.查看EventListener到FOSUserBundle



我使用kernel.view Event Listener将移动请求和web请求分开。

逻辑是这样的:

  • 如果请求来自移动设备,则加载xxx.mobile.twig
  • 如果请求来自web,则加载xxx.html.twig

这是工作与我的CustomBundle没有任何问题。除此之外,我使用FOSUserBundle和HWIOAuthBundle与他们的一些路由。我检查了var/logs/dev.log,我看不到kernel.view事件关于这些束路由,最终我的监听器不能与这些束一起工作。

你能给我一个主意,我怎么才能绑定到kernel.view事件为那些捆绑?

/**
 * @param GetResponseForControllerResultEvent $event
 * @return bool
 */
public function onKernelView(GetResponseForControllerResultEvent $event)
{
    if (!$this->isMobileRequest($event->getRequest()->headers->get('user-agent'))) {
        return false;
    }
    $template = $event->getRequest()->attributes->get('_template');
    if (!$template) {
        return false;
    }
    $templateReference = $this->templateNameParser->parse($template);
    if ($templateReference->get('format') == 'html' && $templateReference->get('bundle') == 'CustomBundle') {
        $mobileTemplate = sprintf(
            '%s:%s:%s.mobile.twig',
            $templateReference->get('bundle'),
            $templateReference->get('controller'),
            $templateReference->get('name')
        );
        if ($this->templating->exists($mobileTemplate)) {
            $templateReference->set('format', 'mobile');
            $event->getRequest()->attributes->set('_template', $templateReference);
        }
    }
}

在Symfony2上调试与事件相关的问题时,您应该考虑几件事。

  1. 事件传播可以停止

    • 可能是另一个侦听器正在侦听相同的事件,并通过调用$event->stopPropagation()来停止事件传播。在这种情况下,确保先执行侦听器(参见下面的第2点)。
  2. 事件监听器有优先级

    • 定义侦听器时,可以设置其优先级,如下所示:

    view_response_listener:
        class: AppBundleEventListenerViewResponseListener
        tags:
            # The highest the priority, the earlier a listener is executed
            # @see http://symfony.com/doc/2.7/cookbook/event_dispatcher/event_listener.html#creating-an-event-listener
            - { name: kernel.event_listener, event: kernel.view, method: onKernelView, priority: 101 }
    

    另一个可选标记属性称为priority,默认值为0,它控制侦听器执行的顺序(优先级越高,侦听器执行得越早)。当您需要保证一个侦听器在另一个侦听器之前执行时,这很有用。内部Symfony侦听器的优先级通常在-255到255之间,但您自己的侦听器可以使用任何正整数或负整数。

    来源:http://symfony.com/doc/2.7/cookbook/event_dispatcher/event_listener.html创建一个实践监听器

  3. 通常这些事件的调度是在引导文件中完成的

    • 确保重新生成你的引导文件(并清除缓存,现在你在它!),特别是如果你玩的优先级和/或你的配置。

    composer run-script post-update-cmd
    php app/console cache:clear --env=dev
    

    作曲家post-update-cmd将重新生成你的引导文件,但它也会做其他事情,如重新安装你的资产,这可能是你不需要的东西。要重新生成引导文件,请查看我的答案。

我找到了解决方案,但是有点变通,现在工作正常。

我把下面的函数到我的MobileTemplateListener.php文件。更多细节在这里-> http://www.99bugs.com/handling-mobile-template-switching-in-symfony2/

    /**
 * @param GetResponseEvent $event
 */
public function onKernelRequest(GetResponseEvent $event)
{
    $request = $event->getRequest();
    if ($this->isMobileRequest($request->headers->get('user-agent')))
    {
        //ONLY AFFECT HTML REQUESTS
        //THIS ENSURES THAT YOUR JSON REQUESTS TO E.G. REST API, DO NOT GET SERVED TEXT/HTML CONTENT-TYPE
        if ($request->getRequestFormat() == "html")
        {
            $request->setRequestFormat('mobile');
        }
    }
}
/**
 * Returns true if request is from mobile device, otherwise false
 * @return boolean mobileUA
 */
private function isMobileRequest($userAgent)
{
    if (preg_match('/(android|blackberry|iphone|ipad|phone|playbook|mobile)/i', $userAgent)) {
        return true;
    }
    return false;
}
因此,当kernel.request事件侦听器开始处理时,它正在设置值为mobile 的格式。

我使用FOSUserBundle通过一个子bundle来操作我的需要。你可以在这里找到更多的细节-> https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/doc/overriding_controllers.md

为例:我们假设SecurityController.php我在UserBundle下创建了一个名为SecurityController.php的文件,如下所示:

<?php
namespace AcmeUserBundleController;
use SymfonyComponentHttpFoundationRedirectResponse;
use FOSUserBundleControllerSecurityController as BaseController;
use SymfonyComponentHttpFoundationRequest;
use AcmeUserBundleOverridesControllerOverrideRenderTrait;
class SecurityController extends BaseController
{
    use ControllerOverrideRenderTrait;
    public function loginAction(Request $request)
    {
        $securityContext = $this->container->get('security.context');
        $router = $this->container->get('router');
        if ($securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
            return new RedirectResponse($router->generate('my_profile_dashboard'), 307);
        }
        return parent::loginAction($request);
    }
}

对于所有其他FOS控制器,我必须重写渲染函数。由smyfony SymfonyBundleFrameworkBundleController

提供

但是我的子bundle已经扩展了FOSUserBundle的控制器,要覆盖它而不重复代码的唯一方法就是使用traits。

,我创建了一个如下的特征。

    <?php
namespace AcmeUserBundleOverrides;
use SymfonyComponentHttpFoundationResponse;
trait ControllerOverrideRenderTrait {
    /**
     * This overrides vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php
     * Renders a view.
     *
     * @param string   $view       The view name
     * @param array    $parameters An array of parameters to pass to the view
     * @param Response $response   A response instance
     *
     * @return Response A Response instance
     */
    public function render($view, array $parameters = array(), Response $response = null)
    {
        $format = $this->getRequest()->getRequestFormat();
        $view = str_replace('.html.', '.' . $format . '.', $view);
        return $this->container->get('templating')->renderResponse($view, $parameters, $response);
    }
}

symfony提供的原始功能如下:

    /**
 * Renders a view.
 *
 * @param string   $view       The view name
 * @param array    $parameters An array of parameters to pass to the view
 * @param Response $response   A response instance
 *
 * @return Response A Response instance
 */
public function render($view, array $parameters = array(), Response $response = null)
{
    return $this->container->get('templating')->renderResponse($view, $parameters, $response);
}

基本上我的改变取代了'.html.'部分在模板名称提供$format,通过onKernelRequest EventListener设置。

别忘了在services.yml

中添加你的服务定义
services:
    acme.frontend.listener.mobile_template_listener:
        class: AcmeFrontendBundleEventListenerMobileTemplateListener
        arguments: ['@templating', '@templating.name_parser']
        tags:
            - { name: kernel.event_listener, event: kernel.view, method: onKernelView }
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

最新更新