Symfony 2 carrega um modelo diferente dependendo das propriedades do agente do usuário

É possível (e como)

  • determine se um usuário está usando um dispositivo móvel
  • force o symfony 2 para carregar o modelo diferente nesse caso
  • (e recuar o modelo padrão html)

O que gostar de fazer é, carregar modelos diferentes sem modificar nenhum controlador.

ATUALIZAR

Não foi a parte de detecção a questão real aqui, realmente não tem nada a ver com symfony. Pode ser feito (carregar modelo diferente) em um nível de controlador:

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

Mas pode ser feito globalmente? Como um serviço, ou algo que executa antes de cada pedido, e faça mudanças nas regras de modelos.

Ok, então eu não tenho uma solução completa, mas um pouco mais do que procurar por um 🙂

Você pode especificar carregadores (serviços) para o item de modelo em 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: ~ 

Em seguida, defina o serviço de carregador mencionado:

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

Depois disso, defina sua class de serviço de carregador:

 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 você pode ver, esta não é a solução completa, mas espero que isso, pelo menos, aponte para a direção certa.

EDIT: acabei de descobrir que existe um pacote com resources de detecção de dispositivos móveis, com mecanismo de twig personalizado que processa o arquivo de modelo dependendo de um dispositivo que enviou o pedido ZenstruckMobileBundle , embora eu nunca usei assim … 🙂

Bem, você pode usar LiipThemeBundle .

Você pode utilizar o ouvinte de events kernel.view . Este evento vem à ação quando o controlador retorna nenhuma resposta, apenas dados. Você pode configurar a resposta de acordo com a propriedade do agente do usuário. Por exemplo

No seu controlador,

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

E o seu ouvinte de evento kernel.view ,

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

Definição do serviço,

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

Foi o que fez o truque para mim no Symfony 2.0:

Substitua o serviço twig.loader para que possamos definir nossa class personalizada:

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

E crie nossa class personalizada, que apenas define o formato “mob” para os modelos no caso de o cliente ser um dispositivo móvel:

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

Gostaria de sugerir que este não é melhor tratado pelo controlador, mas por consultas de mídia CSS e que serve uma folha de estilo separada para diferentes classs de dispositivos com base nos resultados dessa consulta de mídia CSS. Uma boa introdução aqui: http://www.adobe.com/devnet/dreamweaver/articles/introducing-media-queries.html

e eu tentaria ler http://www.abookapart.com/products/responsive-web-design em grande detalhe. Algum pensamento foi feito desde que o livro foi publicado, mas isso irá ajudá-lo na direção certa.

Das minhas experiências, você pode, mas, especificando um formato em primeiro lugar – verifique esses documentos , eles podem ajudá-lo

Eu acho que não tem nada a ver com symfony. Os modelos são para a VISTA. Você pode conseguir isso usando diferentes CSS para o mesmo modelo para obter um layout diferente (modelo). Estou usando jQuery e CSS para lidar com diferentes dispositivos. Você pode querer ver algum código-fonte da UI de http://themeforest.net/ ; especificamente este modelo . Este é um dispositivo diferente.