NodeVisitor::getPriority()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/*
3
 * This file is part of the Twig Bufferized Template package, an RunOpenCode project.
4
 *
5
 * (c) 2017 RunOpenCode
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace RunOpenCode\Twig\BufferizedTemplate;
11
12
use RunOpenCode\Twig\BufferizedTemplate\Tag\Bufferize\Node as BufferizeNode;
13
use RunOpenCode\Twig\BufferizedTemplate\Tag\TemplateBuffer\BreakPoint;
14
use RunOpenCode\Twig\BufferizedTemplate\Tag\TemplateBuffer\Initialize;
15
use RunOpenCode\Twig\BufferizedTemplate\Tag\TemplateBuffer\Terminate;
16
17
/**
18
 * Class NodeVisitor
19
 *
20
 * Parses AST adding buffering tags on required templates.
21
 *
22
 * @package RunOpenCode\Twig\BufferizedTemplate
23
 *
24
 * @internal
25
 */
26
final class NodeVisitor extends \Twig_BaseNodeVisitor
27
{
28
    const CONTEXT_VARIABLE_NAME = '$_________runopencode_twig_bufferized_template_environment_variable_______iByUtNtcGcwrjomGoxjFQNuKmmOSVpZjLuKersvpdImnPTfXsCrfWXNrkpTV';
29
30
    /**
31
     * @var array
32
     */
33
    private $settings;
34
35
    /**
36
     * @var string Current template name.
37
     */
38
    protected $templateName;
39
40
    /**
41
     * @var bool Denotes if current template body should be bufferized.
42
     */
43
    private $shouldBufferize = false;
44
45
    /**
46
     * @var string Denotes current scope of AST (block or body).
47
     */
48
    private $currentScope;
49
50
    /**
51
     * @var \Twig_Node[] List of blocks for current template.
52
     */
53
    private $blocks;
54
55 10
    public function __construct(array $settings)
56
    {
57 10
        $this->settings = $settings;
58 10
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63 8
    protected function doEnterNode(\Twig_Node $node, \Twig_Environment $env)
64
    {
65 8
        if ($node instanceof \Twig_Node_Module) {
66 8
            $this->templateName = $node->getTemplateName();
67
        }
68
69 8
        if ($this->shouldProcess()) {
70
71 6
            if ($this->isBufferizingNode($node)) {
72 6
                $this->shouldBufferize = true;
73
            }
74
75 6
            if ($node instanceof \Twig_Node_Module) {
76 6
                $this->blocks = $node->getNode('blocks')->getIterator();
0 ignored issues
show
Documentation Bug introduced by
It seems like $node->getNode('blocks')->getIterator() of type object<Traversable> is incompatible with the declared type array<integer,object<Twig_Node>> of property $blocks.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
77
            }
78
79 6
            if ($node instanceof \Twig_Node_Body) {
80 6
                $this->currentScope = null;
81
            }
82
83 6
            if ($node instanceof \Twig_Node_Block) {
84 2
                $this->currentScope = $node->getAttribute('name');
85
            }
86
        }
87
88 8
        return $node;
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94 8
    protected function doLeaveNode(\Twig_Node $node, \Twig_Environment $env)
95
    {
96 8
        if ($node instanceof \Twig_Node_Module) {
97 8
            $this->templateName = null;
98
        }
99
100
101 8
        if ($this->shouldProcess()) {
102
103 7
            if ($node instanceof \Twig_Node_Module) {
104
105 7
                if ($this->shouldBufferize) {
106
107 6
                    $node->setNode('body', new \Twig_Node([
108 6
                        new Initialize([], [
109 6
                            'bufferized_context_variable_name' => self::CONTEXT_VARIABLE_NAME
110
                        ]),
111 6
                        $node->getNode('body'),
112 6
                        new Terminate([], [
113 6
                            'bufferized_context_variable_name' => self::CONTEXT_VARIABLE_NAME,
114 6
                            'execution_priority' => $this->settings['default_execution_priority']
115
                        ])
116
                    ]));
117
                }
118
119 7
                $this->shouldBufferize = false;
120 7
                $this->blocks = [];
121
            }
122
123 7
            if ($this->isBufferizingNode($node) || ($node instanceof \Twig_Node_BlockReference && $this->hasBufferizingNode($this->blocks[$node->getAttribute('name')]))) {
124
125 6
                return new \Twig_Node([
126 6
                    new BreakPoint([], [
127 6
                        'bufferized_context_variable_name' => self::CONTEXT_VARIABLE_NAME,
128 6
                        'execution_priority' => $this->settings['default_execution_priority']
129
                    ]),
130 6
                    $node,
131 6
                    new BreakPoint([], [
132 6
                        'bufferized_context_variable_name' => self::CONTEXT_VARIABLE_NAME,
133 6
                        'execution_priority' => $this->getNodeExecutionPriority($node)
134
                    ])
135
                ]);
136
137
            }
138
139 7
            if ($this->currentScope && $node instanceof \Twig_Node_Block && $this->hasBufferizingNode($node)) {
140
141 1
                $node->setNode('body', new \Twig_Node([
142 1
                    new Initialize([], [
143 1
                        'bufferized_context_variable_name' => self::CONTEXT_VARIABLE_NAME
144
                    ]),
145 1
                    $node->getNode('body'),
146 1
                    new Terminate([], [
147 1
                        'bufferized_context_variable_name' => self::CONTEXT_VARIABLE_NAME,
148 1
                        'execution_priority' => $this->settings['default_execution_priority']
149
                    ])
150
                ]));
151
152 1
                return $node;
153
            }
154
155
        }
156
157 8
        return $node;
158
    }
159
160
    /**
161
     * {@inheritdoc}
162
     */
163 8
    public function getPriority()
164
    {
165 8
        return $this->settings['node_visitor_priority'];
166
    }
167
168
    /**
169
     * Check if current template should be processed with node visitor based on whitelist or blacklist.
170
     *
171
     * @return bool
172
     */
173 8
    private function shouldProcess()
174
    {
175 8
        if (count($this->settings['whitelist']) > 0) {
176 1
            return in_array($this->templateName, $this->settings['whitelist'], true);
177
        }
178
179 7
        if (count($this->settings['blacklist']) > 0) {
180 1
            return !in_array($this->templateName, $this->settings['blacklist'], true);
181
        }
182
183 6
        return true;
184
    }
185
186
    /**
187
     * Check if provided node is node for bufferizing.
188
     *
189
     * @param \Twig_Node $node
190
     * @return bool
191
     */
192 7
    private function isBufferizingNode(\Twig_Node $node)
193
    {
194 7
        foreach ($this->settings['nodes'] as $nodeClass => $priority) {
195
196 7
            if ($node instanceof $nodeClass) {
197 7
                return true;
198
            }
199
        }
200
201 7
        return false;
202
    }
203
204
    /**
205
     * Checks if current node is asset injection node, or if such node exists in its sub-tree.
206
     *
207
     * @param \Twig_Node $node Node to check.
208
     * @return bool TRUE if this subtree has bufferizing node.
209
     */
210 2
    private function hasBufferizingNode(\Twig_Node $node)
211
    {
212 2
        if ($this->isBufferizingNode($node)) {
213 1
            return true;
214
        }
215
216 2
        $has = false;
217
218 2
        foreach ($node as $n) {
219
220
            if (
221 2
                ($has |= $this->hasBufferizingNode($n))
222
                ||
223 2
                ($n instanceof \Twig_Node_BlockReference && $this->hasBufferizingNode($this->blocks[$n->getAttribute('name')]))
224
            ) {
225 2
                return true;
226
            }
227
        }
228
229 2
        return $has;
230
    }
231
232
    /**
233
     * Get execution priority of bufferized node.
234
     *
235
     * Get execution priority of bufferized node based on the node settings or configuration of the extension.
236
     *
237
     * @param \Twig_Node $node
238
     *
239
     * @return mixed
240
     */
241 6
    private function getNodeExecutionPriority(\Twig_Node $node)
242
    {
243 6
        if ($node instanceof BufferizeNode && null !== $node->getExecutionPriority()) {
244 4
            return $node->getExecutionPriority();
245
        }
246
247 4
        foreach ($this->settings['nodes'] as $nodeClass => $priority) {
248
249 4
            if (null !== $priority && $node instanceof $nodeClass) {
250 4
                return $priority;
251
            }
252
        }
253
254 2
        return $this->settings['default_execution_priority'];
255
    }
256
}
257