From 5ed59be9c5edf9eb212a07bd328e5aa130a4ad25 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 12 Nov 2016 08:50:46 -0800 Subject: [PATCH] added support for a custom template on the block() function --- CHANGELOG | 1 + doc/functions/block.rst | 14 ++++++ lib/Twig/ExpressionParser.php | 2 +- lib/Twig/Node/Expression/BlockReference.php | 47 ++++++++++++++++----- lib/Twig/TokenParser/Filter.php | 2 +- 5 files changed, 54 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4d2c72fc3..acdb89a88 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 1.28.0 (2016-XX-XX) + * added support for a custom template on the block() function * added "is defined" support for block() and constant() * optimized the way attributes are fetched diff --git a/doc/functions/block.rst b/doc/functions/block.rst index 2f3de2456..9c2e3d3b5 100644 --- a/doc/functions/block.rst +++ b/doc/functions/block.rst @@ -1,6 +1,9 @@ ``block`` ========= +.. versionadded: 1.28 + Support for the template argument was added in Twig 1.28. + When a template uses inheritance and if you want to print a block multiple times, use the ``block`` function: @@ -12,6 +15,13 @@ times, use the ``block`` function: {% block body %}{% endblock %} +The ``block`` function can also be used to display one block of another +template: + +.. code-block:: jinja + + {{ block("title", "common_blocks.twig") }} + Use the ``defined`` test to check if a block exists in the context of the current template: @@ -21,4 +31,8 @@ current template: ... {% endif %} + {% if block("footer", "common_blocks.twig") is defined %} + ... + {% endif %} + .. seealso:: :doc:`extends<../tags/extends>`, :doc:`parent<../functions/parent>` diff --git a/lib/Twig/ExpressionParser.php b/lib/Twig/ExpressionParser.php index 43a8cf157..de2e56a3b 100644 --- a/lib/Twig/ExpressionParser.php +++ b/lib/Twig/ExpressionParser.php @@ -349,7 +349,7 @@ class Twig_ExpressionParser throw new Twig_Error_Syntax('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext()->getName()); } - return new Twig_Node_Expression_BlockReference($args->getNode(0), $line); + return new Twig_Node_Expression_BlockReference($args->getNode(0), count($args) > 1 ? $args->getNode(1) : null, $line); case 'attribute': $args = $this->parseArguments(); if (count($args) < 2) { diff --git a/lib/Twig/Node/Expression/BlockReference.php b/lib/Twig/Node/Expression/BlockReference.php index d22dd57cc..5f91f3d03 100644 --- a/lib/Twig/Node/Expression/BlockReference.php +++ b/lib/Twig/Node/Expression/BlockReference.php @@ -17,16 +17,23 @@ */ class Twig_Node_Expression_BlockReference extends Twig_Node_Expression { - public function __construct(Twig_NodeInterface $name, $lineno, $tag = null) + /** + * @param Twig_Node|null $template + */ + public function __construct(Twig_NodeInterface $name, $template = null, $lineno, $tag = null) { - if (is_bool($lineno)) { + if (is_bool($template)) { @trigger_error(sprintf('The %s method "$asString" argument is deprecated since version 1.28 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED); - $lineno = $tag; - $tag = func_num_args() > 3 ? func_get_arg(3) : null; + $template = null; } - parent::__construct(array('name' => $name), array('is_defined_test' => false, 'output' => false), $lineno, $tag); + $nodes = array('name' => $name); + if (null !== $template) { + $nodes['template'] = $template; + } + + parent::__construct($nodes, array('is_defined_test' => false, 'output' => false), $lineno, $tag); } public function compile(Twig_Compiler $compiler) @@ -39,19 +46,39 @@ class Twig_Node_Expression_BlockReference extends Twig_Node_Expression ; } else { if ($this->getAttribute('output')) { - $compiler - ->addDebugInfo($this) - ->write('$this->displayBlock(') + $compiler->addDebugInfo($this); + + $this + ->compileTemplateCall($compiler) + ->raw('->displayBlock(') ->subcompile($this->getNode('name')) ->raw(", \$context, \$blocks);\n") ; } else { - $compiler - ->raw('$this->renderBlock(') + $this + ->compileTemplateCall($compiler) + ->raw('->renderBlock(') ->subcompile($this->getNode('name')) ->raw(', $context, $blocks)') ; } } } + + private function compileTemplateCall(Twig_Compiler $compiler) + { + if (!$this->hasNode('template')) { + return $compiler->write('$this'); + } + + return $compiler + ->write('$this->loadTemplate(') + ->subcompile($this->getNode('template')) + ->raw(', ') + ->repr($this->getTemplateName()) + ->raw(', ') + ->repr($this->getTemplateLine()) + ->raw(')') + ; + } } diff --git a/lib/Twig/TokenParser/Filter.php b/lib/Twig/TokenParser/Filter.php index 150cef739..b735ed409 100644 --- a/lib/Twig/TokenParser/Filter.php +++ b/lib/Twig/TokenParser/Filter.php @@ -23,7 +23,7 @@ class Twig_TokenParser_Filter extends Twig_TokenParser public function parse(Twig_Token $token) { $name = $this->parser->getVarName(); - $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), $token->getLine(), $this->getTag()); + $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), null, $token->getLine(), $this->getTag()); $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag()); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);