web-dev-qa-db-fra.com

Symfony 2 charge un modèle différent en fonction des propriétés de l'agent utilisateur

Est-il possible (et comment) de

  • déterminer si un utilisateur utilise un appareil mobile
  • obliger symfony 2 à charger un modèle différent dans ce cas
  • (et récupère le modèle HTML par défaut)

Ce que j’aime faire, c’est de charger différents modèles sans modifier aucun contrôleur.

METTRE À JOUR

Le vrai problème ici, ce n’était pas la détection, c’est vraiment rien à voir avec symfony. Cela peut être fait (charger un modèle différent) au niveau du contrôleur:

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

Mais cela peut-il être fait globalement? Comme un service, ou quelque chose qui s'exécute avant chaque requête et modifie les règles du modèle.

25
user1063963

Ok, donc je n'ai pas de solution complète mais un peu plus que l'endroit où en chercher une :)

Vous pouvez spécifier des chargeurs (services) pour les éléments de gabarit dans 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:         ~

Définissez ensuite le service de chargement mentionné:

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

Après cela, définissez votre classe de service de chargeur:

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;
       }
 }

Comme vous pouvez le constater, cette solution n’est pas complète, mais j’espère que cela vous aidera au moins à aller dans la bonne direction.

EDIT: Je viens de découvrir qu’il existe un ensemble de fonctionnalités de détection mobile, avec un moteur de brindille personnalisé qui rend le fichier de modèle en fonction du périphérique qui a envoyé la demande ZenstruckMobileBundle , bien que je ne l’aie jamais utilisé alors ... :)

23
Marko Jovanović

Eh bien, vous pouvez utiliser LiipThemeBundle .

6
Henrik Bjørnskov

Vous pouvez utiliser l'écouteur d'événements kernel.view. Cet événement se déclenche lorsque le contrôleur ne renvoie aucune réponse, uniquement des données. Vous pouvez définir la réponse en fonction de la propriété de l'agent utilisateur. Par exemple

Dans votre contrôleur,

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

    return $data;
}

Et le dans votre écouteur d'événements 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);
    }
}

Définition du service,

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

C’est ce qui m’a joué dans Symfony 2.0:

Remplacez le service twig.loader afin que nous puissions définir notre classe personnalisée:

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

Et créez notre classe personnalisée, qui définit simplement le format "mob" sur les modèles dans le cas où le client est un appareil mobile:

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
    }
 }
2
nachopas

Je suggérerais que cela ne soit pas mieux géré par le contrôleur, mais par les requêtes de média CSS, et de servir une feuille de style séparée à différentes classes de périphériques en fonction des résultats de cette requête de média CSS. Une bonne introduction ici: http://www.Adobe.com/devnet/dreamweaver/articles/introducing-media-queries.html

et je voudrais essayer de lire http://www.abookapart.com/products/responsive-web-design en détail. Certaines réflexions ont été faites depuis la publication du livre, mais cela vous mènera dans la bonne direction.

1
Jeremy Anderson
0
ihsan

Je pense qu'il n'y a rien à voir avec symfony. Les modèles sont pour la vue. Vous pouvez y parvenir en utilisant différentes CSS pour le même modèle afin d’obtenir une présentation différente (modèle). J'utilise jQuery et CSS pour gérer différents périphériques. Vous voudrez peut-être consulter un code source de l'interface utilisateur à partir de http://themeforest.net/ ; spécifiquement ce template . Ceci est l'un gère un périphérique différent.

0
PMoubed

D'après mes expériences, vous pouvez, mais en spécifiant tout d'abord un format - vérifiez ces docs , ils pourront peut-être vous aider.

0
Matt