added self variable, simplified macro management, added some more documentation for...
authorFabien Potencier <fabien.potencier@gmail.com>
Sat, 12 Jun 2010 09:27:38 +0000 (11:27 +0200)
committerFabien Potencier <fabien.potencier@gmail.com>
Sat, 12 Jun 2010 09:27:41 +0000 (11:27 +0200)
CHANGELOG
doc/02-Twig-for-Template-Designers.markdown
lib/Twig/Environment.php
lib/Twig/Node/Expression/Name.php
lib/Twig/Node/Import.php
lib/Twig/Node/Module.php
test/Twig/Tests/Node/ModuleTest.php
test/Twig/Tests/Node/SandboxedModuleTest.php
test/fixtures/tags/macro/basic.test
test/fixtures/tags/macro/self_import.test [new file with mode: 0644]

index cb0ebfa..46d1302 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@ Backward incompatibilities:
  * removed the sandboxed attribute of the include tag (use the new sandbox tag instead)
  * refactored the Node system (if you have custom nodes, you will have to update them to use the new API)
 
+ * added self as a special variable that refers to the current template (useful for importing macros from the current template)
  * added Twig_Template instance support to the include tag
  * added support for dynamic and conditional inheritance ({% extends some_var %} and {% extends standalone ? "minimum" : "base" %})
  * added a grammar sub-framework to ease the creation of custom tags
index e3336ee..6a9d292 100644 (file)
@@ -569,7 +569,7 @@ more complex `expressions` there too:
 ### Macros
 
 Macros are comparable with functions in regular programming languages. They
-are useful to put often used HTML idioms into reusable functions to not repeat
+are useful to put often used HTML idioms into reusable elements to not repeat
 yourself.
 
 Here a small example of a macro that renders a form element:
@@ -589,8 +589,8 @@ Macros differs from native PHP functions in a few ways:
 But as PHP functions, macros don't have access to the current template
 variables.
 
-Macros can be defined in any template, and always need to be "imported" before
-being used (see the Import section for more information):
+Macros can be defined in any template, and need to be "imported" before being
+used (see the Import section for more information):
 
     [twig]
     {% import "forms.html" as forms %}
@@ -605,6 +605,44 @@ The macro can then be called at will:
     <p>{{ forms.input('username') }}</p>
     <p>{{ forms.input('password', none, 'password') }}</p>
 
+If the macros are defined and used in the same template, you can use the
+special `self` variable, without importing them:
+
+    [twig]
+    <p>{{ self.input('username') }}</p>
+
+When you want to use a macro in another one from the same file, use the `self`
+variable:
+
+    [twig]
+    {% macro input(name, value, type, size) %}
+      <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
+    {% endmacro %}
+
+    {% macro wrapped_input(name, value, type, size) %}
+        <div class="field">
+            {{ self.input(name, value, type, size) }}
+        </div>
+    {% endmacro %}
+
+When the macro is defined in another file, you need to import it:
+
+    [twig]
+    {# forms.html #}
+
+    {% macro input(name, value, type, size) %}
+      <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
+    {% endmacro %}
+
+    {# shortcuts.html #}
+
+    {% macro wrapped_input(name, value, type, size) %}
+        {% import "forms.html" as forms %}
+        <div class="field">
+            {{ forms.input(name, value, type, size) }}
+        </div>
+    {% endmacro %}
+
 ### Filters
 
 Filter sections allow you to apply regular Twig filters on a block of template
@@ -728,6 +766,7 @@ Importing these macros in a template is as easy as using the `import` tag:
 
     [twig]
     {% import 'forms.html' as forms %}
+
     <dl>
       <dt>Username</dt>
       <dd>{{ forms.input('username') }}</dd>
@@ -736,8 +775,19 @@ Importing these macros in a template is as easy as using the `import` tag:
     </dl>
     <p>{{ forms.textarea('comment') }}</p>
 
-Even if the macros are defined in the same template as the one where you want
-to use them, they still need to be imported:
+Importing is not needed if the macros and the template are defined in the file;
+use the special `self` variable instead:
+
+    [twig]
+    {# index.html template #}
+
+    {% macro textarea(name, value, rows) %}
+      <textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
+    {% endmacro %}
+
+    <p>{{ self.textarea('comment') }}</p>
+
+But you can still create an alias by importing from the `self` variable:
 
     [twig]
     {# index.html template #}
@@ -746,7 +796,7 @@ to use them, they still need to be imported:
       <textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
     {% endmacro %}
 
-    {% import "index.html" as forms %}
+    {% import self as forms %}
 
     <p>{{ forms.textarea('comment') }}</p>
 
index 12c5269..2e17ed8 100644 (file)
@@ -179,13 +179,12 @@ class Twig_Environment
      * Loads a template by name.
      *
      * @param  string  $name  The template name
-     * @param  Boolean $macro Whether to return the macro object if any, or the template one
      *
      * @return Twig_TemplateInterface A template instance representing the given template name
      */
-    public function loadTemplate($name, $macro = false)
+    public function loadTemplate($name)
     {
-        $cls = $this->getTemplateClass($name).($macro ? '_Macro' : '');
+        $cls = $this->getTemplateClass($name);
 
         if (isset($this->loadedTemplates[$cls])) {
             return $this->loadedTemplates[$cls];
index 73b6dab..9aae0bc 100644 (file)
@@ -18,6 +18,10 @@ class Twig_Node_Expression_Name extends Twig_Node_Expression
 
     public function compile($compiler)
     {
-        $compiler->raw(sprintf('$this->getContext($context, \'%s\')', $this['name'], $this['name']));
+        if ('self' === $this['name']) {
+            $compiler->raw('$this');
+        } else {
+            $compiler->raw(sprintf('$this->getContext($context, \'%s\')', $this['name'], $this['name']));
+        }
     }
 }
index 984ff31..e86fc0e 100644 (file)
@@ -30,9 +30,18 @@ class Twig_Node_Import extends Twig_Node
             ->write('')
             ->subcompile($this->var)
             ->raw(' = ')
-            ->raw('$this->env->loadTemplate(')
-            ->subcompile($this->expr)
-            ->raw(", true);\n")
         ;
+
+        if ($this->expr instanceof Twig_Node_Expression_Name && 'self' === $this->expr['name']) {
+            $compiler->raw("\$this");
+        } else {
+            $compiler
+                ->raw('$this->env->loadTemplate(')
+                ->subcompile($this->expr)
+                ->raw(", true)")
+            ;
+        }
+
+        $compiler->raw(";\n");
     }
 }
index eeaddc8..de71710 100644 (file)
@@ -27,7 +27,6 @@ class Twig_Node_Module extends Twig_Node
     public function compile($compiler)
     {
         $this->compileTemplate($compiler);
-        $this->compileMacros($compiler);
     }
 
     protected function compileTemplate($compiler)
@@ -48,6 +47,8 @@ class Twig_Node_Module extends Twig_Node
 
         $this->compileGetName($compiler);
 
+        $this->compileMacros($compiler);
+
         $this->compileClassFooter($compiler);
     }
 
@@ -177,19 +178,6 @@ class Twig_Node_Module extends Twig_Node
 
     protected function compileMacros($compiler)
     {
-        $compiler
-            ->write("\n")
-            ->write('class '.$compiler->getEnvironment()->getTemplateClass($this['filename']).'_Macro extends Twig_Macro'."\n")
-            ->write("{\n")
-            ->indent()
-        ;
-
-        // macros
         $compiler->subcompile($this->macros);
-
-        $compiler
-            ->outdent()
-            ->write("}\n")
-        ;
     }
 }
index 2e78f2e..3fea5d4 100644 (file)
@@ -79,10 +79,6 @@ class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
     }
 
 }
-
-class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
-{
-}
 EOF
         , $twig);
 
@@ -116,10 +112,6 @@ class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
     }
 
 }
-
-class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
-{
-}
 EOF
         , $twig);
 
@@ -158,10 +150,6 @@ class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
     }
 
 }
-
-class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
-{
-}
 EOF
         , $twig);
 
index 4e2cd0b..49217c5 100644 (file)
@@ -84,10 +84,6 @@ class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
     }
 
 }
-
-class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
-{
-}
 EOF
         , $twig);
 
@@ -132,10 +128,6 @@ class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34 extends Twig_Template
     }
 
 }
-
-class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
-{
-}
 EOF
         , $twig);
 
index 2bbae8f..a1460ec 100644 (file)
@@ -1,10 +1,8 @@
 --TEST--
 "macro" tag
 --TEMPLATE--
-{% import 'index.twig' as forms %}
-
-{{ forms.input('username') }}
-{{ forms.input('password', null, 'password', 1) }}
+{{ self.input('username') }}
+{{ self.input('password', null, 'password', 1) }}
 
 {% macro input(name, value, type, size) %}
   <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
diff --git a/test/fixtures/tags/macro/self_import.test b/test/fixtures/tags/macro/self_import.test
new file mode 100644 (file)
index 0000000..ae55df8
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+"macro" tag
+--TEMPLATE--
+{% import self as forms %}
+
+{{ forms.input('username') }}
+{{ forms.input('password', null, 'password', 1) }}
+
+{% macro input(name, value, type, size) %}
+  <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
+{% endmacro %}
+--DATA--
+return array()
+--EXPECT--
+  <input type="text" name="username" value="" size="20">
+
+  <input type="password" name="password" value="" size="1">