From 029bb5b5a836bba02ca5c45cb6c13ceab7f38d34 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 25 Mar 2010 11:38:43 +0100 Subject: [PATCH] added a long-syntax for the set tag ({% set foo %}...{% endset %}) (closes #25) --- CHANGELOG | 1 + doc/02-Twig-for-Template-Designers.markdown | 9 ++++ doc/06-Recipes.markdown | 16 +++++++ lib/Twig/Node/Set.php | 64 ++++++++++++++++++++------ lib/Twig/TokenParser/Set.php | 33 ++++++++++++-- 5 files changed, 104 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c253df3..896a8a1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 0.9.6-DEV + * added a long-syntax for the set tag ({% set foo %}...{% endset %}) * unit tests are now powered by PHPUnit * added support for gettext via the `i18n` extension * fixed twig_capitalize_string_filter() and fixed twig_length_filter() when used with UTF-8 values diff --git a/doc/02-Twig-for-Template-Designers.markdown b/doc/02-Twig-for-Template-Designers.markdown index 11207a8..3a907bc 100644 --- a/doc/02-Twig-for-Template-Designers.markdown +++ b/doc/02-Twig-for-Template-Designers.markdown @@ -592,6 +592,15 @@ the `set` tag and can have multiple targets: {% set foo, bar as 'foo', 'bar' %} +The `set` tag can also be used to 'capture' chunks of HTML: + + [twig] + {% set foo %} + + {% endset %} + ### Extends The `extends` tag can be used to extend a template from another one. You can diff --git a/doc/06-Recipes.markdown b/doc/06-Recipes.markdown index 1b66b35..20ec0c9 100644 --- a/doc/06-Recipes.markdown +++ b/doc/06-Recipes.markdown @@ -211,3 +211,19 @@ The output will be similar to: In the inner loop, the `loop.parent` variable is used to access the outer context. So, the index of the current `topic` defined in the outer for loop is accessible via the `loop.parent.loop.index` variable. + +Passing a Macro as an Argument +------------------------------ + +By default, a macro directly outputs its content to the screen. If you want to +pass the content of a macro as an argument to a method or to another macro, +you can use the `set` tag: + + [twig] + {% import "form_elements.html" as form %} + + {% set theinput %} + {{ form.input('test', 'text', 'Value') }} + {% endset %} + + {{ form.row('Label', theinput) }} diff --git a/lib/Twig/Node/Set.php b/lib/Twig/Node/Set.php index 7b1026f..7058b3f 100644 --- a/lib/Twig/Node/Set.php +++ b/lib/Twig/Node/Set.php @@ -1,16 +1,34 @@ + * @version SVN: $Id$ + */ class Twig_Node_Set extends Twig_Node implements Twig_NodeListInterface { protected $names; protected $values; protected $isMultitarget; + protected $capture; - public function __construct($isMultitarget, $names, $values, $lineno, $tag = null) + public function __construct($isMultitarget, $capture, $names, $values, $lineno, $tag = null) { parent::__construct($lineno, $tag); $this->isMultitarget = $isMultitarget; + $this->capture = $capture; $this->names = $names; $this->values = $values; } @@ -71,32 +89,48 @@ class Twig_Node_Set extends Twig_Node implements Twig_NodeListInterface } else { + if ($this->capture) + { + $compiler + ->write("ob_start();\n") + ->subcompile($this->values) + ; + } + $compiler ->write('$context[') ->string($this->names->getName()) ->raw(']') ; - } - $compiler->raw(' = '); + if ($this->capture) + { + $compiler->raw(" = ob_get_clean()"); + } + } - if ($this->isMultitarget) + if (!$this->capture) { - $compiler->write('array('); - foreach ($this->values as $idx => $value) + $compiler->raw(' = '); + + if ($this->isMultitarget) { - if ($idx) + $compiler->write('array('); + foreach ($this->values as $idx => $value) { - $compiler->raw(', '); - } + if ($idx) + { + $compiler->raw(', '); + } - $compiler->subcompile($value); + $compiler->subcompile($value); + } + $compiler->raw(')'); + } + else + { + $compiler->subcompile($this->values); } - $compiler->raw(')'); - } - else - { - $compiler->subcompile($this->values); } $compiler->raw(";\n"); diff --git a/lib/Twig/TokenParser/Set.php b/lib/Twig/TokenParser/Set.php index 5272134..63d97a8 100644 --- a/lib/Twig/TokenParser/Set.php +++ b/lib/Twig/TokenParser/Set.php @@ -13,18 +13,43 @@ class Twig_TokenParser_Set extends Twig_TokenParser public function parse(Twig_Token $token) { $lineno = $token->getLine(); + $stream = $this->parser->getStream(); list($isMultitarget, $names) = $this->parser->getExpressionParser()->parseAssignmentExpression(); - $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, 'as'); - list(, $values) = $this->parser->getExpressionParser()->parseMultitargetExpression(); - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + $capture = false; + if ($stream->test(Twig_Token::NAME_TYPE, 'as')) + { + $stream->expect(Twig_Token::NAME_TYPE, 'as'); + list(, $values) = $this->parser->getExpressionParser()->parseMultitargetExpression(); + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + } + else + { + $capture = true; + + if ($isMultitarget) + { + throw new Twig_SyntaxError("When using set with a block, you cannot have a multi-target.", $lineno); + } + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + $values = $this->parser->subparse(array($this, 'decideBlockEnd'), true); + $stream->expect(Twig_Token::BLOCK_END_TYPE); + } if (count($names) !== count($values)) { throw new Twig_SyntaxError("When using set, you must have the same number of variables and assignements.", $lineno); } - return new Twig_Node_Set($isMultitarget, $names, $values, $lineno, $this->getTag()); + return new Twig_Node_Set($isMultitarget, $capture, $names, $values, $lineno, $this->getTag()); + } + + public function decideBlockEnd($token) + { + return $token->test('endset'); } public function getTag() -- 1.7.2.5