source: pro-violet-viettel/sourcecode/application/third_party/Twig/NodeVisitor/Optimizer.php @ 345

Last change on this file since 345 was 345, checked in by quyenla, 11 years ago

collaborator page

File size: 4.8 KB
Line 
1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) 2010 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
12/**
13 * Twig_NodeVisitor_Optimizer tries to optimizes the AST.
14 *
15 * This visitor is always the last registered one.
16 *
17 * You can configure which optimizations you want to activate via the
18 * optimizer mode.
19 *
20 * @package twig
21 * @author  Fabien Potencier <fabien.potencier@symfony-project.com>
22 */
23class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
24{
25    const OPTIMIZE_ALL         = -1;
26    const OPTIMIZE_NONE        = 0;
27    const OPTIMIZE_FOR         = 2;
28    const OPTIMIZE_RAW_FILTER  = 4;
29
30    protected $loops = array();
31    protected $optimizers;
32
33    /**
34     * Constructor.
35     *
36     * @param integer $optimizers The optimizer mode
37     */
38    public function __construct($optimizers = -1)
39    {
40        if (!is_int($optimizers) || $optimizers > 2) {
41            throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
42        }
43
44        $this->optimizers = $optimizers;
45    }
46
47    /**
48     * {@inheritdoc}
49     */
50    public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
51    {
52        if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
53            $this->enterOptimizeFor($node, $env);
54        }
55
56        return $node;
57    }
58
59    /**
60     * {@inheritdoc}
61     */
62    public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
63    {
64        if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
65            $this->leaveOptimizeFor($node, $env);
66        }
67
68        if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
69            $node = $this->optimizeRawFilter($node, $env);
70        }
71
72        return $node;
73    }
74
75    /**
76     * Removes "raw" filters.
77     *
78     * @param Twig_NodeInterface $node A Node
79     * @param Twig_Environment   $env  The current Twig environment
80     */
81    protected function optimizeRawFilter($node, $env)
82    {
83        if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) {
84            return $node->getNode('node');
85        }
86
87        return $node;
88    }
89
90    /**
91     * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
92     *
93     * @param Twig_NodeInterface $node A Node
94     * @param Twig_Environment   $env  The current Twig environment
95     */
96    protected function enterOptimizeFor($node, $env)
97    {
98        if ($node instanceof Twig_Node_For) {
99            // disable the loop variable by default
100            $node->setAttribute('with_loop', false);
101            array_unshift($this->loops, $node);
102        } elseif (!$this->loops) {
103            // we are outside a loop
104            return;
105        }
106
107        // when do we need to add the loop variable back?
108
109        // the loop variable is referenced for the current loop
110        elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
111            $this->addLoopToCurrent();
112        }
113
114        // block reference
115        elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
116            $this->addLoopToCurrent();
117        }
118
119        // include without the only attribute
120        elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
121            $this->addLoopToAll();
122        }
123
124        // the loop variable is referenced via an attribute
125        elseif ($node instanceof Twig_Node_Expression_GetAttr
126            && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
127                || 'parent' === $node->getNode('attribute')->getAttribute('value')
128               )
129            && (true === $this->loops[0]->getAttribute('with_loop')
130                || ($node->getNode('node') instanceof Twig_Node_Expression_Name
131                    && 'loop' === $node->getNode('node')->getAttribute('name')
132                   )
133               )
134        ) {
135            $this->addLoopToAll();
136        }
137    }
138
139    /**
140     * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
141     *
142     * @param Twig_NodeInterface $node A Node
143     * @param Twig_Environment   $env  The current Twig environment
144     */
145    protected function leaveOptimizeFor($node, $env)
146    {
147        if ($node instanceof Twig_Node_For) {
148            array_shift($this->loops);
149        }
150    }
151
152    protected function addLoopToCurrent()
153    {
154        $this->loops[0]->setAttribute('with_loop', true);
155    }
156
157    protected function addLoopToAll()
158    {
159        foreach ($this->loops as $loop) {
160            $loop->setAttribute('with_loop', true);
161        }
162    }
163
164    /**
165     * {@inheritdoc}
166     */
167    public function getPriority()
168    {
169        return 255;
170    }
171}
Note: See TracBrowser for help on using the repository browser.