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

标签 symfony twig http-caching esi

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

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

最佳答案

我想区分不同类型的 block :

  • 呈现同一 Controller 的其他操作的 block 。
  • 可在应用程序的其他部分使用的 block 。

有什么区别?

大多数情况下,仅呈现与父模板相同的 Controller 的其他操作的 block 是为了模块化一个页面并使部分可缓存。该 block 在整个应用程序中仅使用一次。

呈现评级星星或评论等部分的 block 是一种提供特定功能的独立小部件。当前 Controller 对这个小部件一无所知。此类 block 大多在应用程序中多次使用。

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

这意味着我们将来可能希望改变评论和评分的工作方式。将来是否可以不再由 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 %}

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

关于symfony - 将 Edge Side Includes 放入我的模板中是一个好习惯吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23607642/

相关文章:

php - 何时在 Symfony2 的前端/核心方法中调用 ->flush()?

php - 在 Twig 中如何比较日期是否在 X 天内?

azure - 您可以在 Azure blob 上手动设置 etag 和最后修改时间吗?

java - Spring Boot 缓存 SpEL (#result) 返回 Null

php - 在 Symfony kernel.controller 事件中,ControllerEvent::getController() 的返回类型是什么?

php - 生成连续的引用号

caching - 使用 symfony2 清除缓存命令不刷新静态 Assets

php - SImple Symfony2 'Front Page' Controller 、路由器和模板。为什么我仍然看到欢迎页面?

php - 防止 Twig 在 {% include %} 之后插入换行符

java - 使用 EhCache 将持久缓存集成到 Apache Httpclient