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

Twig_Environment::loadTemplate()   C

Complexity

Conditions 10
Paths 52

Size

Total Lines 55
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 55
rs 6.8372
c 0
b 0
f 0
cc 10
eloc 27
nc 52
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
 * Stores the Twig configuration.
14
 *
15
 * @author Fabien Potencier <[email protected]>
16
 */
17
class Twig_Environment
18
{
19
    const VERSION = '2.4.6';
20
    const VERSION_ID = 20406;
21
    const MAJOR_VERSION = 2;
22
    const MINOR_VERSION = 4;
23
    const RELEASE_VERSION = 5;
24
    const EXTRA_VERSION = '';
25
26
    private $charset;
27
    private $loader;
28
    private $debug;
29
    private $autoReload;
30
    private $cache;
31
    private $lexer;
32
    private $parser;
33
    private $compiler;
34
    private $baseTemplateClass;
35
    private $globals = array();
36
    private $resolvedGlobals;
37
    private $loadedTemplates;
38
    private $strictVariables;
39
    private $templateClassPrefix = '__TwigTemplate_';
40
    private $originalCache;
41
    private $extensionSet;
42
    private $runtimeLoaders = array();
43
    private $runtimes = array();
44
    private $optionsHash;
45
    private $loading = array();
46
47
    /**
48
     * Constructor.
49
     *
50
     * Available options:
51
     *
52
     *  * debug: When set to true, it automatically set "auto_reload" to true as
53
     *           well (default to false).
54
     *
55
     *  * charset: The charset used by the templates (default to UTF-8).
56
     *
57
     *  * base_template_class: The base template class to use for generated
58
     *                         templates (default to Twig_Template).
59
     *
60
     *  * cache: An absolute path where to store the compiled templates,
61
     *           a Twig_Cache_Interface implementation,
62
     *           or false to disable compilation cache (default).
63
     *
64
     *  * auto_reload: Whether to reload the template if the original source changed.
65
     *                 If you don't provide the auto_reload option, it will be
66
     *                 determined automatically based on the debug value.
67
     *
68
     *  * strict_variables: Whether to ignore invalid variables in templates
69
     *                      (default to false).
70
     *
71
     *  * autoescape: Whether to enable auto-escaping (default to html):
72
     *                  * false: disable auto-escaping
73
     *                  * html, js: set the autoescaping to one of the supported strategies
74
     *                  * name: set the autoescaping strategy based on the template name extension
75
     *                  * PHP callback: a PHP callback that returns an escaping strategy based on the template "name"
76
     *
77
     *  * optimizations: A flag that indicates which optimizations to apply
78
     *                   (default to -1 which means that all optimizations are enabled;
79
     *                   set it to 0 to disable).
80
     *
81
     * @param Twig_LoaderInterface $loader
82
     * @param array                $options An array of options
83
     */
84
    public function __construct(Twig_LoaderInterface $loader, $options = array())
85
    {
86
        $this->setLoader($loader);
87
88
        $options = array_merge(array(
89
            'debug' => false,
90
            'charset' => 'UTF-8',
91
            'base_template_class' => 'Twig_Template',
92
            'strict_variables' => false,
93
            'autoescape' => 'html',
94
            'cache' => false,
95
            'auto_reload' => null,
96
            'optimizations' => -1,
97
        ), $options);
98
99
        $this->debug = (bool) $options['debug'];
100
        $this->setCharset($options['charset']);
101
        $this->baseTemplateClass = $options['base_template_class'];
102
        $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
103
        $this->strictVariables = (bool) $options['strict_variables'];
104
        $this->setCache($options['cache']);
105
        $this->extensionSet = new Twig_ExtensionSet();
106
107
        $this->addExtension(new Twig_Extension_Core());
108
        $this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
109
        $this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
110
    }
111
112
    /**
113
     * Gets the base template class for compiled templates.
114
     *
115
     * @return string The base template class name
116
     */
117
    public function getBaseTemplateClass()
118
    {
119
        return $this->baseTemplateClass;
120
    }
121
122
    /**
123
     * Sets the base template class for compiled templates.
124
     *
125
     * @param string $class The base template class name
126
     */
127
    public function setBaseTemplateClass($class)
128
    {
129
        $this->baseTemplateClass = $class;
130
        $this->updateOptionsHash();
131
    }
132
133
    /**
134
     * Enables debugging mode.
135
     */
136
    public function enableDebug()
137
    {
138
        $this->debug = true;
139
        $this->updateOptionsHash();
140
    }
141
142
    /**
143
     * Disables debugging mode.
144
     */
145
    public function disableDebug()
146
    {
147
        $this->debug = false;
148
        $this->updateOptionsHash();
149
    }
150
151
    /**
152
     * Checks if debug mode is enabled.
153
     *
154
     * @return bool true if debug mode is enabled, false otherwise
155
     */
156
    public function isDebug()
157
    {
158
        return $this->debug;
159
    }
160
161
    /**
162
     * Enables the auto_reload option.
163
     */
164
    public function enableAutoReload()
165
    {
166
        $this->autoReload = true;
167
    }
168
169
    /**
170
     * Disables the auto_reload option.
171
     */
172
    public function disableAutoReload()
173
    {
174
        $this->autoReload = false;
175
    }
176
177
    /**
178
     * Checks if the auto_reload option is enabled.
179
     *
180
     * @return bool true if auto_reload is enabled, false otherwise
181
     */
182
    public function isAutoReload()
183
    {
184
        return $this->autoReload;
185
    }
186
187
    /**
188
     * Enables the strict_variables option.
189
     */
190
    public function enableStrictVariables()
191
    {
192
        $this->strictVariables = true;
193
        $this->updateOptionsHash();
194
    }
195
196
    /**
197
     * Disables the strict_variables option.
198
     */
199
    public function disableStrictVariables()
200
    {
201
        $this->strictVariables = false;
202
        $this->updateOptionsHash();
203
    }
204
205
    /**
206
     * Checks if the strict_variables option is enabled.
207
     *
208
     * @return bool true if strict_variables is enabled, false otherwise
209
     */
210
    public function isStrictVariables()
211
    {
212
        return $this->strictVariables;
213
    }
214
215
    /**
216
     * Gets the current cache implementation.
217
     *
218
     * @param bool $original Whether to return the original cache option or the real cache instance
219
     *
220
     * @return Twig_CacheInterface|string|false A Twig_CacheInterface implementation,
221
     *                                          an absolute path to the compiled templates,
222
     *                                          or false to disable cache
223
     */
224
    public function getCache($original = true)
225
    {
226
        return $original ? $this->originalCache : $this->cache;
227
    }
228
229
    /**
230
     * Sets the current cache implementation.
231
     *
232
     * @param Twig_CacheInterface|string|false $cache A Twig_CacheInterface implementation,
233
     *                                                an absolute path to the compiled templates,
234
     *                                                or false to disable cache
235
     */
236
    public function setCache($cache)
237
    {
238
        if (is_string($cache)) {
239
            $this->originalCache = $cache;
240
            $this->cache = new Twig_Cache_Filesystem($cache);
241
        } elseif (false === $cache) {
242
            $this->originalCache = $cache;
243
            $this->cache = new Twig_Cache_Null();
244
        } elseif ($cache instanceof Twig_CacheInterface) {
0 ignored issues
show
introduced by
$cache is always a sub-type of Twig_CacheInterface.
Loading history...
245
            $this->originalCache = $this->cache = $cache;
246
        } else {
247
            throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.'));
248
        }
249
    }
250
251
    /**
252
     * Gets the template class associated with the given string.
253
     *
254
     * The generated template class is based on the following parameters:
255
     *
256
     *  * The cache key for the given template;
257
     *  * The currently enabled extensions;
258
     *  * Whether the Twig C extension is available or not;
259
     *  * PHP version;
260
     *  * Twig version;
261
     *  * Options with what environment was created.
262
     *
263
     * @param string   $name  The name for which to calculate the template class name
264
     * @param int|null $index The index if it is an embedded template
265
     *
266
     * @return string The template class name
267
     */
268
    public function getTemplateClass($name, $index = null)
269
    {
270
        $key = $this->getLoader()->getCacheKey($name).$this->optionsHash;
271
272
        return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '_'.$index);
273
    }
274
275
    /**
276
     * Renders a template.
277
     *
278
     * @param string $name    The template name
279
     * @param array  $context An array of parameters to pass to the template
280
     *
281
     * @return string The rendered template
282
     *
283
     * @throws Twig_Error_Loader  When the template cannot be found
284
     * @throws Twig_Error_Syntax  When an error occurred during compilation
285
     * @throws Twig_Error_Runtime When an error occurred during rendering
286
     */
287
    public function render($name, array $context = array())
288
    {
289
        return $this->loadTemplate($name)->render($context);
290
    }
291
292
    /**
293
     * Displays a template.
294
     *
295
     * @param string $name    The template name
296
     * @param array  $context An array of parameters to pass to the template
297
     *
298
     * @throws Twig_Error_Loader  When the template cannot be found
299
     * @throws Twig_Error_Syntax  When an error occurred during compilation
300
     * @throws Twig_Error_Runtime When an error occurred during rendering
301
     */
302
    public function display($name, array $context = array())
303
    {
304
        $this->loadTemplate($name)->display($context);
305
    }
306
307
    /**
308
     * Loads a template.
309
     *
310
     * @param string|Twig_TemplateWrapper|Twig_Template $name The template name
311
     *
312
     * @throws Twig_Error_Loader  When the template cannot be found
313
     * @throws Twig_Error_Runtime When a previously generated cache is corrupted
314
     * @throws Twig_Error_Syntax  When an error occurred during compilation
315
     *
316
     * @return Twig_TemplateWrapper
317
     */
318
    public function load($name)
319
    {
320
        if ($name instanceof Twig_TemplateWrapper) {
321
            return $name;
322
        }
323
324
        if ($name instanceof Twig_Template) {
325
            return new Twig_TemplateWrapper($this, $name);
326
        }
327
328
        return new Twig_TemplateWrapper($this, $this->loadTemplate($name));
329
    }
330
331
    /**
332
     * Loads a template internal representation.
333
     *
334
     * This method is for internal use only and should never be called
335
     * directly.
336
     *
337
     * @param string $name  The template name
338
     * @param int    $index The index if it is an embedded template
339
     *
340
     * @return Twig_Template A template instance representing the given template name
341
     *
342
     * @throws Twig_Error_Loader  When the template cannot be found
343
     * @throws Twig_Error_Runtime When a previously generated cache is corrupted
344
     * @throws Twig_Error_Syntax  When an error occurred during compilation
345
     *
346
     * @internal
347
     */
348
    public function loadTemplate($name, $index = null)
349
    {
350
        $cls = $mainCls = $this->getTemplateClass($name);
351
        if (null !== $index) {
352
            $cls .= '_'.$index;
353
        }
354
355
        if (isset($this->loadedTemplates[$cls])) {
356
            return $this->loadedTemplates[$cls];
357
        }
358
359
        if (!class_exists($cls, false)) {
360
            $key = $this->cache->generateKey($name, $mainCls);
361
362
            if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
363
                $this->cache->load($key);
364
            }
365
366
            if (!class_exists($cls, false)) {
367
                $source = $this->getLoader()->getSourceContext($name);
368
                $content = $this->compileSource($source);
369
                $this->cache->write($key, $content);
370
                $this->cache->load($key);
371
372
                if (!class_exists($mainCls, false)) {
373
                    /* Last line of defense if either $this->bcWriteCacheFile was used,
374
                     * $this->cache is implemented as a no-op or we have a race condition
375
                     * where the cache was cleared between the above calls to write to and load from
376
                     * the cache.
377
                     */
378
                    eval('?>'.$content);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
379
                }
380
381
                if (!class_exists($cls, false)) {
382
                    throw new Twig_Error_Runtime(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.', $name, $index), -1, $source);
383
                }
384
            }
385
        }
386
387
        // to be removed in 3.0
388
        $this->extensionSet->initRuntime($this);
389
390
        if (isset($this->loading[$cls])) {
391
            throw new Twig_Error_Runtime(sprintf('Circular reference detected for Twig template "%s", path: %s.', $name, implode(' -> ', array_merge($this->loading, array($name)))));
392
        }
393
394
        $this->loading[$cls] = $name;
395
396
        try {
397
            $this->loadedTemplates[$cls] = new $cls($this);
398
        } finally {
399
            unset($this->loading[$cls]);
400
        }
401
402
        return $this->loadedTemplates[$cls];
403
    }
404
405
    /**
406
     * Creates a template from source.
407
     *
408
     * This method should not be used as a generic way to load templates.
409
     *
410
     * @param string $template The template name
411
     *
412
     * @return Twig_Template A template instance representing the given template name
413
     *
414
     * @throws Twig_Error_Loader When the template cannot be found
415
     * @throws Twig_Error_Syntax When an error occurred during compilation
416
     */
417
    public function createTemplate($template)
418
    {
419
        $name = sprintf('__string_template__%s', hash('sha256', $template, false));
420
421
        $loader = new Twig_Loader_Chain(array(
422
            new Twig_Loader_Array(array($name => $template)),
423
            $current = $this->getLoader(),
424
        ));
425
426
        $this->setLoader($loader);
427
        try {
428
            $template = $this->loadTemplate($name);
429
        } finally {
430
            $this->setLoader($current);
431
        }
432
433
        return $template;
434
    }
435
436
    /**
437
     * Returns true if the template is still fresh.
438
     *
439
     * Besides checking the loader for freshness information,
440
     * this method also checks if the enabled extensions have
441
     * not changed.
442
     *
443
     * @param string $name The template name
444
     * @param int    $time The last modification time of the cached template
445
     *
446
     * @return bool true if the template is fresh, false otherwise
447
     */
448
    public function isTemplateFresh($name, $time)
449
    {
450
        return $this->extensionSet->getLastModified() <= $time && $this->getLoader()->isFresh($name, $time);
451
    }
452
453
    /**
454
     * Tries to load a template consecutively from an array.
455
     *
456
     * Similar to loadTemplate() but it also accepts instances of Twig_Template and
457
     * Twig_TemplateWrapper, and an array of templates where each is tried to be loaded.
458
     *
459
     * @param string|Twig_Template|Twig_TemplateWrapper|array $names A template or an array of templates to try consecutively
460
     *
461
     * @return Twig_Template|Twig_TemplateWrapper
462
     *
463
     * @throws Twig_Error_Loader When none of the templates can be found
464
     * @throws Twig_Error_Syntax When an error occurred during compilation
465
     */
466
    public function resolveTemplate($names)
467
    {
468
        if (!is_array($names)) {
469
            $names = array($names);
470
        }
471
472
        foreach ($names as $name) {
473
            if ($name instanceof Twig_Template) {
474
                return $name;
475
            }
476
477
            if ($name instanceof Twig_TemplateWrapper) {
478
                return $name;
479
            }
480
481
            try {
482
                return $this->loadTemplate($name);
483
            } catch (Twig_Error_Loader $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
484
            }
485
        }
486
487
        if (1 === count($names)) {
488
            throw $e;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $e seems to be defined by a foreach iteration on line 472. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
489
        }
490
491
        throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
492
    }
493
494
    public function setLexer(Twig_Lexer $lexer)
495
    {
496
        $this->lexer = $lexer;
497
    }
498
499
    /**
500
     * Tokenizes a source code.
501
     *
502
     * @return Twig_TokenStream
503
     *
504
     * @throws Twig_Error_Syntax When the code is syntactically wrong
505
     */
506
    public function tokenize(Twig_Source $source)
507
    {
508
        if (null === $this->lexer) {
509
            $this->lexer = new Twig_Lexer($this);
510
        }
511
512
        return $this->lexer->tokenize($source);
513
    }
514
515
    public function setParser(Twig_Parser $parser)
516
    {
517
        $this->parser = $parser;
518
    }
519
520
    /**
521
     * Converts a token stream to a node tree.
522
     *
523
     * @return Twig_Node_Module
524
     *
525
     * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
526
     */
527
    public function parse(Twig_TokenStream $stream)
528
    {
529
        if (null === $this->parser) {
530
            $this->parser = new Twig_Parser($this);
531
        }
532
533
        return $this->parser->parse($stream);
534
    }
535
536
    public function setCompiler(Twig_Compiler $compiler)
537
    {
538
        $this->compiler = $compiler;
539
    }
540
541
    /**
542
     * Compiles a node and returns the PHP code.
543
     *
544
     * @return string The compiled PHP source code
545
     */
546
    public function compile(Twig_Node $node)
547
    {
548
        if (null === $this->compiler) {
549
            $this->compiler = new Twig_Compiler($this);
550
        }
551
552
        return $this->compiler->compile($node)->getSource();
553
    }
554
555
    /**
556
     * Compiles a template source code.
557
     *
558
     * @return string The compiled PHP source code
559
     *
560
     * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling
561
     */
562
    public function compileSource(Twig_Source $source)
563
    {
564
        try {
565
            return $this->compile($this->parse($this->tokenize($source)));
566
        } catch (Twig_Error $e) {
567
            $e->setSourceContext($source);
568
            throw $e;
569
        } catch (Exception $e) {
570
            throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
571
        }
572
    }
573
574
    public function setLoader(Twig_LoaderInterface $loader)
575
    {
576
        $this->loader = $loader;
577
    }
578
579
    /**
580
     * Gets the Loader instance.
581
     *
582
     * @return Twig_LoaderInterface
583
     */
584
    public function getLoader()
585
    {
586
        return $this->loader;
587
    }
588
589
    /**
590
     * Sets the default template charset.
591
     *
592
     * @param string $charset The default charset
593
     */
594
    public function setCharset($charset)
595
    {
596
        if ('UTF8' === $charset = strtoupper($charset)) {
597
            // iconv on Windows requires "UTF-8" instead of "UTF8"
598
            $charset = 'UTF-8';
599
        }
600
601
        $this->charset = $charset;
602
    }
603
604
    /**
605
     * Gets the default template charset.
606
     *
607
     * @return string The default charset
608
     */
609
    public function getCharset()
610
    {
611
        return $this->charset;
612
    }
613
614
    /**
615
     * Returns true if the given extension is registered.
616
     *
617
     * @param string $class The extension class name
618
     *
619
     * @return bool Whether the extension is registered or not
620
     */
621
    public function hasExtension($class)
622
    {
623
        return $this->extensionSet->hasExtension($class);
624
    }
625
626
    /**
627
     * Adds a runtime loader.
628
     */
629
    public function addRuntimeLoader(Twig_RuntimeLoaderInterface $loader)
630
    {
631
        $this->runtimeLoaders[] = $loader;
632
    }
633
634
    /**
635
     * Gets an extension by class name.
636
     *
637
     * @param string $class The extension class name
638
     *
639
     * @return Twig_ExtensionInterface
640
     */
641
    public function getExtension($class)
642
    {
643
        return $this->extensionSet->getExtension($class);
644
    }
645
646
    /**
647
     * Returns the runtime implementation of a Twig element (filter/function/test).
648
     *
649
     * @param string $class A runtime class name
650
     *
651
     * @return object The runtime implementation
652
     *
653
     * @throws Twig_Error_Runtime When the template cannot be found
654
     */
655
    public function getRuntime($class)
656
    {
657
        if (isset($this->runtimes[$class])) {
658
            return $this->runtimes[$class];
659
        }
660
661
        foreach ($this->runtimeLoaders as $loader) {
662
            if (null !== $runtime = $loader->load($class)) {
663
                return $this->runtimes[$class] = $runtime;
664
            }
665
        }
666
667
        throw new Twig_Error_Runtime(sprintf('Unable to load the "%s" runtime.', $class));
668
    }
669
670
    public function addExtension(Twig_ExtensionInterface $extension)
671
    {
672
        $this->extensionSet->addExtension($extension);
673
        $this->updateOptionsHash();
674
    }
675
676
    /**
677
     * Registers an array of extensions.
678
     *
679
     * @param array $extensions An array of extensions
680
     */
681
    public function setExtensions(array $extensions)
682
    {
683
        $this->extensionSet->setExtensions($extensions);
684
        $this->updateOptionsHash();
685
    }
686
687
    /**
688
     * Returns all registered extensions.
689
     *
690
     * @return Twig_ExtensionInterface[] An array of extensions (keys are for internal usage only and should not be relied on)
691
     */
692
    public function getExtensions()
693
    {
694
        return $this->extensionSet->getExtensions();
695
    }
696
697
    public function addTokenParser(Twig_TokenParserInterface $parser)
698
    {
699
        $this->extensionSet->addTokenParser($parser);
700
    }
701
702
    /**
703
     * Gets the registered Token Parsers.
704
     *
705
     * @return Twig_TokenParserInterface[]
706
     *
707
     * @internal
708
     */
709
    public function getTokenParsers()
710
    {
711
        return $this->extensionSet->getTokenParsers();
712
    }
713
714
    /**
715
     * Gets registered tags.
716
     *
717
     * @return Twig_TokenParserInterface[]
718
     *
719
     * @internal
720
     */
721
    public function getTags()
722
    {
723
        $tags = array();
724
        foreach ($this->getTokenParsers() as $parser) {
725
            $tags[$parser->getTag()] = $parser;
726
        }
727
728
        return $tags;
729
    }
730
731
    public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
732
    {
733
        $this->extensionSet->addNodeVisitor($visitor);
734
    }
735
736
    /**
737
     * Gets the registered Node Visitors.
738
     *
739
     * @return Twig_NodeVisitorInterface[]
740
     *
741
     * @internal
742
     */
743
    public function getNodeVisitors()
744
    {
745
        return $this->extensionSet->getNodeVisitors();
746
    }
747
748
    public function addFilter(Twig_Filter $filter)
749
    {
750
        $this->extensionSet->addFilter($filter);
751
    }
752
753
    /**
754
     * Get a filter by name.
755
     *
756
     * Subclasses may override this method and load filters differently;
757
     * so no list of filters is available.
758
     *
759
     * @param string $name The filter name
760
     *
761
     * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
762
     *
763
     * @internal
764
     */
765
    public function getFilter($name)
766
    {
767
        return $this->extensionSet->getFilter($name);
768
    }
769
770
    public function registerUndefinedFilterCallback(callable $callable)
771
    {
772
        $this->extensionSet->registerUndefinedFilterCallback($callable);
773
    }
774
775
    /**
776
     * Gets the registered Filters.
777
     *
778
     * Be warned that this method cannot return filters defined with registerUndefinedFilterCallback.
779
     *
780
     * @return Twig_Filter[]
781
     *
782
     * @see registerUndefinedFilterCallback
783
     *
784
     * @internal
785
     */
786
    public function getFilters()
787
    {
788
        return $this->extensionSet->getFilters();
789
    }
790
791
    /**
792
     * Registers a Test.
793
     *
794
     * @param Twig_Test $test A Twig_Test instance
795
     */
796
    public function addTest(Twig_Test $test)
797
    {
798
        $this->extensionSet->addTest($test);
799
    }
800
801
    /**
802
     * Gets the registered Tests.
803
     *
804
     * @return Twig_Test[]
805
     *
806
     * @internal
807
     */
808
    public function getTests()
809
    {
810
        return $this->extensionSet->getTests();
811
    }
812
813
    /**
814
     * Gets a test by name.
815
     *
816
     * @param string $name The test name
817
     *
818
     * @return Twig_Test|false A Twig_Test instance or false if the test does not exist
819
     *
820
     * @internal
821
     */
822
    public function getTest($name)
823
    {
824
        return $this->extensionSet->getTest($name);
825
    }
826
827
    public function addFunction(Twig_Function $function)
828
    {
829
        $this->extensionSet->addFunction($function);
830
    }
831
832
    /**
833
     * Get a function by name.
834
     *
835
     * Subclasses may override this method and load functions differently;
836
     * so no list of functions is available.
837
     *
838
     * @param string $name function name
839
     *
840
     * @return Twig_Function|false A Twig_Function instance or false if the function does not exist
841
     *
842
     * @internal
843
     */
844
    public function getFunction($name)
845
    {
846
        return $this->extensionSet->getFunction($name);
847
    }
848
849
    public function registerUndefinedFunctionCallback(callable $callable)
850
    {
851
        $this->extensionSet->registerUndefinedFunctionCallback($callable);
852
    }
853
854
    /**
855
     * Gets registered functions.
856
     *
857
     * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
858
     *
859
     * @return Twig_Function[]
860
     *
861
     * @see registerUndefinedFunctionCallback
862
     *
863
     * @internal
864
     */
865
    public function getFunctions()
866
    {
867
        return $this->extensionSet->getFunctions();
868
    }
869
870
    /**
871
     * Registers a Global.
872
     *
873
     * New globals can be added before compiling or rendering a template;
874
     * but after, you can only update existing globals.
875
     *
876
     * @param string $name  The global name
877
     * @param mixed  $value The global value
878
     */
879
    public function addGlobal($name, $value)
880
    {
881
        if ($this->extensionSet->isInitialized() && !array_key_exists($name, $this->getGlobals())) {
882
            throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
883
        }
884
885
        if (null !== $this->resolvedGlobals) {
886
            $this->resolvedGlobals[$name] = $value;
887
        } else {
888
            $this->globals[$name] = $value;
889
        }
890
    }
891
892
    /**
893
     * Gets the registered Globals.
894
     *
895
     * @return array An array of globals
896
     *
897
     * @internal
898
     */
899
    public function getGlobals()
900
    {
901
        if ($this->extensionSet->isInitialized()) {
902
            if (null === $this->resolvedGlobals) {
903
                $this->resolvedGlobals = array_merge($this->extensionSet->getGlobals(), $this->globals);
904
            }
905
906
            return $this->resolvedGlobals;
907
        }
908
909
        return array_merge($this->extensionSet->getGlobals(), $this->globals);
910
    }
911
912
    /**
913
     * Merges a context with the defined globals.
914
     *
915
     * @param array $context An array representing the context
916
     *
917
     * @return array The context merged with the globals
918
     */
919
    public function mergeGlobals(array $context)
920
    {
921
        // we don't use array_merge as the context being generally
922
        // bigger than globals, this code is faster.
923
        foreach ($this->getGlobals() as $key => $value) {
924
            if (!array_key_exists($key, $context)) {
925
                $context[$key] = $value;
926
            }
927
        }
928
929
        return $context;
930
    }
931
932
    /**
933
     * Gets the registered unary Operators.
934
     *
935
     * @return array An array of unary operators
936
     *
937
     * @internal
938
     */
939
    public function getUnaryOperators()
940
    {
941
        return $this->extensionSet->getUnaryOperators();
942
    }
943
944
    /**
945
     * Gets the registered binary Operators.
946
     *
947
     * @return array An array of binary operators
948
     *
949
     * @internal
950
     */
951
    public function getBinaryOperators()
952
    {
953
        return $this->extensionSet->getBinaryOperators();
954
    }
955
956
    private function updateOptionsHash()
957
    {
958
        $this->optionsHash = implode(':', array(
959
            $this->extensionSet->getSignature(),
960
            PHP_MAJOR_VERSION,
961
            PHP_MINOR_VERSION,
962
            self::VERSION,
963
            (int) $this->debug,
964
            $this->baseTemplateClass,
965
            (int) $this->strictVariables,
966
        ));
967
    }
968
}
969
970
class_alias('Twig_Environment', 'Twig\Environment', false);
971