关于如何使用树枝追加块有几个问题。答案总是使用继承和使用,然后调用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中的两个内容都在appendable中呈现。我怎么能做到这一点?
答案 0 :(得分: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 %}
根据我的研究,这种技术被称为“水平重用”,这里是doc:
答案 1 :(得分: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 %}
答案 2 :(得分:0)
我想分享我自己的解决方案。我实现了自己的Twig扩展,它实现了自定义标记widget
(我使用了Twig标记embed
作为源代码。)
WidgetNode.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';
}
}
TemplateTagsExtension.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';
}
}
services.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的embed
嵌入模板(我使用此标记作为我的扩展的来源),但只有(和主要)差异 - 它呈现 ONLY < / em>名为&#34; widget&#34;的块。所有其他块都被忽略,但可以在&#34;小部件内使用&#34;块。
答案 3 :(得分: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 %}