1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Twig\NodeVisitor;
13
14use Twig\Environment;
15use Twig\Node\Expression\AssignNameExpression;
16use Twig\Node\Expression\ConstantExpression;
17use Twig\Node\Expression\GetAttrExpression;
18use Twig\Node\Expression\MethodCallExpression;
19use Twig\Node\Expression\NameExpression;
20use Twig\Node\ImportNode;
21use Twig\Node\ModuleNode;
22use Twig\Node\Node;
23
24/**
25 * @author Fabien Potencier <fabien@symfony.com>
26 */
27final class MacroAutoImportNodeVisitor implements NodeVisitorInterface
28{
29    private $inAModule = false;
30    private $hasMacroCalls = false;
31
32    public function enterNode(Node $node, Environment $env)
33    {
34        if ($node instanceof ModuleNode) {
35            $this->inAModule = true;
36            $this->hasMacroCalls = false;
37        }
38
39        return $node;
40    }
41
42    public function leaveNode(Node $node, Environment $env)
43    {
44        if ($node instanceof ModuleNode) {
45            $this->inAModule = false;
46            if ($this->hasMacroCalls) {
47                $node->getNode('constructor_end')->setNode('_auto_macro_import', new ImportNode(new NameExpression('_self', 0), new AssignNameExpression('_self', 0), 0, 'import', true));
48            }
49        } elseif ($this->inAModule) {
50            if (
51                $node instanceof GetAttrExpression &&
52                $node->getNode('node') instanceof NameExpression &&
53                '_self' === $node->getNode('node')->getAttribute('name') &&
54                $node->getNode('attribute') instanceof ConstantExpression
55            ) {
56                $this->hasMacroCalls = true;
57
58                $name = $node->getNode('attribute')->getAttribute('value');
59                $node = new MethodCallExpression($node->getNode('node'), 'macro_'.$name, $node->getNode('arguments'), $node->getTemplateLine());
60                $node->setAttribute('safe', true);
61            }
62        }
63
64        return $node;
65    }
66
67    public function getPriority()
68    {
69        // we must be ran before auto-escaping
70        return -10;
71    }
72}
73