所以,我仍然是Symfony和Twig的新手.我想知道如何在模板中最好地包含/创建可重用代码片段.例如,假设您有一个要在每个页面上显示的侧边栏.
{% extends 'AppBundle::base.html.twig' %} {% block body %}{% endblock %}{# Main content... #}{% include 'sidebar.html.twig' %}
而那个侧边栏中有几个小部件都是他们自己的逻辑.你如何创建/包含这些小部件?
到目前为止,我遇到了几个解决方案.
作为控制者第一个是将小部件作为控制器嵌入 Twig中.
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'中包含这样的内容
作为一项服务{# Recent Articles widget #} {{ render(controller('AppBundle:Widget:recentArticlesWidget' )) }} {# Subscribe-Button widget #} {{ render(controller('AppBundle:Widget:subscribeButtonWidget' )) }} {# and so on #}
我也看到有些人将小部件注册为服务(可以直接在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"作为Twig扩展
这个与使用上面的服务非常相似(参见文档).您创建了一个与之前显示的服务几乎相同的twig扩展类
// 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中使用可重用小部件是否有最好的做法?我敢肯定其中一些方法也可以混合,所以我只是想知道如何最好地解决这个问题.