2011-11-24 17 views
24

¿Es posible (y cómo) aSymfony 2 carga diferente plantilla en función de las propiedades del agente de usuario

  • determinar si un usuario está utilizando un dispositivo móvil
  • fuerza symfony 2 a carga diferente plantilla en ese caso
  • (y caer de nuevo la plantilla hTML por defecto)

lo que como seria do es, cargar diferentes plantillas sin modificar ningún controlador.

ACTUALIZACIÓN

No era la parte de detección del verdadero problema aquí, es realmente nada que ver con Symfony. Se puede hacer (cargar una plantilla diferente) en un nivel de controlador:

public function indexAction() 
{ 
    $format = $this->isMobile() ? 'mob' : 'html'; 
    return $this->render('AcmeBlogBundle:Blog:index.'.$format.'.twig'); 
} 

¿Pero se puede hacer de forma global? Como un servicio, o algo que se ejecuta antes de cada solicitud, y hacer cambios en las reglas de plantillas.

+0

No estoy seguro de que la solución esté relacionada con el marco. ¿Ha realizado la compra http://www.hand-interactive.com/resources/detect-mobile-php.htm#download? – FMaz008

Respuesta

22

Ok, así que no tengo una solución completa, pero un poco más de dónde buscar una :)

Puede especificar cargadores (servicios) para el punto de plantillas en app/config/config.yml

framework: 
    esi:    { enabled: true } 
    #translator:  { fallback: %locale% } 
    secret:   %secret% 
    router: 
     resource: "%kernel.root_dir%/config/routing.yml" 
     strict_requirements: %kernel.debug% 
    form:   true 
    csrf_protection: true 
    validation:  { enable_annotations: true } 
    templating:  
     engines: 
      - twig 
     loaders: [moby.loader] 
    default_locale: %locale% 
    trust_proxy_headers: false 
    session:   ~ 

A continuación, defina el servicio del cargador mencionado:

services: 
    moby.loader: 
     class: Acme\AppBundle\Twig\Loader\MobyFilesystemLoader 
     arguments: ["@templating.locator", "@service_container"] 

Después de eso definir su servicio de cargador de clases:

namespace Acme\AppBundle\Twig\Loader; 

use Symfony\Bundle\FrameworkBundle\Templating\Loader\FilesystemLoader; 
use Symfony\Component\Templating\Storage\FileStorage; 


class MobyFilesystemLoader extends FilesystemLoader 
{ 
    protected $container; 

    public function __construct($templatePathPatterns, $container) 
    { 
     parent::__construct($templatePathPatterns); 
     $this->container = $container; 
    } 

    public function load(\Symfony\Component\Templating\TemplateReferenceInterface $template) 
    { 
     // Here you can filter what you actually want to change from html 
     // to mob format 
     // ->get('controller') returns the name of a controller 
     // ->get('name') returns the name of the template 
     if($template->get('bundle') == 'AcmeAppBundle') 
     { 
      $request = $this->container->get('request'); 
      $format = $this->isMobile($request) ? 'mob' : 'html'; 

      $template->set('format', $format); 
     } 

     try { 
      $file = $this->locator->locate($template); 
     } catch (\InvalidArgumentException $e) { 
      return false; 
     } 

     return new FileStorage($file); 
     } 

     /** 
     * Implement your check to see if request is made from mobile platform 
     */ 
     private function isMobile($request) 
     { 
      return true; 
     } 
} 

Como puede ver, esta no es la solución completa, pero espero que esto, al menos, lo guíe en la dirección correcta.

EDIT: acabo de enterar que hay un paquete con capacidades de detección de móviles, con el motor ramita personalizado que hace que el archivo de plantilla en función de un dispositivo que envía la solicitud ZenstruckMobileBundle, aunque nunca he usado así que ... :)

+1

FYI ZenstruckMobileBundle link is down. Sin embargo, esto funciona: [http://zenstruck.com/projects/ZenstruckMobileBundle](http://zenstruck.com/projects/ZenstruckMobileBundle) –

+0

También hay https://github.com/suncat2000/MobileDetectBundle que le brinda la herramienta por eso también –

0

De mis experiencias, se puede, pero especificando un formato en el primer lugar - comprobar estos docs, que puede ser capaz de ayudarle

0

Creo que es nada que ver con Symfony. Las plantillas son para la VISTA. Puede lograr esto utilizando diferentes CSS para la misma plantilla para obtener un diseño diferente (plantilla). Estoy usando jQuery y CSS para manejar diferentes dispositivos. Es posible que desee consultar algún código fuente de la interfaz de usuario desde http://themeforest.net/; específicamente este template. Este es uno maneja un dispositivo diferente.

1

Sugeriría que el controlador no lo maneje mejor, pero sí las consultas de medios de CSS y que se sirva una hoja de estilos separada para diferentes clases de dispositivos en función de los resultados de esa consulta de medios CSS. Una buena introducción aquí: http://www.adobe.com/devnet/dreamweaver/articles/introducing-media-queries.html

y yo intentaría leer http://www.abookapart.com/products/responsive-web-design con gran detalle. Se han hecho algunas reflexiones desde la publicación del libro, pero te llevará en la dirección correcta.

3

Puede utilizar el detector de eventos kernel.view. Este evento entra en acción cuando el controlador no devuelve respuesta, solo datos. Puede establecer una respuesta de acuerdo con la propiedad del agente de usuario. Por ejemplo

En su controlador,

public function indexAction() 
{ 
    $data = ... //data prepared for view 
    $data['template_name'] = "AcmeBlogBundle:Blog:index"; 

    return $data; 
} 

Y el detector de eventos en su kernel.view,

<?php 

namespace Your\Namespace; 

use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; 
use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\Templating\EngineInterface; 

Class ViewListener 
{ 
    /** 
    * @var EngineInterface 
    */ 
    private $templating; 

    public function __construct(EngineInterface $templating) 
    { 
     $this->templating = $templating; 
    } 

    public function onKernelView(GetResponseForControllerResultEvent $event) 
    { 
     $data = $event->getControllerResult(); //result returned by the controller 
     $templateName = $data['template_name']; 

     $format = $this->isMobile() ? 'mob' : 'html'; //isMobile() method may come from a injected service 
     $response = $this->templating->renderResponse($templateName . "." . $format . "twig", $data); 

     $event->setResponse($response); 
    } 
} 

Definición de servicio,

your_view_listener.listener: 
    class: FQCN\Of\Listener\Class 
    arguments: [@templating] 
    tags: 
     - { name: kernel.event_listener, event: kernel.view, method: onKernelView } 
2

Esto es lo que hizo el truco para mí en Symfony 2.0:

Anulación servicio twig.loader para que podamos establecer nuestra clase personalizada:

twig.loader: 
    class: Acme\AppBundle\TwigLoader\MobileFilesystemLoader 
    arguments: 
     locator: "@templating.locator" 
     parser: "@templating.name_parser" 

Y crear nuestra clase personalizada, que acaba de juegos de formatos "mafia" a las plantillas en caso de que el cliente es un dispositivo móvil:

namespace Acme\AppBundle\TwigLoader; 

use Symfony\Bundle\TwigBundle\Loader\FilesystemLoader; 

class MobileFilesystemLoader extends FilesystemLoader 
{ 

    public function findTemplate($template) 
    { 
     if ($this->isMobile()) { 
      $template->set('format', 'mob'); 
     } 

     return parent::findTemplate($template); 
    } 


    private function isMobile() 
    { 
     //do whatever to detect it 
    } 
} 
Cuestiones relacionadas