将 Edge Side Includes 放入我的模板是一种好习惯吗? [英] Is it good practice to put Edge Side Includes into my templates?

查看:25
本文介绍了将 Edge Side Includes 放入我的模板是一种好习惯吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我们的 Symfony2 应用程序中,我们使用 render_esi 渲染可重用的块.我们有这种模板:

{% for products as product %}<div class="product"><h4>{{ product.name }}</h4><div class="ratings">{{ render_esi(controller('AcmeDemoCommunityBundle:Rating:ratingStars', {对象类型:'产品',objectId:product.id,只读:真})) }}

{% 结束为 %}

因为我们也在产品的详细信息页面中使用了 render_esi.

解决方案

我想区分不同类型的块:

  • 呈现同一控制器的其他操作的块.
  • 可以在应用程序的其他部分使用的块.

有什么区别?

仅呈现与父模板相同控制器的其他操作的块在大多数情况下用于模块化一页并使部件可缓存.此块在整个应用程序中仅使用一次.

呈现评级星或评论等部分的块是一种提供特定功能的独立小部件.当前控制器对这个小部件一无所知.这种块在一个应用程序中大多被多次使用.

这对软件设计意味着什么?

这意味着我们可能希望在未来改变评论和评分的工作方式.将来是否可能不再由 ESI 呈现,因为我们已将功能外包给第三方服务并且只需要在此处包含某种 JavaScript?还是我们直接渲染它们?

这必须由小部件决定,而不是由包含小部件的部分决定.

那么我可以做些什么来改进我的设计?

您可以继续使用 ESI(因为它对您的用例有意义),但您应该更改模块在 Twig 文件中的包含方式.您应该将模板中的逻辑移到 AcmeDemoCommunityBundle 中的一个单独的 Twig 扩展中.

命名空间 Acme\DemoCommunityBundle\Twig;使用 Symfony\Component\HttpKernel\Fragment\FragmentHandler;使用 Symfony\Component\HttpKernel\Controller\ControllerReference;使用 Acme\DemoCommunityBundle\Rating\RateableInterface;类 CommunityExtension 扩展 \Twig_Extension{/*** @var 字符串*/const RATING_ACTION = 'AcmeDemoCommunityBundle:Rating:ratingStars';/*** @var FragmentHandler*/受保护的 $handler;公共函数 __construct(FragmentHandler $handler){$this->handler = $handler;}公共函数 getFunctions(){返回数组('community_rating' =>new \Twig_Function_Method($this, 'communityRating', array('is_safe' => array('html'))),);}公共功能 communityRating(RateableInterface $object, $readOnly = false){返回 $this->handler->render(new ControllerReference(self::RATING_ACTION, array('对象类型' =>$object->getRatingType(),'objectId' =>$object->getId(),'只读' =>$只读)), 'esi', $options);}公共函数 getName(){返回社区";}}

服务:acme_community.twig.community:类:Acme\DemoCommunityBundle\Twig\CommunityExtension参数:[@fragment.handler]标签:- { 名称:twig.extension }

现在您的模板应如下所示:

{% for products as product %}<div class="product"><h4>{{ product.name }}</h4><div class="ratings">{{ community_rating(product, true) }}

{% 结束为 %}

通过这种设计,可以轻松地在我们的应用程序中使用评级星级,但​​我们也可以灵活地更改未来评级的实现方式,而无需触及使用评级的模板.

In our Symfony2 Application we render reusable blocks with render_esi. We have this kind of templates:

{% for products as product %}
<div class="product">
    <h4>{{ product.name }}</h4>
    <div class="ratings">
    {{ render_esi(controller('AcmeDemoCommunityBundle:Rating:ratingStars', {
        objectType: 'product',
        objectId: product.id,
        readOnly: true
    })) }}
    </div>
</div>
{% endfor %}

And of cause we use the render_esi also in the detail page of the product.

解决方案

I would like to differentiate different types of blocks:

What is the difference?

Blocks that only renders other actions of the same controller as the parent template are most of the times there to modularize one page and make parts cacheable. This blocks are only used one times in the whole application.

Blocks that renders parts like rating stars or comments are kind of independent widgets that provide an specific functionality. The current controller dose not know anything about this widgets. This kind of blocks are mostly used multiple times in an application.

What does that mean for the software design?

It means that we may want to change the way comments and ratings work in the future. May the not get rendered by an ESI anymore in the future because we have outsourced the functionality to an third-party service and only need to include some kind of JavaScript in this place? Or we render them directly?

This is something that has to be decided by the widget and not by the part that include the widget.

So what could I do to improve my design?

You could keep using ESI (because it makes sense for your usecase), but you should change the way of how the modules are included in the Twig files. You should move the logic for this out of the template into an separate Twig Extension in the AcmeDemoCommunityBundle.

namespace Acme\DemoCommunityBundle\Twig;

use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Acme\DemoCommunityBundle\Rating\RateableInterface;

class CommunityExtension extends \Twig_Extension
{
    /**
     * @var string
     */
    const RATING_ACTION = 'AcmeDemoCommunityBundle:Rating:ratingStars';

    /**
     * @var FragmentHandler
     */
    protected $handler;

    public function __construct(FragmentHandler $handler)
    {
        $this->handler = $handler;
    }

    public function getFunctions()
    {
        return array(
            'community_rating' => new \Twig_Function_Method($this, 'communityRating', array('is_safe' => array('html'))),
        );
    }

    public function communityRating(RateableInterface $object, $readOnly = false)
    {
        return $this->handler->render(new ControllerReference(self::RATING_ACTION, array(
            'objectType' => $object->getRatingType(),
            'objectId' => $object->getId(),
            'readOnly' => $readOnly
        )), 'esi', $options);
    }

    public function getName()
    {
        return 'community';
    }
}

services:
    acme_community.twig.community:
        class:     Acme\DemoCommunityBundle\Twig\CommunityExtension
        arguments: [ @fragment.handler ]
        tags:
            - { name: twig.extension }

Now your template should look like this:

{% for products as product %}
<div class="product">
    <h4>{{ product.name }}</h4>
    <div class="ratings">
    {{ community_rating(product, true) }}
    </div>
</div>
{% endfor %}

With this design it is easy to use the rating stars in our application, but we also have the flexibility to change the implementation how ratings work in the future without touching the templates where ratings are used.

这篇关于将 Edge Side Includes 放入我的模板是一种好习惯吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆