所以,我还是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 %}
在那个侧边栏中有几个小部件都是他们自己的逻辑。你如何创建/包含这些小部件?
到目前为止,我已经遇到过几种解决方案。
第一个是在Twig的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
// ...
}
并将其包含在&#39; sidebar.html.twig&#39;像这样
<div id="sidebar">
{# Recent Articles widget #}
{{ render(controller('AppBundle:Widget:recentArticlesWidget' )) }}
{# Subscribe-Button widget #}
{{ render(controller('AppBundle:Widget:subscribeButtonWidget' )) }}
{# and so on #}
</div>
我也看到有些人将小部件注册为服务(可以直接在Twig中使用)。使用小部件主类
// 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));
}
}
所以它可以简单地在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 }
并简单地将其用作Twig中的全局函数
{# sidebar.html.twig #}
{{ getRecentArticles() }}
我注意到的一件事是,最后两种方法是逻辑和视图似乎不再分离。您基本上编写了一个小部件功能,并让该功能输出小部件的完整html。这似乎违背了Symfony试图强制执行的模块化和模式。
另一方面,为每个单独的小部件调用不同的控制器或控制器操作(使用自己的twig渲染)似乎可能需要比可能需要的更多处理。我不确定它是否真的减慢了任何东西,但我确实想知道它是否过度。
长话短说,在Symfony中使用可重用小部件是否有最好的做法?我确定其中一些方法也可以混合使用,所以我只是想知道如何最好地解决这个问题。
答案 0 :(得分:1)
我认为最简单的方法是在模板中定义一个块,然后将该模板扩展为渲染块,如下所示:
#reusable.html.twig
{% block reusable_code %}
...
{% endblock %}
和
#reused.html.twig
{% extends 'reusable.html.twig' %}
{{ block('reusable_code') }}
如果您希望获得更多的可重用性,或者您的块包含业务逻辑或模型调用,则可以使用twig扩展
答案 1 :(得分:1)
Twig扩展和Twig宏应该指向正确的方向。
将宏用于业务逻辑的视图和扩展名。
在Twig扩展示例的旁注中,最好只传入您正在使用的服务而不是整个服务容器。
答案 2 :(得分: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
块。
希望这有帮助!