mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-31 20:47:28 +00:00
Local macros auto-import
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
* 2.11.0 (2019-XX-XX)
|
||||
|
||||
* macros are now auto-imported in the template they are defined (under the ``_self`` variable)
|
||||
* added support for macros on "is defined" tests
|
||||
* fixed macros "import" when using the same name in the parent and child templates
|
||||
* fixed recursive macros
|
||||
|
||||
+14
-1
@@ -74,7 +74,20 @@ via the ``from`` tag:
|
||||
|
||||
.. tip::
|
||||
|
||||
To import macros from the current file, use the special ``_self`` variable:
|
||||
When macro usages and definitions are in the same template, you don't need to
|
||||
import the macros as they are automatically available under the special
|
||||
``_self`` variable:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
<p>{{ _self.input('password', '', 'password') }}</p>
|
||||
|
||||
{% macro input(name, value, type = "text", size = 20) %}
|
||||
<input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
|
||||
{% endmacro %}
|
||||
|
||||
Auto-import is only available as of Twig 2.11. For older versions, import
|
||||
macros using the special ``_self`` variable for the template name:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ use Twig\Node\Expression\Test\SameasTest;
|
||||
use Twig\Node\Expression\Unary\NegUnary;
|
||||
use Twig\Node\Expression\Unary\NotUnary;
|
||||
use Twig\Node\Expression\Unary\PosUnary;
|
||||
use Twig\NodeVisitor\MacroAutoImportNodeVisitor;
|
||||
use Twig\TokenParser\ApplyTokenParser;
|
||||
use Twig\TokenParser\BlockTokenParser;
|
||||
use Twig\TokenParser\DeprecatedTokenParser;
|
||||
@@ -281,6 +282,11 @@ final class CoreExtension extends AbstractExtension
|
||||
];
|
||||
}
|
||||
|
||||
public function getNodeVisitors()
|
||||
{
|
||||
return [new MacroAutoImportNodeVisitor()];
|
||||
}
|
||||
|
||||
public function getOperators()
|
||||
{
|
||||
return [
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\NodeVisitor;
|
||||
|
||||
use Twig\Environment;
|
||||
use Twig\Node\Expression\AssignNameExpression;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Node\Expression\GetAttrExpression;
|
||||
use Twig\Node\Expression\MethodCallExpression;
|
||||
use Twig\Node\Expression\NameExpression;
|
||||
use Twig\Node\ImportNode;
|
||||
use Twig\Node\ModuleNode;
|
||||
use Twig\Node\Node;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
final class MacroAutoImportNodeVisitor implements NodeVisitorInterface
|
||||
{
|
||||
private $inAModule = false;
|
||||
private $hasMacroCalls = false;
|
||||
|
||||
public function enterNode(Node $node, Environment $env)
|
||||
{
|
||||
if ($node instanceof ModuleNode) {
|
||||
$this->inAModule = true;
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function leaveNode(Node $node, Environment $env)
|
||||
{
|
||||
if ($node instanceof ModuleNode) {
|
||||
$this->inAModule = false;
|
||||
if ($this->hasMacroCalls) {
|
||||
$body = [new ImportNode(new NameExpression('_self', 0), new AssignNameExpression('_self', 0), 0, 'import', true)];
|
||||
foreach ($node->getNode('body') as $n) {
|
||||
$body[] = $n;
|
||||
}
|
||||
$node->setNode('body', new Node($body));
|
||||
}
|
||||
} elseif ($this->inAModule) {
|
||||
if (
|
||||
$node instanceof GetAttrExpression &&
|
||||
$node->getNode('node') instanceof NameExpression &&
|
||||
'_self' === $node->getNode('node')->getAttribute('name') &&
|
||||
$node->getNode('attribute') instanceof ConstantExpression
|
||||
) {
|
||||
$this->hasMacroCalls = true;
|
||||
|
||||
$name = $node->getNode('attribute')->getAttribute('value');
|
||||
$node = new MethodCallExpression($node->getNode('node'), 'macro_'.$name, $node->getNode('arguments'), $node->getTemplateLine());
|
||||
$node->setAttribute('safe', true);
|
||||
}
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function getPriority()
|
||||
{
|
||||
// we must be ran before auto-escaping
|
||||
return -10;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
"macro" tag
|
||||
--TEMPLATE--
|
||||
{{ _self.hello('Fabien') }}
|
||||
|
||||
{% macro hello(name) -%}
|
||||
Hello {{ _self.up(name) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro up(name) -%}
|
||||
{{ name|upper }}
|
||||
{% endmacro %}
|
||||
--DATA--
|
||||
return []
|
||||
--EXPECT--
|
||||
Hello FABIEN
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
"macro" tag
|
||||
--TEMPLATE--
|
||||
{% block content %}
|
||||
{{ _self.hello('Fabien') }}
|
||||
{% endblock %}
|
||||
|
||||
{% macro hello(name) -%}
|
||||
Hello {{ _self.up(name) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro up(name) -%}
|
||||
{{ name|upper }}
|
||||
{% endmacro %}
|
||||
--DATA--
|
||||
return []
|
||||
--EXPECT--
|
||||
Hello FABIEN
|
||||
Reference in New Issue
Block a user