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