2

关于如何用树枝附加块有几个问题。答案总是使用继承和使用,然后调用 parent()。不知何故,我不知道这在我的具体情况下是如何工作的:

base.html.twig

{% block content %}{% endblock %}
{% block appendable %}
{% endblock %}
{% block another_appendable %}
{% endblock %}

site.html.twig

{% extends base.html.twig %}
{% block content %}
{# Here use/include/embed, i dont know #}
{% use sub1.html.twig %}
{% use sub2.html.twig %}
{% endblock content %}

sub1.html.twig

Some content that should be directly rendered
{% block appendable %}
some stuff that should be added to appendable
{% endblock %}
{% block another_appendable %}
This content should be added to "another appendable"
{% endblock %}

sub2.html.twig

{% block appendable %}
additional stuff that should be appended
{% endblock %}

我希望 sub1 和 sub2 的内容都呈现在可附加内容中。我怎么能做到这一点?

4

4 回答 4

5

我们走吧。我有同样的问题,这个解决方案对我有用:

base.html.twig

{% block content %}{% endblock %}

site.html.twig

{% extends base.html.twig %}

{% use sub1.html.twig with appendable as appendableContent, another_appendable as another_appendableContent %}

{% block content %}

    {% block appendable -%}
        {{ block('appendableContent') }}
    {% endblock %}

    {% block another_appendable -%}
        {{ block('another_appendableContent') }}
    {% endblock %}

{% endblock %}

sub1.html.twig

{% use sub2.html.twig with appendable as appendableContentAlternative %}

{% block appendable %}
    some stuff that should be added to appendable<br/><br/>

    {{ block('appendableContentAlternative') }}
{% endblock %}

{% block another_appendable %}
    This content should be added to "another appendable"<br/><br/>
{% endblock %}

sub2.html.twig

{% block appendable %}
    additional stuff that should be appended<br/><br/>
{% endblock %}

根据我的研究,这种技术称为“水平重用”,这是文档:

http://twig.sensiolabs.org/doc/tags/use.html

于 2013-12-04T16:53:42.640 回答
2

要包含模板,您需要使用include关键字,而不是use关键字:

{% block appendable %}

    {# Assuming your sub1 template is in AcmeDemoBundle/Resources/views/MySub/sub1.html.twig #}
    {% include "AcmeDemoBundle:MySub:sub1.html.twig" %}

{% endblock appendable %}

AcmeDemoBundle:MySub:sub1.html.twig可能如下所示:

<b>Put directly your code there, no need to use the blocks.</b>

使用继承

如果您愿意,可以使用{{ parent() }}关键字来使用继承。例如,如果您想sub1.html.twig默认包含但附加sub2.html.twig在您的子模板中,您可以执行以下操作:

base.html.twig

{% block content %}

    {% include "AcmeDemoBundle:MySub:sub1.html.twig" %}

{% endblock %}

site.html.twig

{% extends base.html.twig %}

{% block content %}

    {# render what happens in the parent content block #}
    {{ parent() }}

    {# and append sub2.html.twig as well #}
    {% include "AcmeDemoBundle:MySub:sub2.html.twig" %}

{% endblock content %}
于 2013-01-28T14:48:03.677 回答
0

我想分享我自己解决这个问题的方法。我实现了自己的 Twig 扩展,它实现了自定义标签widget(我使用 Twig 标签embed作为源)。

扩大

小部件节点.php:

namespace Artprima\Bundle\TwigWidgetTagBundle\Twig\Extension;

/**
 * Class WidgetNode
 *
 * @author Denis V
 *
 * @package Artprima\Bundle\TwigWidgetTagBundle\Twig\Extension
 */
class WidgetNode extends \Twig_Node_Include
{
    // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
    public function __construct($filename, $index, \Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
    {
        parent::__construct(new \Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);

        $this->setAttribute('filename', $filename);
        $this->setAttribute('index', $index);
    }

    /**
     * Compiles the node to PHP.
     *
     * @param $compiler \Twig_Compiler A Twig_Compiler instance
     */
    public function compile(\Twig_Compiler $compiler)
    {
        $compiler->addDebugInfo($this);

        if ($this->getAttribute('ignore_missing')) {
            $compiler
                ->write("try {\n")
                ->indent()
            ;
        }

        $this->addGetTemplate($compiler);

        $compiler->raw('->displayBlock(');

        $compiler->string('widget');

        $compiler->raw(', ');

        $this->addTemplateArguments($compiler);

        $compiler->raw(");\n");

        if ($this->getAttribute('ignore_missing')) {
            $compiler
                ->outdent()
                ->write("} catch (Twig_Error_Loader \$e) {\n")
                ->indent()
                ->write("// ignore missing template\n")
                ->outdent()
                ->write("}\n\n")
            ;
        }
    }

    protected function addGetTemplate(\Twig_Compiler $compiler)
    {
        $compiler
            ->write("\$this->env->loadTemplate(")
            ->string($this->getAttribute('filename'))
            ->raw(', ')
            ->string($this->getAttribute('index'))
            ->raw(")")
        ;
    }
}

WidgetTokenParser.php:

namespace Artprima\Bundle\TwigWidgetTagBundle\Twig\Extension;

/**
 * Class WidgetTokenParser
 *
 * @author Denis V
 *
 * @package Artprima\Bundle\TwigWidgetTagBundle\Twig\Extension
 */
class WidgetTokenParser extends \Twig_TokenParser_Include
{
    /**
     * Parses a token and returns a node.
     *
     * @param \Twig_Token $token A Twig_Token instance
     *
     * @return \Twig_NodeInterface A Twig_NodeInterface instance
     */
    public function parse(\Twig_Token $token)
    {
        $stream = $this->parser->getStream();

        $parent = $this->parser->getExpressionParser()->parseExpression();

        list($variables, $only, $ignoreMissing) = $this->parseArguments();

        // inject a fake parent to make the parent() function work
        $stream->injectTokens(array(
            new \Twig_Token(\Twig_Token::BLOCK_START_TYPE, '', $token->getLine()),
            new \Twig_Token(\Twig_Token::NAME_TYPE, 'extends', $token->getLine()),
            new \Twig_Token(\Twig_Token::STRING_TYPE, '__parent__', $token->getLine()),
            new \Twig_Token(\Twig_Token::BLOCK_END_TYPE, '', $token->getLine()),
        ));

        $module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true);

        // override the parent with the correct one
        $module->setNode('parent', $parent);

        $this->parser->embedTemplate($module);

        $stream->expect(\Twig_Token::BLOCK_END_TYPE);

        return new WidgetNode($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
    }

    public function decideBlockEnd(\Twig_Token $token)
    {
        return $token->test('endwidget');
    }

    /**
     * Gets the tag name associated with this token parser.
     *
     * @return string The tag name
     */
    public function getTag()
    {
        return 'widget';
    }

}

模板标签扩展.php:

namespace Artprima\Bundle\TwigWidgetTagBundle\Twig\Extension;

/**
 * Class TemplateTagsExtension
 *
 * @author Denis V
 *
 * @package Artprima\Bundle\TwigWidgetTagBundle\Twig\Extension
 */
class TemplateTagsExtension extends \Twig_Extension
{
    /**
     * @inheritdoc
     */
    public function getTokenParsers()
    {
        return array(
            new WidgetTokenParser(),
        );
    }

    /**
     * Returns the name of the extension.
     *
     * @return string The extension name
     */
    public function getName()
    {
        return 'template_tags';
    }
}

服务.yml:

parameters:
    artprima.twig.extension.template_tags.class: Artprima\Bundle\TwigWidgetTagBundle\Twig\Extension\TemplateTagsExtension

services:
    artprima.twig.extension.template_tags:
        class: %artprima.twig.extension.template_tags.class%
        tags:
            - { name: twig.extension }

使用示例

视图/块/widget.html.twig:

{# please note, that only "widget" block is rendered, all other blocks can be used inside the "widget" block #}
{# if you don't define the "widget" block, nothing will be rendered #}
{% block widget %}
    <div class="{{ block('widget_box_class') }}">
        {{ block('widget_header') }}
        {{ block('widget_body') }}
    </div>
{% endblock %}

{% block widget_header %}
    <div class="{{ block('widget_header_class') }}">
        {{ block('widget_title') }}
        {% if display_toolbar is defined and display_toolbar %}{{ block('widget_toolbar') }}{% endif %}
    </div>
{% endblock %}

{% block widget_body %}
    <div class="{{ block('widget_main_class') }}">
        {{ block('widget_main') }}
    </div>
{% endblock %}

{% block widget_title %}
    <h5 class="widget-title">{{ block('widget_title_text') }}</h5>
{% endblock %}

{% block widget_title_text %}(undefined){% endblock %}

{% block widget_toolbar %}
    <div class="widget-toolbar">
        {{ block('widget_toolbar_inner') }}
    </div>
{% endblock %}

{% block widget_toolbar_inner %}{% endblock %}

{% block widget_box_class %}{% spaceless %}widget-box{% endspaceless %}{% endblock %}

{% block widget_main_class %}{% spaceless %}widget-main{% endspaceless %}{% endblock %}

{% block widget_main %}{% endblock %}

{% block widget_header_class %}{% spaceless %}widget-header{% endspaceless %}{% endblock %}

视图/仪表板/小部件/sample.html.twig

{% widget "ArtprimaSampleBundle:Blocks:widgets.html.twig" %}
    {% block widget_title_text %}{{ "widget.records_creation_history"|trans }}{% endblock %}
    {% block widget_main_class %}{% spaceless %}no-padding {{ parent() }}{% endspaceless %}{% endblock %}
    {% block widget_main %}
        <table class="table table-striped table-bordered table-hover no-margin-bottom">
            <thead>
            <tr>
                <th>Description</th>
                <th>Amount</th>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td>{{ "widget.number_of_countries.created"|trans }}</td>
                <td>{{ dashboard.countries.created }}</td>
            </tr>
            <tr>
                <td>{{ "widget.number_of_users.created"|trans }}</td>
                <td>{{ dashboard.users.created }}</td>
            </tr>
            </tbody>
        </table>
    {% endblock %}
{% endwidget %}

概括

因此,如您所见,使用我的扩展程序,可以包含一个模板并重用其中的块。如果您需要多个小部件,您可以widget使用相同的源模板在模板中有多个标签,并且块内容不会重叠。本质上,它就像使用 Twig's 嵌入模板embed(我使用这个标签作为我的扩展的源),但唯一(和主要)不同 - 它只呈现名为“widget”的块。所有其他块都被忽略,但可以在“小部件”块内使用。

于 2014-09-14T10:42:38.537 回答
0

如果您只在子模板中定义块,您可以使用该block函数并显式替换:

base.html.twig

{% block content %}{% endblock %}
{% block appendable %}{% endblock %}
{% block another_appendable %}{% endblock %}

site.html.twig

{% extends base.html.twig %}

{% block appendable %}
{{ block('appendable', 'sub1.html.twig') }}
{{ block('appendable', 'sub2.html.twig') }}
{% endblock %}

{% block another_appendable %}
This content should be added to "another appendable"
{{ block('another_appendable', 'sub1.html.twig') }}
{% endblock %}

sub1.html.twig

{% block appendable %}
some stuff that should be added to appendable
{% endblock %}

{% block another_appendable %}
This content should be added to "another appendable"
{% endblock %}

sub2.html.twig

{% block appendable %}
additional stuff that should be appended
{% endblock %}
于 2018-03-30T17:46:04.247 回答