【问题标题】:Embedded controller views with assets带有资产的嵌入式控制器视图
【发布时间】:2012-02-11 07:51:47
【问题描述】:

我目前正在开发一个 symfony2 应用程序并且正在使用嵌入式控制器。我的嵌入式控制器就像小部件一样,应该封装自己的一组功能,可以嵌入到任何地方,并且仍然可以正常工作。

我有一个控制器,称为在线用户。它生成的视图很简单,只是一个在线用户列表。但是,我想在该视图中添加一些 javascript,以便我可以使用 ajax 来检索被点击的用户的信息。

控制器基本上返回一个视图:

return $this->render('AppBundle:Users:usersOnline.html.twig', array('somedata' => $data);

这是该控制器的视图:

{% extends partial.html.twig" %}
{%  block content %}
 <ul>
   <li><a href="site.com/ajax/user/1">User 1</a></li> (this would all be generated using 'somedata')
   <li><a href="site.com/ajax/user/2">User 2</a></li>
   ....
 <ul>
{% endblock content %}
{%  block scripts %}
   ..some javascript for interacting with this widget
{% endblock %}

这是从以下扩展而来的部分:

{%  block content %}
{% endblock content %}

{%  block scripts %}{% endblock %}

这是嵌入控制器的主页:

{% "base.html.twig" %}
{% block title %}Main{% endblock %}

{% block content %}
 ..some markup here
 <div id="usersonline">
  {% render "AppBundle:Users:usersOnline" with {'max': 4} %}
 </div>
{% endblock %}

{% block scripts %}
  ..some javascript
{% endblock %}

这是它扩展的基础:

<!DOCTYPE html>
<html>
    <head>
     <meta charset="utf-8">
     <title>{% block title %}{% endblock %} - App</title>       
     ...Some stylesheets
    </head>
    <body>
        {% block content %}{% endblock %}
        <script src="http://yui.yahooapis.com/3.5.0pr2/build/yui/yui-min.js"></script>
        {%  block scripts %}{% endblock %}
    </body>
</html>

我现在面临的问题是包含来自嵌入式控制器的 javascript。在我的例子中,视图扩展了部分,并在插入主页之前完全呈现为 1 个单元。在这种情况下,我只能将我的 javascript 放在 content 块中,这意味着我将在 &lt;div&gt; 标记中包含 &lt;script&gt; 标记。我还希望在正文末尾添加脚本以提高用户界面性能。

我应该如何构建我的模板(或者甚至可能),以便我可以将嵌入式控制器视图中的适当部分渲染到嵌入控制器的模板中的适当块中?在我当前的模板中,YUI 库将在嵌入式控制器呈现 HTML 标记之后加载,因此无法在嵌入式控制器中使用 YUI 库进行访问。

【问题讨论】:

  • Duplicate 虽然更容易阅读。我不认为嵌入式控制器的结果可以在多个块之间划分。返回的结果只是呈现的 html 而不是 twig 模板。我认为您需要两个嵌入式控制器,一个用于内容,一个用于 javascript。在某些情况下,甚至可能是一个用于 css 的。
  • 嗯。拥有 2 个嵌入式控制器并不理想,而且 imo 也不是很优雅。
  • 好吧,您实际上并不需要两个控制器,只需使用指定您想要的参数的同一个控制器的两次调用,即使用 { 'generate' : 'html' or 'js' or 'css ' }。然后相应地调整您的模板。

标签: templates symfony


【解决方案1】:

我编写了一个扩展,它本质上是一个令牌解析器来处理这个问题。令牌解析器的文档非常稀少,而且代码也大多没有注释,所以花了一些时间才开始工作。

我已经构建了解析器,以便在开始时声明一些内容(类似于{% use %}):

{% myparser "AppBundle:Users:usersOnline" with {'max': 4} as xyz %}

然后像xyzcontent 这样的块将可用,然后您只需使用 {{ block('xyzcontent') }} 在适当的位置呈现它们。它工作得很好。但是以下方法不起作用:

{% set max = 4 %}
{% myparser "AppBundle:Users:usersOnline" with {'max': max} as xyz %}

我找不到直接在令牌解析器中评估表达式并获取其值的方法。大部分情况下它都可以正常工作,除了这个问题。

如果有人知道如何在令牌解析器中获取变量的值,那就太好了:)

【讨论】:

  • 我正在拼命寻找类似问题的解决方案:在我的情况下,我正在编写一个能够嵌入多个控制器(这意味着包括其他模板)的“小部件”包,但我想要能够将资产(js/css/less)“注册”到正确的块(“样式表”/“javascripts”)。无论如何,你能分享你的 Twig 扩展代码吗?编写自己的令牌解析器非常困难(没有经验)。感谢您的优势。
【解决方案2】:

找了一天满意的解决方案后,我最终选择了以下方法:

  • 为小部件的功能渲染控制器(就像您已经在做的那样);
  • 渲染模板以嵌入小部件的资产(不需要控制器,这会浪费您的性能)。如果模板不存在,则忽略包含。
  • 使用一致的命名约定使小部件功能更具动态性。

一个小部件的示例:

{% "base.html.twig" %}
{% block title %}Main{% endblock %}

{% block content %}
 ..some markup here
 <div id="usersonline">
  {{ render(controller("AppBundle:Users:usersOnline", {'max': 4})) }}
 </div>
{% endblock %}

{% block scripts %}
  {{ include("AppBundle:Users:usersOnline_js.html.twig" ignore missing }}
{% endblock %}

{% block stylesheets %}
  {{ include("AppBundle:Users:usersOnline_css.html.twig" ignore missing }}
{% endblock %}

(如您所见,我使用 Symfony 2.2 的包含和嵌入方式)

或者,一种更动态的小部件渲染方式:

{% "base.html.twig" %}
{% block title %}Main{% endblock %}

{% block widgets %}
 ..some markup here
  {% for widget in widgets %}
    {{ render(controller(widget.controller ~ ':widget', widget.options)) }}
  {% endfor %}
{% endblock %}

{% block scripts %}
  {% for widget in widgets %}
    {{ include(widget.controller ~ ':widget_js.html.twig' ignore missing }}
  {% endfor %}
{% endblock %}

{% block stylesheets %}
  {% for widget in widgets %}
    {{ include(widget.controller ~ ':widget_css.html.twig' ignore missing }}
  {% endfor %}
{% endblock %}

我的结论

在一个页面中渲染多个控制器,同时“合并”它的模板块,不能在 Symfony2 中实现开箱即用。 Symfony2 一直专注于为每个请求使用一个控制器,这解释了为什么多个控制器输出是分开的且难以组合的原因。

我认为 Symfony CMF 已经(或将拥有)一个合适的解决方案,因为整个小部件主题更多地应用于动态内容管理的网站。

无论如何,我认为我结合嵌入式控制器和包含模板的方式是迄今为止 Symfony 2 的最佳方法。

在我看来,替代方案确实有很多缺点:

  • 使用多个控制器:太重且不需要,因为资产不需要任何控制器。
  • 直接在页面中加载小部件资产:更改小部件/资产时难以维护。

【讨论】:

    猜你喜欢
    • 2016-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-26
    • 2012-09-22
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多