将Edge Side Includes放入我的模板中是一种好习惯吗?

时间:2014-05-12 11:22:35

标签: symfony twig http-caching esi

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

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

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

1 个答案:

答案 0 :(得分:2)

我想区分不同类型的块:

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

有什么区别?

只能渲染与父模板相同的控制器的其他操作的块大多数时候可以模块化一个页面并使零件可缓存。此块仅在整个应用程序中使用一次。

呈现评级星或评论等部分的块是一种提供特定功能的独立窗口小部件。目前的控制器对此小部件一无所知。这种块通常在应用程序中多次使用。

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

这意味着我们可能希望改变评论和评级在未来的工作方式。可能以后不再由ESI提供,因为我们已将功能外包给第三方服务,只需要在这个地方包含某种JavaScript?或者我们直接渲染它们?

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

那么我该怎样做才能改善我的设计?

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

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 }

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

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

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