2017-01-22 74 views
3

所以,我對Symfony和Twig還​​是比較陌生的。我想知道如何在模板中最好地包含/創建可重用代碼片段。比如說,你有一個你想在每個頁面上顯示的邊欄。如何在Symfony(Twig)中包含可重用的小部件?

{% extends 'AppBundle::base.html.twig' %} 

{% block body %} 
    <div id="wrapper"> 
     <div id="content-container"> 
      {# Main content... #} 
     </div> 
     <div id="sidebar"> 
      {% include 'sidebar.html.twig' %} 
     </div> 
    </div> 
{% endblock %} 

而且在那個側邊欄中有一些小部件都是自己的邏輯。你如何去創建/包括這些小部件?

到目前爲止,我遇到過幾種解決方案。

作爲控制器

首先是在embed the widget as a controller(s)嫩枝。

class WidgetController extends Controller 
{ 
    public function recentArticlesWidgetAction() 
    { 
     // some logic to generate to required widget data 
     // ... 

     // Render custom widget template with data 
     return $this->render('widgets/recentArticles.html.twig', array('data' => $data) 
     ); 
    } 
    public function subscribeButtonWidgetAction() 
    { 
     // ... 

     return $this->render('widgets/subscribeButton.html.twig', array('data' => $data) 
    } 

    // Many more widgets 
    // ... 
} 

,包括在「sidebar.html.twig」像這樣

<div id="sidebar">   
    {# Recent Articles widget #} 
    {{ render(controller('AppBundle:Widget:recentArticlesWidget')) }} 

    {# Subscribe-Button widget #} 
    {{ render(controller('AppBundle:Widget:subscribeButtonWidget')) }} 

    {# and so on #} 
</div> 

作爲服務

我也看到有些人註冊爲小部件服務(可以使用在枝杈直接)。與小部件主類

// src/AppBundle/Service/RecentArticlesWidget.php 
namespace AppBundle\Service; 

use Symfony\Component\DependencyInjection\ContainerInterface; 

class RecentArticlesWidget 
{ 
    protected $container; 

    public function __construct(ContainerInterface $container) 
    { 
     $this->container = $container; 
    } 

    public function getRecentArticles() 
    { 
     // do some logic (use container for doctrine etc.) 
    } 
} 

被然後註冊爲服務,

# src/AppBundle/Resources/config/services.yml 
services: 
    recentArticlesWidget: 
     class:  AppBundle\Service\RecentArticlesWidget 
     arguments: ["@service_container"] 

傳遞給控制器​​的模板,

namespace AppBundle\Controller; 

class SidebarController { 

    public function showAction($request) { 

     // Get the widget(s) 
     $recentArticlesWidget = $this->get('recentArticlesWidget'); 

     // Pass it (them) along 
     return $this->render('sidebar.html.twig', array('recentArticlesWidget' => $recentArticlesWidget)); 
    } 
} 

,因此可以簡單地使用這樣的in Twig

{# sidebar.html.twig #} 

{{ recentArticlesWidget.getRecentArticles()|raw }} 

或者,您也可以直接將您的服務添加到Twig全局變量,方法是將其添加到Twig配置中。這樣,它不需要由控制器傳遞到視圖中。

#app/config/config.yml 
twig: 
    globals: 
     # twig_var_name: symfony_service 
     recentArticlesWidget: "@recentArticlesWidget" 

作爲枝條延長

這一個是非常類似於使用上述服務(see the documentation)。您創建一個樹枝延伸類,幾乎等同於前面所示

// src/AppBundle/Twig/RecentArticlesWidgetExtension.php 
namespace AppBundle\Twig; 

class RecentArticlesWidgetExtension extends \Twig_Extension 
{ 
    protected $container; 

    public function __construct(ContainerInterface $container) 
    { 
     $this->container = $container; 
    } 

    public function getFunctions() 
    { 
     return array( 
      "getRecentArticles" => new Twig_Function_Method($this, "getRecentArticles") 
      // register more functions 
     ); 
    } 

    public function getRecentArticles() 
    { 
     // do some logic (use container for doctrine etc.) 
    } 

    // Some more functions... 

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

註冊服務,作爲與添加的標籤與服務

# src/AppBundle/Resources/config/services.yml 
services: 
    recentArticlesWidget: 
     class: AppBundle\Twig\RecentArticlesWidgetExtension 
     arguments: [@service_container] 
     tags: 
      - { name: twig.extension } 

,只是在嫩枝

使用它像一個全局函數
{# sidebar.html.twig #} 

{{ getRecentArticles() }} 

思考

有一兩件事我注意到的是,與上2米方法是邏輯和觀點似乎根本不分離。您基本上編寫了一個小部件函數,並讓該函數輸出小部件的完整html。這似乎違背了Symfony試圖實施的模塊化和模式。另一方面,爲每一個小部件調用一個獨立的控制器或控制器動作(用它們自己的小枝渲染)似乎可能需要比可能需要更多的處理。我不確定它是否會減緩任何事情,但我懷疑它是否過度。

長話短說,在Symfony中使用可重用小部件是否有最佳做法?我相信其中的一些方法也可以混合使用,所以我只是想知道如何最好地解決這個問題。

回答

0

我寧願使用塊和父模板。簡單地說,將側欄插入主佈局中,並使所有其他模板都需要從側邊欄 繼承。

事情是這樣的:

layout.html.twig將是這樣的:

{% block title} 
// title goes here 
{%endblock%} 

<div id="wrapper"> 
    <div id="content-container"> 
     {% block pageContent %} 
     {% endblock %} 
    </div> 
    <div id="sidebar"> 
     // Side bar html goes here 
    </div> 
</div> 

現在所有頁面將從此layout.html.twig繼承。例如說,一個名爲home.html.twig頁面將是:

home.html.twig 

{% extends 'AppBundle::layout.html.twig' %} 

{% block title%} 
// this page title goes here 
{% endblock %} 

{% block pageContent %} 
    //This page content goes here 
{% endblock %} 

您可以添加儘可能多的模塊,根據需要,例如css併爲每個頁面js塊。

希望這會有所幫助!

+0

謝謝你的回答!你提出的建議是有幫助和正確的。然而,我的問題更多的是如何最好地將複雜的代碼放在樹枝模板的邊欄(或任何其他地方)。如在內容中,需要執行自己的查詢並具有各種邏輯來生成輸出。通常不會在主控制器中傳遞的東西。我拿小部件作爲一個簡單的例子(把我最喜歡的三篇文章拿給我看,並且很好地展示它們)。我個人傾向於如上所述嵌入額外的「widget控制器」,但我想知道其他人做了什麼。 – Mvin

1

我想在模板中最簡單的方法是定義一個塊,然後擴展該模板呈現塊,像這樣:

#reusable.html.twig 

{% block reusable_code %} 
    ... 
{% endblock %} 

而且

#reused.html.twig 
{% extends 'reusable.html.twig' %} 

{{ block('reusable_code') }} 

如果你想比或更多重用您的塊包含業務邏輯或模型調用樹枝擴展是要走的路

1

枝條擴展和枝條宏應指向你在正確的方向。

將宏用於業務邏輯的視圖和擴展。

在你的Twig擴展示例的一個附註中,最好只傳遞你使用的服務而不是整個服務容器。

相關問題