Symfony 2 根据用户代理属性加载不同的模板

发布于 2024-12-17 20:08:39 字数 515 浏览 0 评论 0原文

是否可以(以及如何)

  • 确定用户是否使用移动设备
  • 在这种情况下强制 symfony 2 加载不同的模板
  • (并回退默认的 html 模板)< br>

id 喜欢做的是,在不修改任何控制器的情况下加载不同的模板。

更新

这里真正的问题不是检测部分,它实际上与 symfony 无关。它可以在控制器级别完成(加载不同的模板):

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

但是可以在全局范围内完成吗?就像服务,或者在每个请求之前执行的东西,并在模板规则中进行更改。

Is it possible (and how) to

  • determine if a user is using a mobile device
  • force symfony 2 to load different template in that case
  • (and fall back the default html template)

What id like to do is, to load different templates without modifying any controller.

UPDATE

It wasn't the detection part the real issue here, it's really nothing to do with symfony. It can be done (load different template) on a controller level:

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

But can it be done globally? Like a service, or something that execute before every request, and make changes in the templating rules.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

夏夜暖风 2024-12-24 20:08:39

好的,所以我没有完整的解决方案,但比在哪里寻找一个解决方案多一点:)

您可以在 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:         ~

然后定义提到的加载程序服务:

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

之后定义您的加载程序服务类:

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

如您所见,这不是完整的解决方案,但我希望这至少能为您指明正确的方向。

编辑:刚刚发现有一个具有移动检测功能的捆绑包,带有自定义树枝引擎,可根据发送请求的设备呈现模板文件
ZenstruckMobileBundle,虽然我从来没有用过它......:)

Ok, so I don't have a full solution but a little more than where to look for one :)

You can specify loaders (services) for templating item in 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:         ~

Then define the mentioned loader service:

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

After that define your loader service class:

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

As you can see this isn't the full solution, but I hope that this, at least, points you to the right direction.

EDIT: Just found out that there is a bundle with mobile detection capabilities, with custom twig engine that renders template file depending on a device that sent request
ZenstruckMobileBundle, although I never used it so... :)

初懵 2024-12-24 20:08:39

好吧,你可以使用 LiipThemeBundle

Well, you can use LiipThemeBundle.

勿忘心安 2024-12-24 20:08:39

您可以利用 kernel.view 事件监听器。当控制器未返回响应而仅返回数据时,此事件将起作用。您可以根据用户代理属性设置响应。例如

在您的控制器中,

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

    return $data;
}

以及在 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);
    }
}

服务定义中,

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

You can utilize kernel.view event listener. This event comes to action when controller returns no response, only data. You can set reponse according to user agent property. For example

In your controller,

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

    return $data;
}

And the in your kernel.view event listener,

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

Service definition,

your_view_listener.listener:
    class: FQCN\Of\Listener\Class
    arguments:    [@templating]
    tags:
        - { name: kernel.event_listener, event: kernel.view, method: onKernelView }
铃予 2024-12-24 20:08:39

这就是 Symfony 2.0 中对我有用的技巧:

覆盖 twig.loader 服务,以便我们可以设置自定义类:

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

并创建我们的自定义类,只需将“mob”格式设置为模板,以防客户端是移动设备:

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

This is what did the trick for me in Symfony 2.0:

Override twig.loader service so we can set our custom class:

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

And create our custom class, that just sets "mob" format to the templates in case the client is a mobile device:

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
    }
 }
淡淡绿茶香 2024-12-24 20:08:39

我建议这最好不是由控制器来处理,而是由 CSS 媒体查询来处理,并根据 CSS 媒体查询的结果为不同类别的设备提供单独的样式表。
这里有一个很好的介绍:
http://www.adobe.com/devnet/dreamweaver/articles /introducing-media-queries.html

我会尝试阅读 http://www.abookapart.com/products/responsive-web-design 非常详细。自本书出版以来,我们已经进行了一些思考,但它会让您朝着正确的方向前进。

I would suggest that this is not best handled by the controller but by CSS media queries, and serving a separate stylesheet to different classes of devices based on the results of that CSS media query.
A good intro here:
http://www.adobe.com/devnet/dreamweaver/articles/introducing-media-queries.html

and I would try reading http://www.abookapart.com/products/responsive-web-design in great detail. Some thinking has been done since the book was published, but it will get you headed the right direction.

書生途 2024-12-24 20:08:39

根据我的经验,您可以通过首先指定格式 - 检查这些 文档,他们也许能够帮助您

From my experiences, you can but by specifying a format in the first place - check these docs, they may be able to assist you

舟遥客 2024-12-24 20:08:39

我认为与 symfony 无关。模板用于 VIEW。您可以通过对同一模板使用不同的 CSS 来获得不同的布局(模板)来实现此目的。我使用 jQuery 和 CSS 来处理不同的设备。您可能想从 http://themeforest.net/ 查看一些 UI 源代码;特别是这个 模板。这是一种处理不同设备的方法。

I think is nothing to do with symfony. Templates are for the VIEW. You may achieve this by using different CSS for the same template to get different layout (template). I am using jQuery and CSS to handle different devices. You may want to look at some source code of the UI from http://themeforest.net/; specifically this template. This is one handles different device.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文