Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
/*
4
 * This file is part of Mustache.php.
5
 *
6
 * (c) 2010-2017 Justin Hileman
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
 * A Mustache implementation in PHP.
14
 *
15
 * {@link http://defunkt.github.com/mustache}
16
 *
17
 * Mustache is a framework-agnostic logic-less templating language. It enforces separation of view
18
 * logic from template files. In fact, it is not even possible to embed logic in the template.
19
 *
20
 * This is very, very rad.
21
 *
22
 * @author Justin Hileman {@link http://justinhileman.com}
23
 */
24
class Mustache_Engine
25
{
26
    const VERSION        = '2.14.2';
27
    const SPEC_VERSION   = '1.2.2';
28
 
29
    const PRAGMA_FILTERS      = 'FILTERS';
30
    const PRAGMA_BLOCKS       = 'BLOCKS';
31
    const PRAGMA_ANCHORED_DOT = 'ANCHORED-DOT';
32
 
33
    // Known pragmas
34
    private static $knownPragmas = array(
35
        self::PRAGMA_FILTERS      => true,
36
        self::PRAGMA_BLOCKS       => true,
37
        self::PRAGMA_ANCHORED_DOT => true,
38
    );
39
 
40
    // Template cache
41
    private $templates = array();
42
 
43
    // Environment
44
    private $templateClassPrefix = '__Mustache_';
45
    private $cache;
46
    private $lambdaCache;
47
    private $cacheLambdaTemplates = false;
48
    private $loader;
49
    private $partialsLoader;
50
    private $helpers;
51
    private $escape;
52
    private $entityFlags = ENT_COMPAT;
53
    private $charset = 'UTF-8';
54
    private $logger;
55
    private $strictCallables = false;
56
    private $disableLambdaRendering = false;
57
    private $pragmas = array();
58
    private $delimiters;
59
 
60
    // Services
61
    private $tokenizer;
62
    private $parser;
63
    private $compiler;
64
 
65
    /**
66
     * Mustache class constructor.
67
     *
68
     * Passing an $options array allows overriding certain Mustache options during instantiation:
69
     *
70
     *     $options = array(
71
     *         // The class prefix for compiled templates. Defaults to '__Mustache_'.
72
     *         'template_class_prefix' => '__MyTemplates_',
73
     *
74
     *         // A Mustache cache instance or a cache directory string for compiled templates.
75
     *         // Mustache will not cache templates unless this is set.
76
     *         'cache' => dirname(__FILE__).'/tmp/cache/mustache',
77
     *
78
     *         // Override default permissions for cache files. Defaults to using the system-defined umask. It is
79
     *         // *strongly* recommended that you configure your umask properly rather than overriding permissions here.
80
     *         'cache_file_mode' => 0666,
81
     *
82
     *         // Optionally, enable caching for lambda section templates. This is generally not recommended, as lambda
83
     *         // sections are often too dynamic to benefit from caching.
84
     *         'cache_lambda_templates' => true,
85
     *
86
     *         // Customize the tag delimiters used by this engine instance. Note that overriding here changes the
87
     *         // delimiters used to parse all templates and partials loaded by this instance. To override just for a
88
     *         // single template, use an inline "change delimiters" tag at the start of the template file:
89
     *         //
90
     *         //     {{=<% %>=}}
91
     *         //
92
     *         'delimiters' => '<% %>',
93
     *
94
     *         // A Mustache template loader instance. Uses a StringLoader if not specified.
95
     *         'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'),
96
     *
97
     *         // A Mustache loader instance for partials.
98
     *         'partials_loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views/partials'),
99
     *
100
     *         // An array of Mustache partials. Useful for quick-and-dirty string template loading, but not as
101
     *         // efficient or lazy as a Filesystem (or database) loader.
102
     *         'partials' => array('foo' => file_get_contents(dirname(__FILE__).'/views/partials/foo.mustache')),
103
     *
104
     *         // An array of 'helpers'. Helpers can be global variables or objects, closures (e.g. for higher order
105
     *         // sections), or any other valid Mustache context value. They will be prepended to the context stack,
106
     *         // so they will be available in any template loaded by this Mustache instance.
107
     *         'helpers' => array('i18n' => function ($text) {
108
     *             // do something translatey here...
109
     *         }),
110
     *
111
     *         // An 'escape' callback, responsible for escaping double-mustache variables.
112
     *         'escape' => function ($value) {
113
     *             return htmlspecialchars($buffer, ENT_COMPAT, 'UTF-8');
114
     *         },
115
     *
116
     *         // Type argument for `htmlspecialchars`.  Defaults to ENT_COMPAT.  You may prefer ENT_QUOTES.
117
     *         'entity_flags' => ENT_QUOTES,
118
     *
119
     *         // Character set for `htmlspecialchars`. Defaults to 'UTF-8'. Use 'UTF-8'.
120
     *         'charset' => 'ISO-8859-1',
121
     *
122
     *         // A Mustache Logger instance. No logging will occur unless this is set. Using a PSR-3 compatible
123
     *         // logging library -- such as Monolog -- is highly recommended. A simple stream logger implementation is
124
     *         // available as well:
125
     *         'logger' => new Mustache_Logger_StreamLogger('php://stderr'),
126
     *
127
     *         // Only treat Closure instances and invokable classes as callable. If true, values like
128
     *         // `array('ClassName', 'methodName')` and `array($classInstance, 'methodName')`, which are traditionally
129
     *         // "callable" in PHP, are not called to resolve variables for interpolation or section contexts. This
130
     *         // helps protect against arbitrary code execution when user input is passed directly into the template.
131
     *         // This currently defaults to false, but will default to true in v3.0.
132
     *         'strict_callables' => true,
133
     *
134
     *         // Do not render the output of lambdas. Use this to prevent repeated rendering if the lambda already
135
     *         // takes care of rendering its content. This helps protect against mustache code injection when user
136
     *         // input is passed directly into the template. Defaults to false.
137
     *         'disable_lambda_rendering' => true,
138
     *
139
     *         // Enable pragmas across all templates, regardless of the presence of pragma tags in the individual
140
     *         // templates.
141
     *         'pragmas' => [Mustache_Engine::PRAGMA_FILTERS],
142
     *     );
143
     *
144
     * @throws Mustache_Exception_InvalidArgumentException If `escape` option is not callable
145
     *
146
     * @param array $options (default: array())
147
     */
148
    public function __construct(array $options = array())
149
    {
150
        if (isset($options['template_class_prefix'])) {
151
            if ((string) $options['template_class_prefix'] === '') {
152
                throw new Mustache_Exception_InvalidArgumentException('Mustache Constructor "template_class_prefix" must not be empty');
153
            }
154
 
155
            $this->templateClassPrefix = $options['template_class_prefix'];
156
        }
157
 
158
        if (isset($options['cache'])) {
159
            $cache = $options['cache'];
160
 
161
            if (is_string($cache)) {
162
                $mode  = isset($options['cache_file_mode']) ? $options['cache_file_mode'] : null;
163
                $cache = new Mustache_Cache_FilesystemCache($cache, $mode);
164
            }
165
 
166
            $this->setCache($cache);
167
        }
168
 
169
        if (isset($options['cache_lambda_templates'])) {
170
            $this->cacheLambdaTemplates = (bool) $options['cache_lambda_templates'];
171
        }
172
 
173
        if (isset($options['loader'])) {
174
            $this->setLoader($options['loader']);
175
        }
176
 
177
        if (isset($options['partials_loader'])) {
178
            $this->setPartialsLoader($options['partials_loader']);
179
        }
180
 
181
        if (isset($options['partials'])) {
182
            $this->setPartials($options['partials']);
183
        }
184
 
185
        if (isset($options['helpers'])) {
186
            $this->setHelpers($options['helpers']);
187
        }
188
 
189
        if (isset($options['escape'])) {
190
            if (!is_callable($options['escape'])) {
191
                throw new Mustache_Exception_InvalidArgumentException('Mustache Constructor "escape" option must be callable');
192
            }
193
 
194
            $this->escape = $options['escape'];
195
        }
196
 
197
        if (isset($options['entity_flags'])) {
198
            $this->entityFlags = $options['entity_flags'];
199
        }
200
 
201
        if (isset($options['charset'])) {
202
            $this->charset = $options['charset'];
203
        }
204
 
205
        if (isset($options['logger'])) {
206
            $this->setLogger($options['logger']);
207
        }
208
 
209
        if (isset($options['strict_callables'])) {
210
            $this->strictCallables = $options['strict_callables'];
211
        }
212
 
213
        if (isset($options['disable_lambda_rendering'])) {
214
            $this->disableLambdaRendering = $options['disable_lambda_rendering'];
215
        }
216
 
217
        if (isset($options['delimiters'])) {
218
            $this->delimiters = $options['delimiters'];
219
        }
220
 
221
        if (isset($options['pragmas'])) {
222
            foreach ($options['pragmas'] as $pragma) {
223
                if (!isset(self::$knownPragmas[$pragma])) {
224
                    throw new Mustache_Exception_InvalidArgumentException(sprintf('Unknown pragma: "%s".', $pragma));
225
                }
226
                $this->pragmas[$pragma] = true;
227
            }
228
        }
229
    }
230
 
231
    /**
232
     * Shortcut 'render' invocation.
233
     *
234
     * Equivalent to calling `$mustache->loadTemplate($template)->render($context);`
235
     *
236
     * @see Mustache_Engine::loadTemplate
237
     * @see Mustache_Template::render
238
     *
239
     * @param string $template
240
     * @param mixed  $context  (default: array())
241
     *
242
     * @return string Rendered template
243
     */
244
    public function render($template, $context = array())
245
    {
246
        return $this->loadTemplate($template)->render($context);
247
    }
248
 
249
    /**
250
     * Get the current Mustache escape callback.
251
     *
252
     * @return callable|null
253
     */
254
    public function getEscape()
255
    {
256
        return $this->escape;
257
    }
258
 
259
    /**
260
     * Get the current Mustache entitity type to escape.
261
     *
262
     * @return int
263
     */
264
    public function getEntityFlags()
265
    {
266
        return $this->entityFlags;
267
    }
268
 
269
    /**
270
     * Get the current Mustache character set.
271
     *
272
     * @return string
273
     */
274
    public function getCharset()
275
    {
276
        return $this->charset;
277
    }
278
 
279
    /**
280
     * Get the current globally enabled pragmas.
281
     *
282
     * @return array
283
     */
284
    public function getPragmas()
285
    {
286
        return array_keys($this->pragmas);
287
    }
288
 
289
    /**
290
     * Set the Mustache template Loader instance.
291
     *
292
     * @param Mustache_Loader $loader
293
     */
294
    public function setLoader(Mustache_Loader $loader)
295
    {
296
        $this->loader = $loader;
297
    }
298
 
299
    /**
300
     * Get the current Mustache template Loader instance.
301
     *
302
     * If no Loader instance has been explicitly specified, this method will instantiate and return
303
     * a StringLoader instance.
304
     *
305
     * @return Mustache_Loader
306
     */
307
    public function getLoader()
308
    {
309
        if (!isset($this->loader)) {
310
            $this->loader = new Mustache_Loader_StringLoader();
311
        }
312
 
313
        return $this->loader;
314
    }
315
 
316
    /**
317
     * Set the Mustache partials Loader instance.
318
     *
319
     * @param Mustache_Loader $partialsLoader
320
     */
321
    public function setPartialsLoader(Mustache_Loader $partialsLoader)
322
    {
323
        $this->partialsLoader = $partialsLoader;
324
    }
325
 
326
    /**
327
     * Get the current Mustache partials Loader instance.
328
     *
329
     * If no Loader instance has been explicitly specified, this method will instantiate and return
330
     * an ArrayLoader instance.
331
     *
332
     * @return Mustache_Loader
333
     */
334
    public function getPartialsLoader()
335
    {
336
        if (!isset($this->partialsLoader)) {
337
            $this->partialsLoader = new Mustache_Loader_ArrayLoader();
338
        }
339
 
340
        return $this->partialsLoader;
341
    }
342
 
343
    /**
344
     * Set partials for the current partials Loader instance.
345
     *
346
     * @throws Mustache_Exception_RuntimeException If the current Loader instance is immutable
347
     *
348
     * @param array $partials (default: array())
349
     */
350
    public function setPartials(array $partials = array())
351
    {
352
        if (!isset($this->partialsLoader)) {
353
            $this->partialsLoader = new Mustache_Loader_ArrayLoader();
354
        }
355
 
356
        if (!$this->partialsLoader instanceof Mustache_Loader_MutableLoader) {
357
            throw new Mustache_Exception_RuntimeException('Unable to set partials on an immutable Mustache Loader instance');
358
        }
359
 
360
        $this->partialsLoader->setTemplates($partials);
361
    }
362
 
363
    /**
364
     * Set an array of Mustache helpers.
365
     *
366
     * An array of 'helpers'. Helpers can be global variables or objects, closures (e.g. for higher order sections), or
367
     * any other valid Mustache context value. They will be prepended to the context stack, so they will be available in
368
     * any template loaded by this Mustache instance.
369
     *
370
     * @throws Mustache_Exception_InvalidArgumentException if $helpers is not an array or Traversable
371
     *
372
     * @param array|Traversable $helpers
373
     */
374
    public function setHelpers($helpers)
375
    {
376
        if (!is_array($helpers) && !$helpers instanceof Traversable) {
377
            throw new Mustache_Exception_InvalidArgumentException('setHelpers expects an array of helpers');
378
        }
379
 
380
        $this->getHelpers()->clear();
381
 
382
        foreach ($helpers as $name => $helper) {
383
            $this->addHelper($name, $helper);
384
        }
385
    }
386
 
387
    /**
388
     * Get the current set of Mustache helpers.
389
     *
390
     * @see Mustache_Engine::setHelpers
391
     *
392
     * @return Mustache_HelperCollection
393
     */
394
    public function getHelpers()
395
    {
396
        if (!isset($this->helpers)) {
397
            $this->helpers = new Mustache_HelperCollection();
398
        }
399
 
400
        return $this->helpers;
401
    }
402
 
403
    /**
404
     * Add a new Mustache helper.
405
     *
406
     * @see Mustache_Engine::setHelpers
407
     *
408
     * @param string $name
409
     * @param mixed  $helper
410
     */
411
    public function addHelper($name, $helper)
412
    {
413
        $this->getHelpers()->add($name, $helper);
414
    }
415
 
416
    /**
417
     * Get a Mustache helper by name.
418
     *
419
     * @see Mustache_Engine::setHelpers
420
     *
421
     * @param string $name
422
     *
423
     * @return mixed Helper
424
     */
425
    public function getHelper($name)
426
    {
427
        return $this->getHelpers()->get($name);
428
    }
429
 
430
    /**
431
     * Check whether this Mustache instance has a helper.
432
     *
433
     * @see Mustache_Engine::setHelpers
434
     *
435
     * @param string $name
436
     *
437
     * @return bool True if the helper is present
438
     */
439
    public function hasHelper($name)
440
    {
441
        return $this->getHelpers()->has($name);
442
    }
443
 
444
    /**
445
     * Remove a helper by name.
446
     *
447
     * @see Mustache_Engine::setHelpers
448
     *
449
     * @param string $name
450
     */
451
    public function removeHelper($name)
452
    {
453
        $this->getHelpers()->remove($name);
454
    }
455
 
456
    /**
457
     * Set the Mustache Logger instance.
458
     *
459
     * @throws Mustache_Exception_InvalidArgumentException If logger is not an instance of Mustache_Logger or Psr\Log\LoggerInterface
460
     *
461
     * @param Mustache_Logger|Psr\Log\LoggerInterface $logger
462
     */
463
    public function setLogger($logger = null)
464
    {
465
        if ($logger !== null && !($logger instanceof Mustache_Logger || is_a($logger, 'Psr\\Log\\LoggerInterface'))) {
466
            throw new Mustache_Exception_InvalidArgumentException('Expected an instance of Mustache_Logger or Psr\\Log\\LoggerInterface.');
467
        }
468
 
469
        if ($this->getCache()->getLogger() === null) {
470
            $this->getCache()->setLogger($logger);
471
        }
472
 
473
        $this->logger = $logger;
474
    }
475
 
476
    /**
477
     * Get the current Mustache Logger instance.
478
     *
479
     * @return Mustache_Logger|Psr\Log\LoggerInterface
480
     */
481
    public function getLogger()
482
    {
483
        return $this->logger;
484
    }
485
 
486
    /**
487
     * Set the Mustache Tokenizer instance.
488
     *
489
     * @param Mustache_Tokenizer $tokenizer
490
     */
491
    public function setTokenizer(Mustache_Tokenizer $tokenizer)
492
    {
493
        $this->tokenizer = $tokenizer;
494
    }
495
 
496
    /**
497
     * Get the current Mustache Tokenizer instance.
498
     *
499
     * If no Tokenizer instance has been explicitly specified, this method will instantiate and return a new one.
500
     *
501
     * @return Mustache_Tokenizer
502
     */
503
    public function getTokenizer()
504
    {
505
        if (!isset($this->tokenizer)) {
506
            $this->tokenizer = new Mustache_Tokenizer();
507
        }
508
 
509
        return $this->tokenizer;
510
    }
511
 
512
    /**
513
     * Set the Mustache Parser instance.
514
     *
515
     * @param Mustache_Parser $parser
516
     */
517
    public function setParser(Mustache_Parser $parser)
518
    {
519
        $this->parser = $parser;
520
    }
521
 
522
    /**
523
     * Get the current Mustache Parser instance.
524
     *
525
     * If no Parser instance has been explicitly specified, this method will instantiate and return a new one.
526
     *
527
     * @return Mustache_Parser
528
     */
529
    public function getParser()
530
    {
531
        if (!isset($this->parser)) {
532
            $this->parser = new Mustache_Parser();
533
        }
534
 
535
        return $this->parser;
536
    }
537
 
538
    /**
539
     * Set the Mustache Compiler instance.
540
     *
541
     * @param Mustache_Compiler $compiler
542
     */
543
    public function setCompiler(Mustache_Compiler $compiler)
544
    {
545
        $this->compiler = $compiler;
546
    }
547
 
548
    /**
549
     * Get the current Mustache Compiler instance.
550
     *
551
     * If no Compiler instance has been explicitly specified, this method will instantiate and return a new one.
552
     *
553
     * @return Mustache_Compiler
554
     */
555
    public function getCompiler()
556
    {
557
        if (!isset($this->compiler)) {
558
            $this->compiler = new Mustache_Compiler();
559
        }
560
 
561
        return $this->compiler;
562
    }
563
 
564
    /**
565
     * Set the Mustache Cache instance.
566
     *
567
     * @param Mustache_Cache $cache
568
     */
569
    public function setCache(Mustache_Cache $cache)
570
    {
571
        if (isset($this->logger) && $cache->getLogger() === null) {
572
            $cache->setLogger($this->getLogger());
573
        }
574
 
575
        $this->cache = $cache;
576
    }
577
 
578
    /**
579
     * Get the current Mustache Cache instance.
580
     *
581
     * If no Cache instance has been explicitly specified, this method will instantiate and return a new one.
582
     *
583
     * @return Mustache_Cache
584
     */
585
    public function getCache()
586
    {
587
        if (!isset($this->cache)) {
588
            $this->setCache(new Mustache_Cache_NoopCache());
589
        }
590
 
591
        return $this->cache;
592
    }
593
 
594
    /**
595
     * Get the current Lambda Cache instance.
596
     *
597
     * If 'cache_lambda_templates' is enabled, this is the default cache instance. Otherwise, it is a NoopCache.
598
     *
599
     * @see Mustache_Engine::getCache
600
     *
601
     * @return Mustache_Cache
602
     */
603
    protected function getLambdaCache()
604
    {
605
        if ($this->cacheLambdaTemplates) {
606
            return $this->getCache();
607
        }
608
 
609
        if (!isset($this->lambdaCache)) {
610
            $this->lambdaCache = new Mustache_Cache_NoopCache();
611
        }
612
 
613
        return $this->lambdaCache;
614
    }
615
 
616
    /**
617
     * Helper method to generate a Mustache template class.
618
     *
619
     * This method must be updated any time options are added which make it so
620
     * the same template could be parsed and compiled multiple different ways.
621
     *
622
     * @param string|Mustache_Source $source
623
     *
624
     * @return string Mustache Template class name
625
     */
626
    public function getTemplateClassName($source)
627
    {
628
        // For the most part, adding a new option here should do the trick.
629
        //
630
        // Pick a value here which is unique for each possible way the template
631
        // could be compiled... but not necessarily unique per option value. See
632
        // escape below, which only needs to differentiate between 'custom' and
633
        // 'default' escapes.
634
        //
635
        // Keep this list in alphabetical order :)
636
        $chunks = array(
637
            'charset'                => $this->charset,
638
            'delimiters'             => $this->delimiters ? $this->delimiters : '{{ }}',
639
            'entityFlags'            => $this->entityFlags,
640
            'escape'                 => isset($this->escape) ? 'custom' : 'default',
641
            'key'                    => ($source instanceof Mustache_Source) ? $source->getKey() : 'source',
642
            'pragmas'                => $this->getPragmas(),
643
            'strictCallables'        => $this->strictCallables,
644
            'disableLambdaRendering' => $this->disableLambdaRendering,
645
            'version'                => self::VERSION,
646
        );
647
 
648
        $key = json_encode($chunks);
649
 
650
        // Template Source instances have already provided their own source key. For strings, just include the whole
651
        // source string in the md5 hash.
652
        if (!$source instanceof Mustache_Source) {
653
            $key .= "\n" . $source;
654
        }
655
 
656
        return $this->templateClassPrefix . md5($key);
657
    }
658
 
659
    /**
660
     * Load a Mustache Template by name.
661
     *
662
     * @param string $name
663
     *
664
     * @return Mustache_Template
665
     */
666
    public function loadTemplate($name)
667
    {
668
        return $this->loadSource($this->getLoader()->load($name));
669
    }
670
 
671
    /**
672
     * Load a Mustache partial Template by name.
673
     *
674
     * This is a helper method used internally by Template instances for loading partial templates. You can most likely
675
     * ignore it completely.
676
     *
677
     * @param string $name
678
     *
679
     * @return Mustache_Template
680
     */
681
    public function loadPartial($name)
682
    {
683
        try {
684
            if (isset($this->partialsLoader)) {
685
                $loader = $this->partialsLoader;
686
            } elseif (isset($this->loader) && !$this->loader instanceof Mustache_Loader_StringLoader) {
687
                $loader = $this->loader;
688
            } else {
689
                throw new Mustache_Exception_UnknownTemplateException($name);
690
            }
691
 
692
            return $this->loadSource($loader->load($name));
693
        } catch (Mustache_Exception_UnknownTemplateException $e) {
694
            // If the named partial cannot be found, log then return null.
695
            $this->log(
696
                Mustache_Logger::WARNING,
697
                'Partial not found: "{name}"',
698
                array('name' => $e->getTemplateName())
699
            );
700
        }
701
    }
702
 
703
    /**
704
     * Load a Mustache lambda Template by source.
705
     *
706
     * This is a helper method used by Template instances to generate subtemplates for Lambda sections. You can most
707
     * likely ignore it completely.
708
     *
709
     * @param string $source
710
     * @param string $delims (default: null)
711
     *
712
     * @return Mustache_Template
713
     */
714
    public function loadLambda($source, $delims = null)
715
    {
716
        if ($delims !== null) {
717
            $source = $delims . "\n" . $source;
718
        }
719
 
720
        return $this->loadSource($source, $this->getLambdaCache());
721
    }
722
 
723
    /**
724
     * Instantiate and return a Mustache Template instance by source.
725
     *
726
     * Optionally provide a Mustache_Cache instance. This is used internally by Mustache_Engine::loadLambda to respect
727
     * the 'cache_lambda_templates' configuration option.
728
     *
729
     * @see Mustache_Engine::loadTemplate
730
     * @see Mustache_Engine::loadPartial
731
     * @see Mustache_Engine::loadLambda
732
     *
733
     * @param string|Mustache_Source $source
734
     * @param Mustache_Cache         $cache  (default: null)
735
     *
736
     * @return Mustache_Template
737
     */
738
    private function loadSource($source, Mustache_Cache $cache = null)
739
    {
740
        $className = $this->getTemplateClassName($source);
741
 
742
        if (!isset($this->templates[$className])) {
743
            if ($cache === null) {
744
                $cache = $this->getCache();
745
            }
746
 
747
            if (!class_exists($className, false)) {
748
                if (!$cache->load($className)) {
749
                    $compiled = $this->compile($source);
750
                    $cache->cache($className, $compiled);
751
                }
752
            }
753
 
754
            $this->log(
755
                Mustache_Logger::DEBUG,
756
                'Instantiating template: "{className}"',
757
                array('className' => $className)
758
            );
759
 
760
            $this->templates[$className] = new $className($this);
761
        }
762
 
763
        return $this->templates[$className];
764
    }
765
 
766
    /**
767
     * Helper method to tokenize a Mustache template.
768
     *
769
     * @see Mustache_Tokenizer::scan
770
     *
771
     * @param string $source
772
     *
773
     * @return array Tokens
774
     */
775
    private function tokenize($source)
776
    {
777
        return $this->getTokenizer()->scan($source, $this->delimiters);
778
    }
779
 
780
    /**
781
     * Helper method to parse a Mustache template.
782
     *
783
     * @see Mustache_Parser::parse
784
     *
785
     * @param string $source
786
     *
787
     * @return array Token tree
788
     */
789
    private function parse($source)
790
    {
791
        $parser = $this->getParser();
792
        $parser->setPragmas($this->getPragmas());
793
 
794
        return $parser->parse($this->tokenize($source));
795
    }
796
 
797
    /**
798
     * Helper method to compile a Mustache template.
799
     *
800
     * @see Mustache_Compiler::compile
801
     *
802
     * @param string|Mustache_Source $source
803
     *
804
     * @return string generated Mustache template class code
805
     */
806
    private function compile($source)
807
    {
808
        $name = $this->getTemplateClassName($source);
809
 
810
        $this->log(
811
            Mustache_Logger::INFO,
812
            'Compiling template to "{className}" class',
813
            array('className' => $name)
814
        );
815
 
816
        if ($source instanceof Mustache_Source) {
817
            $source = $source->getSource();
818
        }
819
        $tree = $this->parse($source);
820
 
821
        $compiler = $this->getCompiler();
822
        $compiler->setPragmas($this->getPragmas());
823
 
824
        return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags, $this->disableLambdaRendering);
825
    }
826
 
827
    /**
828
     * Add a log record if logging is enabled.
829
     *
830
     * @param int    $level   The logging level
831
     * @param string $message The log message
832
     * @param array  $context The log context
833
     */
834
    private function log($level, $message, array $context = array())
835
    {
836
        if (isset($this->logger)) {
837
            $this->logger->log($level, $message, $context);
838
        }
839
    }
840
}