Skip to content

Commit

Permalink
added self variable, simplified macro management, added some more doc…
Browse files Browse the repository at this point in the history
…umentation for macros (closes twigphp#61)
  • Loading branch information
fabpot committed Jun 12, 2010
1 parent c017a93 commit a8031fc
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 51 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Expand Up @@ -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
Expand Down
62 changes: 56 additions & 6 deletions doc/02-Twig-for-Template-Designers.markdown
Expand Up @@ -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:
Expand All @@ -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 %}
Expand All @@ -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
Expand Down Expand Up @@ -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>
Expand All @@ -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 #}
Expand All @@ -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>

Expand Down
5 changes: 2 additions & 3 deletions lib/Twig/Environment.php
Expand Up @@ -179,13 +179,12 @@ public function getTemplateClass($name)
* 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];
Expand Down
6 changes: 5 additions & 1 deletion lib/Twig/Node/Expression/Name.php
Expand Up @@ -18,6 +18,10 @@ public function __construct($name, $lineno)

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']));
}
}
}
15 changes: 12 additions & 3 deletions lib/Twig/Node/Import.php
Expand Up @@ -30,9 +30,18 @@ public function compile($compiler)
->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");
}
}
16 changes: 2 additions & 14 deletions lib/Twig/Node/Module.php
Expand Up @@ -27,7 +27,6 @@ public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $pare
public function compile($compiler)
{
$this->compileTemplate($compiler);
$this->compileMacros($compiler);
}

protected function compileTemplate($compiler)
Expand All @@ -48,6 +47,8 @@ protected function compileTemplate($compiler)

$this->compileGetName($compiler);

$this->compileMacros($compiler);

$this->compileClassFooter($compiler);
}

Expand Down Expand Up @@ -177,19 +178,6 @@ protected function compileClassFooter($compiler)

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")
;
}
}
12 changes: 0 additions & 12 deletions test/Twig/Tests/Node/ModuleTest.php
Expand Up @@ -79,10 +79,6 @@ public function getName()
}
}
class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
{
}
EOF
, $twig);

Expand Down Expand Up @@ -116,10 +112,6 @@ public function getName()
}
}
class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
{
}
EOF
, $twig);

Expand Down Expand Up @@ -158,10 +150,6 @@ public function getName()
}
}
class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
{
}
EOF
, $twig);

Expand Down
8 changes: 0 additions & 8 deletions test/Twig/Tests/Node/SandboxedModuleTest.php
Expand Up @@ -84,10 +84,6 @@ public function getName()
}
}
class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
{
}
EOF
, $twig);

Expand Down Expand Up @@ -132,10 +128,6 @@ public function getName()
}
}
class __TwigTemplate_be925a7b06dda0dfdbd18a1509f7eb34_Macro extends Twig_Macro
{
}
EOF
, $twig);

Expand Down
6 changes: 2 additions & 4 deletions 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) %}
<input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
Expand Down
17 changes: 17 additions & 0 deletions 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) %}
<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">

0 comments on commit a8031fc

Please sign in to comment.