Search code examples
phpsymfonymobiletwigfallback

Symfony2 twig mobile template fallback


I need a simple way to fallback on a default template if no mobile version exists.

With some regular expressions I recognize mobile platforms and want to render a template with the following pattern:

<template_name>.mobile.html.twig

But if this template doesn't exist, I want it to automatically fallback on:

<template_name>.html.twig

which always exists.

I tried nearly all the answers from this post: Symfony 2 load different template depending on user agent properties but with no success. Unfortunately there are no version numbers referenced.

At the moment I am trying to copy and modify the default twig loader.

By the way, What I want to achieve with this is the possibility to deploy different templates for mobile devices by just adding a template of the same name and adding a .mobile.

UPDATE:

http://www.99bugs.com/handling-mobile-template-switching-in-symfony2/ This one is also a good approach. It modifies the format property of the request object which affects the automatic template guessing when you don't specify a template in the controller with the render function (or annotation) but just return an array.

Resulting template name:

view/<controller>/<action>.<request format>.<engine>

So you could switch the request format from html to mobile.html based on the device detection. The downside of this is that every template needs a mobile.html pendant (which then could just include the non-mobile version if not needed).

UPDATE:

Besides using a custom templating provider there is also the possibility to hook into the kernel.view event.


Solution

  • You could create a service to handle it and then use it in the same way that you do the templating service like so..

    Create a service with the templating and request service injected into it..

    Service (YAML)

    acme.templating: 
        class: Acme\AcmeBundle\Templating\TemplatingProvider
        scope: request
        arguments:
            - @templating
            - @request // I assume you use request in your platform decision logic,
                       // otherwise you don't needs this or the scope part
            - 'html' 
    

    Class

    class TemplatingProvider
    {
        private $fallback;
        private $platform;
        ... __construct($templating, $request, $fallback) etc
    
        private function setPlatform() ... Your platform decision logic
    
        private function getPlatform()
        {
            if (null === $this->platform) {
                $this->setPlatform();
            }
    
            return $this->platform;
        }
    
        private function getTemplateName($name, $platform)
        {
            if ($platform === 'html') {
                return $name;
            }
    
            $template = explode('.', $name);
    
            $template = array_merge(
                array_slice($template, 0, -2),
                array($platform),
                array_slice($template, -2)
            );
    
            return implode('.', $template);
        }
    
        public function renderResponse($name, array $parameters = array())
        {
            $newname = $this->getTemplateName($name, $this->getPlatform());
    
            if ($this->templating->exists($newname)) {
                return $this->templating->render($newname);
            }
    
            return $this->templating->renderResponse($this->getTemplateName(
                                                    $name, $this->fallback));
        }
    

    And then you could just call your templating service instead of the current one..

    return $this->container->get('acme.templating')
                              ->renderResponse('<template_name>.html.twig', array());