4

用例
我正在 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 项目,但它不支持这个(据我所知)。

4

2 回答 2

1

我有类似的事情发生,我认为这段代码会对你有所帮助。在选择的模板中,您将获得带有块名称的变量。

public function render()
{       
    $modules = $this->moduleService->getModules();

    foreach($modules as $m){
        $templateName = $m->getTemplateName();

        $template = $this->twig->loadTemplate($templateName);
        $blockNames = $template->getBlockNames();

        foreach($blockNames as $b){
            if(isset($this->blocks[$b]) == false)
                $this->blocks[$b] = '';
            $this->blocks[$b] .= $template->renderBlock($b, array('a' => 'aaa', 'b' => 'bbb'));
        }

    }
    $content = $this->twig->render('Admin/index.html.twig',$this->blocks);
    return new \Symfony\Component\HttpFoundation\Response($content);
}
于 2012-09-09T10:28:58.753 回答
1

我知道这是旧的,但如果有人正在寻找这样的东西 SonataBlockBundle 可能是你的解决方案。

https://github.com/sonata-project/SonataBlockBundle

于 2013-11-04T20:40:25.613 回答