Symfony2: Change rendered view with a listener

后端 未结 4 1805
谎友^
谎友^ 2020-12-25 09:04

I would like to render different views in different context in my Symfony2 project. I\'m using multiple routes for the same actions and I would like to render a different pa

相关标签:
4条回答
  • 2020-12-25 09:30

    It seems your device detection is done before you come to your route, so I bet you expect that mobile user will use the mobile routes thanks to some detection before the request, this seems to be painful to deal with in every templates and url generation.

    May be better to detect device either before or later (thanks to Categorizr or some nice apache configuration) but not relying on used route for the mobile detection.

    An integration of Categorizr with that way of calling templates rendering might be nice.

    Then using a nice bundle for using the right templates/themes or using one which provides some more generic functions

    0 讨论(0)
  • 2020-12-25 09:32

    You can add "@templating" service as argument for the controller.pre_execute_listener.

    0 讨论(0)
  • 2020-12-25 09:36

    Worth noting: The accepted solution doesn't actually work if you directly return a Response-object (e.g. when you call $this->render()), because the kernel.view event is not fired in that case:

    If the controller doesn't return a Response object, then the kernel dispatches another event - kernel.view.

    — see Symfony's HTTP Kernel Docs

    I couldn't work out a way around this, but found another interesting solution for the same problem: You could simply extend twig's render engine like the ZenstruckMobileBundle does or write your own file locator like the LiipThemeBundle.

    [edit:] Alternatively you could also override the TemplateNameParser.

    0 讨论(0)
  • 2020-12-25 09:41

    Here is the solution:

    First I have to listen to kernel.view, not kernel.controller.

    Then I use the "@templating" service (Thanks Marko Jovanovic for the hint)

    So here is my new config.yml:

    services:
        controller.pre_execute_listener:
            class: MyProject\MyBundle\Listener\ControllerListener
            arguments: ["@templating"]
            tags:
                    - { name: kernel.event_listener, event: kernel.view, method: preExecute }
    

    Finally here is my listener preExecute function

    public function preExecute(\Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent $event){
        //result returned by the controller
        $data = $event->getControllerResult();
    
        /* @var $request  \Symfony\Component\HttpFoundation\Request */
        $request =  $event->getRequest();       
        $template = $request->get('_template');
        $route = $request->get('_route');
    
        if(substr($route,0,7) == 'mobile_'){
            $newTemplate = str_replace('html.twig','mobile.html.twig',$template);
    
            //Overwrite original template with the mobile one
            $response = $this->templating->renderResponse($newTemplate, $data);
            $event->setResponse($response);
        }
    }
    

    Hope this helps!

    J.

    0 讨论(0)
提交回复
热议问题