如何将 Twig / PHP / HTML 模板块渲染为任意的分解小节数组?

How to render Twig / PHP / HTML template blocks as an arbitrary array of exploded subsections?

我已经为此苦苦思索了一段时间,因为虽然 "easy" 在原始 PHP 中进行,但由于 PHP 的原因,结果无法扩展缺乏体面的内置模板语法。所以我安装了 Twig,假设它有一个内置的 explode 函数来在块之间迭代。但是似乎无法 div 将内容放入任意数量的小节中。

我使用 {% embed %}, 反对 idered,但文档的样式将根据出现在 parent 模板中的部分来设置。以及以什么顺序(这是可变的;这是针对其中包含大量业务逻辑的表单。)

我在 PHP 中构建了表单,并使其作为一个 "very pretty" 静态页面工作,可以轻松地包含任意数量的小节,无论显示哪个小节,所有小节都可以工作和交互(基于例如用户权限),但将其模板化是一个挑战。

静态(无树枝)版本依赖于我将解析的内容导出到一个数组,然后可以用适当样式的 div 为每个可见部分包装该数组。这可行,但需要我使用包含的 html 和看起来很糟糕且不易维护的对象缓冲:

$content = include("form_content_html.php"); // return an object-buffered array
// I was including the escaped values here using if isset($data) and echo short tags.

foreach ($content as $section) { /* do something; */ }

$template = include("form_template_subsection.php");

$formview->addSubsectionTemplate($template);

echo $formview->addSubsection($content,$i++,$type); 
// fill section of $type with $content[$i] if isset

echo $formview->addSubsection($content,$i++,$sometype);
// $types have different css class for certain effects

// etc. not the best approach.

(我需要在将所有用户/数据库内容绑定到表单值之前将其转义,但是由于表单字段是高度自定义的,我将它们分离到它们自己的内容层中,因此这是唯一具有需要内容的层目前正在逃脱。)

算了,现在我用的是 Twig。 (注意:不是 Symfony2,因为该项目位于共享虚拟主机上。)

我认为没有办法 {%extend%}ing 父模板使得一些子模板块是 "dropped into" 指定的父模板容器,其余忽略;这就是我正在寻找的,因为这样我可以将所有逻辑放入顶层(表单的哪些部分可见等)并首先传入值。

请注意,表单部分的样式由父模板的结构决定,而不是由子内容决定。例如。 section 1 可能显示内容 1,并在 section 2 中对内容 2 调用 css;或具有相同 css 的部分 1 和 2 可能显示不同的内容。

如果我将表单拆分为 15 个仅包含内容的子模板,然后有条件地将它们包含在父文件中,就可以了。但这似乎违背了使用模板引擎的目的?尽管我认为 Twig 可以更轻松地以这种方式处理包含 html 片段的包含文件,所以请告诉我这是否是首选解决方案。

我是否应该 divide 将内容节点向上划分为编号 {% block1 %}{% block2 %} 等小节,然后在我的 PHP 视图 class?

如果 Twig 具有 {% section %}...{% section %} 语法,允许您将模板拆分为块,然后将每个块解析为块元素数组...好吧,我有一半预料到了,希望我能自己加一个。

这是可行的解决方案吗? 来自 Twig 文档:

Horizontal reuse is a way to achieve the same goal as multiple inheritance, but without the associated complexity:

{% extends "base.html" %}

{% use "blocks.html" %}

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

The use statement tells Twig to import the blocks defined in blocks.html into the current template (it's like macros, but for blocks):

{# blocks.html #}

{% block sidebar %}{% endblock %}

Note: The use tag only imports a template if it does not extend another template, if it does not define macros, and if the body is empty. But it can use other templates.

嗯,这有点不太清楚。

( "it" 是指导入的模板可以使用其他模板,还是 "it" 表示一个模板可以使用多个模板,或两者兼而有之?如果正文为空, 是指导入块标签的主体吗?如果是这样,那么它可能不是解决方案。)

是否可以这样做:

{# form_template.html #}
{% extends "form_content.html" %}

{% block section1 %}
    <div class="{{ style1 }}"><div class="{{ style2 }}">etc.

        {{ parent() }}

    </div></div>{% endblock %} 

还是这个? ...

{# form.html #}

{% use "form_content.html" %}

{% for sections as i %}
   {% block wrapper_elements %}{% block section{{i.name}} %}{% endblock %}
   {% endblock %}
{% endfor %}

{# form_content.html #}

{% use "form_fields.html" %} 

{% block section1 %}{% if field1 %}
      Actual content here: {% block field1 %}{% endblock %} And here
   {% else %}&nbsp;{% endif %}
{% endblock %}

{% block section2 %}More actual content here{% block section2 %}

但如果是这样,如何在 form.html 中调用每个部分之前迭代这些部分?

我找到了解决方案,认为:

(来自 Twig 文档)

The set tag can also be used to 'capture' chunks of text:

{% set foo %}
    <div id="pagination">
    ...
    </div> 
{% endset %}

因此,set 可用于迭代匿名连续块:

{% set i=0, out=[] %}{# declare top scope #}

{% block initialize_content %}{# use once #}
    {% set i=0, out=[] %}{# prevent dupes #}
    {% set foo %}

        <div id="pagination">...</div> 

    {% endset %}{% set out=out|merge({ i: foo}) %}{% set i=i+1 %}{% set foo %}

        {{ escape_variables_here }} ... more html

    {% endset %}{% set out=out|merge({ i: foo}) %}{% set i=i+1 %}{% set foo %}

        {{ variables_all_scoped_to_same_context }} ... more html

        {# so dividers can be moved "up and down" if necessary ... #}    

    {% endset %}{% set out=out|merge({ i: foo}) %}{% set i=i+1 %}{% set foo %}

        {# ... like this. ^^a tag/macro could probably define this #}

    {% endset %}{% set out=out|merge({ i: foo}) %}
    {# or loop over i = 0..n or i = loop.index0 #}

{% endblock initialize_content %} {# end setter #}
{% block content %}

    {% if key is defined and out.key is defined %}{{ out.key |raw }}{% endif %}

    {# output top-scoped var (outputs nothing if setter not called) #}
    {# the setter doesn't have to be in its own block, but that allows
    the variables in the content to be redefined in setter's scope. #}

{% endblock %}

(比照Setting element of array from Twig