Test Failed
Push — master ( 6a1530...bb1f7e )
by Justin
04:13
created

Twig_ExtensionSet::getBinaryOperators()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 0
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
12
/**
13
 * @author Fabien Potencier <[email protected]>
14
 *
15
 * @internal
16
 */
17
final class Twig_ExtensionSet
18
{
19
    private $extensions;
20
    private $initialized = false;
21
    private $runtimeInitialized = false;
22
    private $staging;
23
    private $parsers;
24
    private $visitors;
25
    private $filters;
26
    private $tests;
27
    private $functions;
28
    private $unaryOperators;
29
    private $binaryOperators;
30
    private $globals;
31
    private $functionCallbacks = array();
32
    private $filterCallbacks = array();
33
    private $lastModified = 0;
34
35
    public function __construct()
36
    {
37
        $this->staging = new Twig_Extension_Staging();
38
    }
39
40
    /**
41
     * Initializes the runtime environment.
42
     */
43
    public function initRuntime(Twig_Environment $env)
44
    {
45
        if ($this->runtimeInitialized) {
46
            return;
47
        }
48
49
        $this->runtimeInitialized = true;
50
51
        foreach ($this->extensions as $extension) {
52
            if ($extension instanceof Twig_Extension_InitRuntimeInterface) {
53
                $extension->initRuntime($env);
54
            }
55
        }
56
    }
57
58
    /**
59
     * Returns true if the given extension is registered.
60
     *
61
     * @param string $class The extension class name
62
     *
63
     * @return bool Whether the extension is registered or not
64
     */
65
    public function hasExtension($class)
66
    {
67
        $class = ltrim($class, '\\');
68
        if (!isset($this->extensions[$class]) && class_exists($class, false)) {
69
            // For BC/FC with namespaced aliases
70
            $class = (new ReflectionClass($class))->name;
71
        }
72
73
        return isset($this->extensions[$class]);
74
    }
75
76
    /**
77
     * Gets an extension by class name.
78
     *
79
     * @param string $class The extension class name
80
     *
81
     * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
82
     */
83
    public function getExtension($class)
84
    {
85
        $class = ltrim($class, '\\');
86
        if (!isset($this->extensions[$class]) && class_exists($class, false)) {
87
            // For BC/FC with namespaced aliases
88
            $class = (new ReflectionClass($class))->name;
89
        }
90
91
        if (!isset($this->extensions[$class])) {
92
            throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $class));
93
        }
94
95
        return $this->extensions[$class];
96
    }
97
98
    /**
99
     * Registers an array of extensions.
100
     *
101
     * @param array $extensions An array of extensions
102
     */
103
    public function setExtensions(array $extensions)
104
    {
105
        foreach ($extensions as $extension) {
106
            $this->addExtension($extension);
107
        }
108
    }
109
110
    /**
111
     * Returns all registered extensions.
112
     *
113
     * @return array An array of extensions
114
     */
115
    public function getExtensions()
116
    {
117
        return $this->extensions;
118
    }
119
120
    public function getSignature()
121
    {
122
        return json_encode(array_keys($this->extensions));
123
    }
124
125
    public function isInitialized()
126
    {
127
        return $this->initialized || $this->runtimeInitialized;
128
    }
129
130
    public function getLastModified()
131
    {
132
        if (0 !== $this->lastModified) {
133
            return $this->lastModified;
134
        }
135
136
        foreach ($this->extensions as $extension) {
137
            $r = new ReflectionObject($extension);
138
            if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModified) {
139
                $this->lastModified = $extensionTime;
140
            }
141
        }
142
143
        return $this->lastModified;
144
    }
145
146
    /**
147
     * Registers an extension.
148
     *
149
     * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
150
     */
151
    public function addExtension(Twig_ExtensionInterface $extension)
152
    {
153
        $class = get_class($extension);
154
155
        if ($this->initialized) {
156
            throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
157
        }
158
159
        if (isset($this->extensions[$class])) {
160
            throw new LogicException(sprintf('Unable to register extension "%s" as it is already registered.', $class));
161
        }
162
163
        $this->extensions[$class] = $extension;
164
    }
165
166
    public function addFunction(Twig_Function $function)
167
    {
168
        if ($this->initialized) {
169
            throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $function->getName()));
170
        }
171
172
        $this->staging->addFunction($function);
173
    }
174
175
    public function getFunctions()
176
    {
177
        if (!$this->initialized) {
178
            $this->initExtensions();
179
        }
180
181
        return $this->functions;
182
    }
183
184
    /**
185
     * Get a function by name.
186
     *
187
     * @param string $name function name
188
     *
189
     * @return Twig_Function|false A Twig_Function instance or false if the function does not exist
190
     */
191
    public function getFunction($name)
192
    {
193
        if (!$this->initialized) {
194
            $this->initExtensions();
195
        }
196
197
        if (isset($this->functions[$name])) {
198
            return $this->functions[$name];
199
        }
200
201
        foreach ($this->functions as $pattern => $function) {
202
            $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
203
204
            if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) {
205
                array_shift($matches);
206
                $function->setArguments($matches);
207
208
                return $function;
209
            }
210
        }
211
212
        foreach ($this->functionCallbacks as $callback) {
213
            if (false !== $function = $callback($name)) {
214
                return $function;
215
            }
216
        }
217
218
        return false;
219
    }
220
221
    public function registerUndefinedFunctionCallback(callable $callable)
222
    {
223
        $this->functionCallbacks[] = $callable;
224
    }
225
226
    public function addFilter(Twig_Filter $filter)
227
    {
228
        if ($this->initialized) {
229
            throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName()));
230
        }
231
232
        $this->staging->addFilter($filter);
233
    }
234
235
    public function getFilters()
236
    {
237
        if (!$this->initialized) {
238
            $this->initExtensions();
239
        }
240
241
        return $this->filters;
242
    }
243
244
    /**
245
     * Get a filter by name.
246
     *
247
     * Subclasses may override this method and load filters differently;
248
     * so no list of filters is available.
249
     *
250
     * @param string $name The filter name
251
     *
252
     * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
253
     */
254
    public function getFilter($name)
255
    {
256
        if (!$this->initialized) {
257
            $this->initExtensions();
258
        }
259
260
        if (isset($this->filters[$name])) {
261
            return $this->filters[$name];
262
        }
263
264
        foreach ($this->filters as $pattern => $filter) {
265
            $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
266
267
            if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) {
268
                array_shift($matches);
269
                $filter->setArguments($matches);
270
271
                return $filter;
272
            }
273
        }
274
275
        foreach ($this->filterCallbacks as $callback) {
276
            if (false !== $filter = $callback($name)) {
277
                return $filter;
278
            }
279
        }
280
281
        return false;
282
    }
283
284
    public function registerUndefinedFilterCallback(callable $callable)
285
    {
286
        $this->filterCallbacks[] = $callable;
287
    }
288
289
    public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
290
    {
291
        if ($this->initialized) {
292
            throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
293
        }
294
295
        $this->staging->addNodeVisitor($visitor);
296
    }
297
298
    public function getNodeVisitors()
299
    {
300
        if (!$this->initialized) {
301
            $this->initExtensions();
302
        }
303
304
        return $this->visitors;
305
    }
306
307
    public function addTokenParser(Twig_TokenParserInterface $parser)
308
    {
309
        if ($this->initialized) {
310
            throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
311
        }
312
313
        $this->staging->addTokenParser($parser);
314
    }
315
316
    public function getTokenParsers()
317
    {
318
        if (!$this->initialized) {
319
            $this->initExtensions();
320
        }
321
322
        return $this->parsers;
323
    }
324
325
    public function getGlobals()
326
    {
327
        if (null !== $this->globals) {
328
            return $this->globals;
329
        }
330
331
        $globals = array();
332
        foreach ($this->extensions as $extension) {
333
            if (!$extension instanceof Twig_Extension_GlobalsInterface) {
334
                continue;
335
            }
336
337
            $extGlobals = $extension->getGlobals();
338
            if (!is_array($extGlobals)) {
339
                throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
340
            }
341
342
            $globals = array_merge($globals, $extGlobals);
343
        }
344
345
        if ($this->initialized) {
346
            $this->globals = $globals;
347
        }
348
349
        return $globals;
350
    }
351
352
    public function addTest(Twig_Test $test)
353
    {
354
        if ($this->initialized) {
355
            throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName()));
356
        }
357
358
        $this->staging->addTest($test);
359
    }
360
361
    public function getTests()
362
    {
363
        if (!$this->initialized) {
364
            $this->initExtensions();
365
        }
366
367
        return $this->tests;
368
    }
369
370
    /**
371
     * Gets a test by name.
372
     *
373
     * @param string $name The test name
374
     *
375
     * @return Twig_Test|false A Twig_Test instance or false if the test does not exist
376
     */
377
    public function getTest($name)
378
    {
379
        if (!$this->initialized) {
380
            $this->initExtensions();
381
        }
382
383
        if (isset($this->tests[$name])) {
384
            return $this->tests[$name];
385
        }
386
387
        return false;
388
    }
389
390
    /**
391
     * Gets the registered unary Operators.
392
     *
393
     * @return array An array of unary operators
394
     */
395
    public function getUnaryOperators()
396
    {
397
        if (!$this->initialized) {
398
            $this->initExtensions();
399
        }
400
401
        return $this->unaryOperators;
402
    }
403
404
    /**
405
     * Gets the registered binary Operators.
406
     *
407
     * @return array An array of binary operators
408
     */
409
    public function getBinaryOperators()
410
    {
411
        if (!$this->initialized) {
412
            $this->initExtensions();
413
        }
414
415
        return $this->binaryOperators;
416
    }
417
418
    private function initExtensions()
419
    {
420
        $this->parsers = array();
421
        $this->filters = array();
422
        $this->functions = array();
423
        $this->tests = array();
424
        $this->visitors = array();
425
        $this->unaryOperators = array();
426
        $this->binaryOperators = array();
427
428
        foreach ($this->extensions as $extension) {
429
            $this->initExtension($extension);
430
        }
431
        $this->initExtension($this->staging);
432
        // Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception
433
        $this->initialized = true;
434
    }
435
436
    private function initExtension(Twig_ExtensionInterface $extension)
437
    {
438
        // filters
439
        foreach ($extension->getFilters() as $filter) {
440
            $this->filters[$filter->getName()] = $filter;
441
        }
442
443
        // functions
444
        foreach ($extension->getFunctions() as $function) {
445
            $this->functions[$function->getName()] = $function;
446
        }
447
448
        // tests
449
        foreach ($extension->getTests() as $test) {
450
            $this->tests[$test->getName()] = $test;
451
        }
452
453
        // token parsers
454
        foreach ($extension->getTokenParsers() as $parser) {
455
            if (!$parser instanceof Twig_TokenParserInterface) {
456
                throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface.');
457
            }
458
459
            $this->parsers[] = $parser;
460
        }
461
462
        // node visitors
463
        foreach ($extension->getNodeVisitors() as $visitor) {
464
            $this->visitors[] = $visitor;
465
        }
466
467
        // operators
468
        if ($operators = $extension->getOperators()) {
469
            if (!is_array($operators)) {
0 ignored issues
show
introduced by
The condition is_array($operators) is always true.
Loading history...
470
                throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', get_class($extension), is_object($operators) ? get_class($operators) : gettype($operators).(is_resource($operators) ? '' : '#'.$operators)));
471
            }
472
473
            if (2 !== count($operators)) {
474
                throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', get_class($extension), count($operators)));
475
            }
476
477
            $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
478
            $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
479
        }
480
    }
481
}
482
483
class_alias('Twig_ExtensionSet', 'Twig\ExtensionSet', false);
484