【问题标题】:Is it good practice to put Edge Side Includes into my templates?将 Edge Side Includes 放入我的模板中是一种好习惯吗?
【发布时间】:2014-05-12 11:22:35
【问题描述】:

在我们的 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。

【问题讨论】:

    标签: symfony twig http-caching esi


    【解决方案1】:

    我想区分不同类型的块:

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

    有什么区别?

    仅呈现与父模板相同的控制器的其他操作的块大部分时间用于模块化一个页面并使部分可缓存。此块在整个应用程序中只使用一次。

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

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

    这意味着我们可能希望在未来改变 cmets 和评级的工作方式。将来可能不再由 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 %}
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 2019-11-20
      • 1970-01-01
      • 2017-07-15
      • 2017-12-09
      • 2023-03-06
      相关资源
      最近更新 更多