added a long-syntax for the set tag ({% set foo %}...{% endset %}) (closes #25)
authorFabien Potencier <fabien.potencier@gmail.com>
Thu, 25 Mar 2010 10:38:43 +0000 (11:38 +0100)
committerFabien Potencier <fabien.potencier@gmail.com>
Thu, 25 Mar 2010 10:38:43 +0000 (11:38 +0100)
CHANGELOG
doc/02-Twig-for-Template-Designers.markdown
doc/06-Recipes.markdown
lib/Twig/Node/Set.php
lib/Twig/TokenParser/Set.php

index c253df3..896a8a1 100644 (file)
--- 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
index 11207a8..3a907bc 100644 (file)
@@ -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 %}
+      <div id="pagination">
+        ...
+      </div>
+    {% endset %}
+
 ### Extends
 
 The `extends` tag can be used to extend a template from another one. You can
index 1b66b35..20ec0c9 100644 (file)
@@ -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) }}
index 7b1026f..7058b3f 100644 (file)
@@ -1,16 +1,34 @@
 <?php
 
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2010 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Represents a set node.
+ *
+ * @package    twig
+ * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @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");
index 5272134..63d97a8 100644 (file)
@@ -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()