用例
我正在 Symfony2 之上开发一个 CMF。其中一项功能将是对“小部件”的支持:最终用户可以向页面添加小“块”或“模块”。例子:
- 一个小的登录表单
- 产品清单
- 一些照片来自画廊
- 一个购物车
这个想法是大多数这些小部件将链接到正常的整页路由/控制器。
例如:用户想要在内容页面的侧边栏中列出热门产品。这些项目将链接到 ProductController 的正常 /product/{name} 路由。但在这种情况下,列表将是一个小部件。最终用户可以定义必须放置的位置,例如,必须显示多少项目。
'widgets' 的行为与常规 Symfony2 控制器相同,它有路由、动作、渲染视图等等。有一个带有包罗万象的路由的 WidgetManager 来加载小部件、配置它们并将它们呈现在正确的位置。
我对 Symfony2 没有太多经验,但我现在玩了 3 个月以上。我肯定想继续使用 Symfony2,但需要添加一些魔法来实现我的一些想法。
问题
支持在一个请求中呈现多个控制器(小部件)的最佳方式是什么?
研究
Symfony 的 TwigExtension “ActionExtension” 包含一个 “render” 方法,其中包含基本思想:
<div id="sidebar">
{% render "AcmeArticleBundle:Article:recentArticles" with {'max': 3} %}
</div>
(文档:http ://symfony.com/doc/current/book/templating.html#embedding-controllers )
但它是相当有限的。这种方法的一些问题:
- 我无法在渲染它们之前配置“小部件”(例如:)
$myWidget->set('show_toolbar', false)
,我不想将所有选项作为控制器操作参数传递。 - 不能使用模板继承。例如,我需要这个来“注入”基本
<HEAD>
块中的资产引用(javascript/css)。
我想要的是
我希望下面的代码工作(这是一个简化的例子):
// Serius\PageBundle\Controller\PageController.php
// executed by a catch-all route
public function indexAction($url) {
// load CMS page, etc
$widgets = $this->loadWidgets($page); // widgets configuration is stored in database
// at this point, $widgets is an array of Controller *instances*
// meaning, they are already constructed and configured
return $this->render("SeriusPageBundle:Page:content.html.twig", array(
'widgets' => $widgets
));
}
Serius\PageBundle\Resources\views\Page\content.html.twig
{% extends 'SeriusPageBundle::layout.html.twig' %}
{% block content %}
{% for widget in widgets %}
<div>
{% render widget %}
<!-- Of course, this doesn't work, I would have to create my own Twig extension -->
</div>
{% endfor %}
{% endblock %}
小部件模板的示例:
{% extends '::base.html.twig' %}
{% block stylesheets %}
My stylesheets
{% endblock %}
{% block body %}
This is a shoppingcart widget!
{% endblock %}
我怎样才能做到这一点?有人有这样的经验吗?我已经看过 Symfony CMF 项目,但它不支持这个(据我所知)。