Skip to main content
 首页 » 编程设计

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

2024年12月31日58dudu

在我们的 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 评级工作方式的实现,而无需触及使用评级的模板。