From a8031fc96a8dbb88c223c7046cd4ffdd385c770b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 12 Jun 2010 11:27:38 +0200 Subject: [PATCH] added self variable, simplified macro management, added some more documentation for macros (closes #61) --- CHANGELOG | 1 + doc/02-Twig-for-Template-Designers.markdown | 62 +++++++++++++++++++++++--- lib/Twig/Environment.php | 5 +- lib/Twig/Node/Expression/Name.php | 6 ++- lib/Twig/Node/Import.php | 15 +++++- lib/Twig/Node/Module.php | 16 +------ test/Twig/Tests/Node/ModuleTest.php | 12 ----- test/Twig/Tests/Node/SandboxedModuleTest.php | 8 --- test/fixtures/tags/macro/basic.test | 6 +-- test/fixtures/tags/macro/self_import.test | 17 +++++++ 10 files changed, 97 insertions(+), 51 deletions(-) create mode 100644 test/fixtures/tags/macro/self_import.test diff --git a/CHANGELOG b/CHANGELOG index cb0ebfa..46d1302 100644 --- 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 diff --git a/doc/02-Twig-for-Template-Designers.markdown b/doc/02-Twig-for-Template-Designers.markdown index e3336ee..6a9d292 100644 --- a/doc/02-Twig-for-Template-Designers.markdown +++ b/doc/02-Twig-for-Template-Designers.markdown @@ -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:

{{ forms.input('username') }}

{{ forms.input('password', none, 'password') }}

+If the macros are defined and used in the same template, you can use the +special `self` variable, without importing them: + + [twig] +

{{ self.input('username') }}

+ +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) %} + + {% endmacro %} + + {% macro wrapped_input(name, value, type, size) %} +
+ {{ self.input(name, value, type, size) }} +
+ {% endmacro %} + +When the macro is defined in another file, you need to import it: + + [twig] + {# forms.html #} + + {% macro input(name, value, type, size) %} + + {% endmacro %} + + {# shortcuts.html #} + + {% macro wrapped_input(name, value, type, size) %} + {% import "forms.html" as forms %} +
+ {{ forms.input(name, value, type, size) }} +
+ {% 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 %} +
Username
{{ forms.input('username') }}
@@ -736,8 +775,19 @@ Importing these macros in a template is as easy as using the `import` tag:

{{ forms.textarea('comment') }}

-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) %} + + {% endmacro %} + +

{{ self.textarea('comment') }}

+ +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: {% endmacro %} - {% import "index.html" as forms %} + {% import self as forms %}

{{ forms.textarea('comment') }}

diff --git a/lib/Twig/Environment.php b/lib/Twig/Environment.php index 12c5269..2e17ed8 100644 --- a/lib/Twig/Environment.php +++ b/lib/Twig/Environment.php @@ -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]; diff --git a/lib/Twig/Node/Expression/Name.php b/lib/Twig/Node/Expression/Name.php index 73b6dab..9aae0bc 100644 --- a/lib/Twig/Node/Expression/Name.php +++ b/lib/Twig/Node/Expression/Name.php @@ -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'])); + } } } diff --git a/lib/Twig/Node/Import.php b/lib/Twig/Node/Import.php index 984ff31..e86fc0e 100644 --- a/lib/Twig/Node/Import.php +++ b/lib/Twig/Node/Import.php @@ -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"); } } diff --git a/lib/Twig/Node/Module.php b/lib/Twig/Node/Module.php index eeaddc8..de71710 100644 --- a/lib/Twig/Node/Module.php +++ b/lib/Twig/Node/Module.php @@ -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") - ; } } diff --git a/test/Twig/Tests/Node/ModuleTest.php b/test/Twig/Tests/Node/ModuleTest.php index 2e78f2e..3fea5d4 100644 --- a/test/Twig/Tests/Node/ModuleTest.php +++ b/test/Twig/Tests/Node/ModuleTest.php @@ -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); diff --git a/test/Twig/Tests/Node/SandboxedModuleTest.php b/test/Twig/Tests/Node/SandboxedModuleTest.php index 4e2cd0b..49217c5 100644 --- a/test/Twig/Tests/Node/SandboxedModuleTest.php +++ b/test/Twig/Tests/Node/SandboxedModuleTest.php @@ -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); diff --git a/test/fixtures/tags/macro/basic.test b/test/fixtures/tags/macro/basic.test index 2bbae8f..a1460ec 100644 --- a/test/fixtures/tags/macro/basic.test +++ b/test/fixtures/tags/macro/basic.test @@ -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) %} diff --git a/test/fixtures/tags/macro/self_import.test b/test/fixtures/tags/macro/self_import.test new file mode 100644 index 0000000..ae55df8 --- /dev/null +++ b/test/fixtures/tags/macro/self_import.test @@ -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) %} + +{% endmacro %} +--DATA-- +return array() +--EXPECT-- + + + -- 1.7.2.5