PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 2.0.6
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v2.0.6
4.0.2 4.0.1 4.0.0 3.16.6 3.16.5 3.16.4 3.16.3 3.16.2 3.16.1 3.16.0 3.15.9 3.9.9 3.9.5 3.9.6 3.9.7 3.9.8 1.1.7 1.1.8 1.1.9 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 All 340 releases
profile-builder / assets / lib / Mustache / Engine.php

Engine.php in User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor 2.0.6, at assets/lib/Mustache/Engine.php

749 lines 22.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of Mustache.php.
5 *
6 * (c) 2012 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.4.1';
27 const SPEC_VERSION = '1.1.2';
28
29 const PRAGMA_FILTERS = 'FILTERS';
30
31 // Template cache
32 private $templates = array();
33
34 // Environment
35 private $templateClassPrefix = '__Mustache_';
36 private $cache = null;
37 private $cacheFileMode = null;
38 private $loader;
39 private $partialsLoader;
40 private $helpers;
41 private $escape;
42 private $entityFlags = ENT_COMPAT;
43 private $charset = 'UTF-8';
44 private $logger;
45 private $strictCallables = false;
46
47 /**
48 * Mustache class constructor.
49 *
50 * Passing an $options array allows overriding certain Mustache options during instantiation:
51 *
52 * $options = array(
53 * // The class prefix for compiled templates. Defaults to '__Mustache_'.
54 * 'template_class_prefix' => '__MyTemplates_',
55 *
56 * // A cache directory for compiled templates. Mustache will not cache templates unless this is set
57 * 'cache' => dirname(__FILE__).'/tmp/cache/mustache',
58 *
59 * // Override default permissions for cache files. Defaults to using the system-defined umask. It is
60 * // *strongly* recommended that you configure your umask properly rather than overriding permissions here.
61 * 'cache_file_mode' => 0666,
62 *
63 * // A Mustache template loader instance. Uses a StringLoader if not specified.
64 * 'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'),
65 *
66 * // A Mustache loader instance for partials.
67 * 'partials_loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views/partials'),
68 *
69 * // An array of Mustache partials. Useful for quick-and-dirty string template loading, but not as
70 * // efficient or lazy as a Filesystem (or database) loader.
71 * 'partials' => array('foo' => file_get_contents(dirname(__FILE__).'/views/partials/foo.mustache')),
72 *
73 * // An array of 'helpers'. Helpers can be global variables or objects, closures (e.g. for higher order
74 * // sections), or any other valid Mustache context value. They will be prepended to the context stack,
75 * // so they will be available in any template loaded by this Mustache instance.
76 * 'helpers' => array('i18n' => function($text) {
77 * // do something translatey here...
78 * }),
79 *
80 * // An 'escape' callback, responsible for escaping double-mustache variables.
81 * 'escape' => function($value) {
82 * return htmlspecialchars($buffer, ENT_COMPAT, 'UTF-8');
83 * },
84 *
85 * // Type argument for `htmlspecialchars`. Defaults to ENT_COMPAT. You may prefer ENT_QUOTES.
86 * 'entity_flags' => ENT_QUOTES,
87 *
88 * // Character set for `htmlspecialchars`. Defaults to 'UTF-8'. Use 'UTF-8'.
89 * 'charset' => 'ISO-8859-1',
90 *
91 * // A Mustache Logger instance. No logging will occur unless this is set. Using a PSR-3 compatible
92 * // logging library -- such as Monolog -- is highly recommended. A simple stream logger implementation is
93 * // available as well:
94 * 'logger' => new Mustache_Logger_StreamLogger('php://stderr'),
95 *
96 * // Only treat Closure instances and invokable classes as callable. If true, values like
97 * // `array('ClassName', 'methodName')` and `array($classInstance, 'methodName')`, which are traditionally
98 * // "callable" in PHP, are not called to resolve variables for interpolation or section contexts. This
99 * // helps protect against arbitrary code execution when user input is passed directly into the template.
100 * // This currently defaults to false, but will default to true in v3.0.
101 * 'strict_callables' => true,
102 * );
103 *
104 * @throws Mustache_Exception_InvalidArgumentException If `escape` option is not callable.
105 *
106 * @param array $options (default: array())
107 */
108 public function __construct(array $options = array())
109 {
110 if (isset($options['template_class_prefix'])) {
111 $this->templateClassPrefix = $options['template_class_prefix'];
112 }
113
114 if (isset($options['cache'])) {
115 $this->cache = $options['cache'];
116 }
117
118 if (isset($options['cache_file_mode'])) {
119 $this->cacheFileMode = $options['cache_file_mode'];
120 }
121
122 if (isset($options['loader'])) {
123 $this->setLoader($options['loader']);
124 }
125
126 if (isset($options['partials_loader'])) {
127 $this->setPartialsLoader($options['partials_loader']);
128 }
129
130 if (isset($options['partials'])) {
131 $this->setPartials($options['partials']);
132 }
133
134 if (isset($options['helpers'])) {
135 $this->setHelpers($options['helpers']);
136 }
137
138 if (isset($options['escape'])) {
139 if (!is_callable($options['escape'])) {
140 throw new Mustache_Exception_InvalidArgumentException('Mustache Constructor "escape" option must be callable');
141 }
142
143 $this->escape = $options['escape'];
144 }
145
146 if (isset($options['entity_flags'])) {
147 $this->entityFlags = $options['entity_flags'];
148 }
149
150 if (isset($options['charset'])) {
151 $this->charset = $options['charset'];
152 }
153
154 if (isset($options['logger'])) {
155 $this->setLogger($options['logger']);
156 }
157
158 if (isset($options['strict_callables'])) {
159 $this->strictCallables = $options['strict_callables'];
160 }
161 }
162
163 /**
164 * Shortcut 'render' invocation.
165 *
166 * Equivalent to calling `$mustache->loadTemplate($template)->render($context);`
167 *
168 * @see Mustache_Engine::loadTemplate
169 * @see Mustache_Template::render
170 *
171 * @param string $template
172 * @param mixed $context (default: array())
173 *
174 * @return string Rendered template
175 */
176 public function render($template, $context = array())
177 {
178 return $this->loadTemplate($template)->render($context);
179 }
180
181 /**
182 * Get the current Mustache escape callback.
183 *
184 * @return mixed Callable or null
185 */
186 public function getEscape()
187 {
188 return $this->escape;
189 }
190
191 /**
192 * Get the current Mustache entitity type to escape.
193 *
194 * @return int
195 */
196 public function getEntityFlags()
197 {
198 return $this->entityFlags;
199 }
200
201 /**
202 * Get the current Mustache character set.
203 *
204 * @return string
205 */
206 public function getCharset()
207 {
208 return $this->charset;
209 }
210
211 /**
212 * Set the Mustache template Loader instance.
213 *
214 * @param Mustache_Loader $loader
215 */
216 public function setLoader(Mustache_Loader $loader)
217 {
218 $this->loader = $loader;
219 }
220
221 /**
222 * Get the current Mustache template Loader instance.
223 *
224 * If no Loader instance has been explicitly specified, this method will instantiate and return
225 * a StringLoader instance.
226 *
227 * @return Mustache_Loader
228 */
229 public function getLoader()
230 {
231 if (!isset($this->loader)) {
232 $this->loader = new Mustache_Loader_StringLoader;
233 }
234
235 return $this->loader;
236 }
237
238 /**
239 * Set the Mustache partials Loader instance.
240 *
241 * @param Mustache_Loader $partialsLoader
242 */
243 public function setPartialsLoader(Mustache_Loader $partialsLoader)
244 {
245 $this->partialsLoader = $partialsLoader;
246 }
247
248 /**
249 * Get the current Mustache partials Loader instance.
250 *
251 * If no Loader instance has been explicitly specified, this method will instantiate and return
252 * an ArrayLoader instance.
253 *
254 * @return Mustache_Loader
255 */
256 public function getPartialsLoader()
257 {
258 if (!isset($this->partialsLoader)) {
259 $this->partialsLoader = new Mustache_Loader_ArrayLoader;
260 }
261
262 return $this->partialsLoader;
263 }
264
265 /**
266 * Set partials for the current partials Loader instance.
267 *
268 * @throws Mustache_Exception_RuntimeException If the current Loader instance is immutable
269 *
270 * @param array $partials (default: array())
271 */
272 public function setPartials(array $partials = array())
273 {
274 if (!isset($this->partialsLoader)) {
275 $this->partialsLoader = new Mustache_Loader_ArrayLoader;
276 }
277
278 if (!$this->partialsLoader instanceof Mustache_Loader_MutableLoader) {
279 throw new Mustache_Exception_RuntimeException('Unable to set partials on an immutable Mustache Loader instance');
280 }
281
282 $this->partialsLoader->setTemplates($partials);
283 }
284
285 /**
286 * Set an array of Mustache helpers.
287 *
288 * An array of 'helpers'. Helpers can be global variables or objects, closures (e.g. for higher order sections), or
289 * any other valid Mustache context value. They will be prepended to the context stack, so they will be available in
290 * any template loaded by this Mustache instance.
291 *
292 * @throws Mustache_Exception_InvalidArgumentException if $helpers is not an array or Traversable
293 *
294 * @param array|Traversable $helpers
295 */
296 public function setHelpers($helpers)
297 {
298 if (!is_array($helpers) && !$helpers instanceof Traversable) {
299 throw new Mustache_Exception_InvalidArgumentException('setHelpers expects an array of helpers');
300 }
301
302 $this->getHelpers()->clear();
303
304 foreach ($helpers as $name => $helper) {
305 $this->addHelper($name, $helper);
306 }
307 }
308
309 /**
310 * Get the current set of Mustache helpers.
311 *
312 * @see Mustache_Engine::setHelpers
313 *
314 * @return Mustache_HelperCollection
315 */
316 public function getHelpers()
317 {
318 if (!isset($this->helpers)) {
319 $this->helpers = new Mustache_HelperCollection;
320 }
321
322 return $this->helpers;
323 }
324
325 /**
326 * Add a new Mustache helper.
327 *
328 * @see Mustache_Engine::setHelpers
329 *
330 * @param string $name
331 * @param mixed $helper
332 */
333 public function addHelper($name, $helper)
334 {
335 $this->getHelpers()->add($name, $helper);
336 }
337
338 /**
339 * Get a Mustache helper by name.
340 *
341 * @see Mustache_Engine::setHelpers
342 *
343 * @param string $name
344 *
345 * @return mixed Helper
346 */
347 public function getHelper($name)
348 {
349 return $this->getHelpers()->get($name);
350 }
351
352 /**
353 * Check whether this Mustache instance has a helper.
354 *
355 * @see Mustache_Engine::setHelpers
356 *
357 * @param string $name
358 *
359 * @return boolean True if the helper is present
360 */
361 public function hasHelper($name)
362 {
363 return $this->getHelpers()->has($name);
364 }
365
366 /**
367 * Remove a helper by name.
368 *
369 * @see Mustache_Engine::setHelpers
370 *
371 * @param string $name
372 */
373 public function removeHelper($name)
374 {
375 $this->getHelpers()->remove($name);
376 }
377
378 /**
379 * Set the Mustache Logger instance.
380 *
381 * @throws Mustache_Exception_InvalidArgumentException If logger is not an instance of Mustache_Logger or Psr\Log\LoggerInterface.
382 *
383 * @param Mustache_Logger|Psr\Log\LoggerInterface $logger
384 */
385 public function setLogger($logger = null)
386 {
387 if ($logger !== null && !($logger instanceof Mustache_Logger || is_a($logger, 'Psr\\Log\\LoggerInterface'))) {
388 throw new Mustache_Exception_InvalidArgumentException('Expected an instance of Mustache_Logger or Psr\\Log\\LoggerInterface.');
389 }
390
391 $this->logger = $logger;
392 }
393
394 /**
395 * Get the current Mustache Logger instance.
396 *
397 * @return Mustache_Logger|Psr\Log\LoggerInterface
398 */
399 public function getLogger()
400 {
401 return $this->logger;
402 }
403
404 /**
405 * Set the Mustache Tokenizer instance.
406 *
407 * @param Mustache_Tokenizer $tokenizer
408 */
409 public function setTokenizer(Mustache_Tokenizer $tokenizer)
410 {
411 $this->tokenizer = $tokenizer;
412 }
413
414 /**
415 * Get the current Mustache Tokenizer instance.
416 *
417 * If no Tokenizer instance has been explicitly specified, this method will instantiate and return a new one.
418 *
419 * @return Mustache_Tokenizer
420 */
421 public function getTokenizer()
422 {
423 if (!isset($this->tokenizer)) {
424 $this->tokenizer = new Mustache_Tokenizer;
425 }
426
427 return $this->tokenizer;
428 }
429
430 /**
431 * Set the Mustache Parser instance.
432 *
433 * @param Mustache_Parser $parser
434 */
435 public function setParser(Mustache_Parser $parser)
436 {
437 $this->parser = $parser;
438 }
439
440 /**
441 * Get the current Mustache Parser instance.
442 *
443 * If no Parser instance has been explicitly specified, this method will instantiate and return a new one.
444 *
445 * @return Mustache_Parser
446 */
447 public function getParser()
448 {
449 if (!isset($this->parser)) {
450 $this->parser = new Mustache_Parser;
451 }
452
453 return $this->parser;
454 }
455
456 /**
457 * Set the Mustache Compiler instance.
458 *
459 * @param Mustache_Compiler $compiler
460 */
461 public function setCompiler(Mustache_Compiler $compiler)
462 {
463 $this->compiler = $compiler;
464 }
465
466 /**
467 * Get the current Mustache Compiler instance.
468 *
469 * If no Compiler instance has been explicitly specified, this method will instantiate and return a new one.
470 *
471 * @return Mustache_Compiler
472 */
473 public function getCompiler()
474 {
475 if (!isset($this->compiler)) {
476 $this->compiler = new Mustache_Compiler;
477 }
478
479 return $this->compiler;
480 }
481
482 /**
483 * Helper method to generate a Mustache template class.
484 *
485 * @param string $source
486 *
487 * @return string Mustache Template class name
488 */
489 public function getTemplateClassName($source)
490 {
491 return $this->templateClassPrefix . md5(sprintf(
492 'version:%s,escape:%s,entity_flags:%i,charset:%s,strict_callables:%s,source:%s',
493 self::VERSION,
494 isset($this->escape) ? 'custom' : 'default',
495 $this->entityFlags,
496 $this->charset,
497 $this->strictCallables ? 'true' : 'false',
498 $source
499 ));
500 }
501
502 /**
503 * Load a Mustache Template by name.
504 *
505 * @param string $name
506 *
507 * @return Mustache_Template
508 */
509 public function loadTemplate($name)
510 {
511 return $this->loadSource($this->getLoader()->load($name));
512 }
513
514 /**
515 * Load a Mustache partial Template by name.
516 *
517 * This is a helper method used internally by Template instances for loading partial templates. You can most likely
518 * ignore it completely.
519 *
520 * @param string $name
521 *
522 * @return Mustache_Template
523 */
524 public function loadPartial($name)
525 {
526 try {
527 if (isset($this->partialsLoader)) {
528 $loader = $this->partialsLoader;
529 } elseif (isset($this->loader) && !$this->loader instanceof Mustache_Loader_StringLoader) {
530 $loader = $this->loader;
531 } else {
532 throw new Mustache_Exception_UnknownTemplateException($name);
533 }
534
535 return $this->loadSource($loader->load($name));
536 } catch (Mustache_Exception_UnknownTemplateException $e) {
537 // If the named partial cannot be found, log then return null.
538 $this->log(
539 Mustache_Logger::WARNING,
540 'Partial not found: "{name}"',
541 array('name' => $e->getTemplateName())
542 );
543 }
544 }
545
546 /**
547 * Load a Mustache lambda Template by source.
548 *
549 * This is a helper method used by Template instances to generate subtemplates for Lambda sections. You can most
550 * likely ignore it completely.
551 *
552 * @param string $source
553 * @param string $delims (default: null)
554 *
555 * @return Mustache_Template
556 */
557 public function loadLambda($source, $delims = null)
558 {
559 if ($delims !== null) {
560 $source = $delims . "\n" . $source;
561 }
562
563 return $this->loadSource($source);
564 }
565
566 /**
567 * Instantiate and return a Mustache Template instance by source.
568 *
569 * @see Mustache_Engine::loadTemplate
570 * @see Mustache_Engine::loadPartial
571 * @see Mustache_Engine::loadLambda
572 *
573 * @param string $source
574 *
575 * @return Mustache_Template
576 */
577 private function loadSource($source)
578 {
579 $className = $this->getTemplateClassName($source);
580
581 if (!isset($this->templates[$className])) {
582 if (!class_exists($className, false)) {
583 if ($fileName = $this->getCacheFilename($source)) {
584 if (!is_file($fileName)) {
585 $this->log(
586 Mustache_Logger::DEBUG,
587 'Writing "{className}" class to template cache: "{fileName}"',
588 array('className' => $className, 'fileName' => $fileName)
589 );
590
591 $this->writeCacheFile($fileName, $this->compile($source));
592 }
593
594 require_once $fileName;
595 } else {
596 $this->log(
597 Mustache_Logger::WARNING,
598 'Template cache disabled, evaluating "{className}" class at runtime',
599 array('className' => $className)
600 );
601
602 eval('?>'.$this->compile($source));
603 }
604 }
605
606 $this->log(
607 Mustache_Logger::DEBUG,
608 'Instantiating template: "{className}"',
609 array('className' => $className)
610 );
611
612 $this->templates[$className] = new $className($this);
613 }
614
615 return $this->templates[$className];
616 }
617
618 /**
619 * Helper method to tokenize a Mustache template.
620 *
621 * @see Mustache_Tokenizer::scan
622 *
623 * @param string $source
624 *
625 * @return array Tokens
626 */
627 private function tokenize($source)
628 {
629 return $this->getTokenizer()->scan($source);
630 }
631
632 /**
633 * Helper method to parse a Mustache template.
634 *
635 * @see Mustache_Parser::parse
636 *
637 * @param string $source
638 *
639 * @return array Token tree
640 */
641 private function parse($source)
642 {
643 return $this->getParser()->parse($this->tokenize($source));
644 }
645
646 /**
647 * Helper method to compile a Mustache template.
648 *
649 * @see Mustache_Compiler::compile
650 *
651 * @param string $source
652 *
653 * @return string generated Mustache template class code
654 */
655 private function compile($source)
656 {
657 $tree = $this->parse($source);
658 $name = $this->getTemplateClassName($source);
659
660 $this->log(
661 Mustache_Logger::INFO,
662 'Compiling template to "{className}" class',
663 array('className' => $name)
664 );
665
666 return $this->getCompiler()->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags);
667 }
668
669 /**
670 * Helper method to generate a Mustache Template class cache filename.
671 *
672 * @param string $source
673 *
674 * @return string Mustache Template class cache filename
675 */
676 private function getCacheFilename($source)
677 {
678 if ($this->cache) {
679 return sprintf('%s/%s.php', $this->cache, $this->getTemplateClassName($source));
680 }
681 }
682
683 /**
684 * Helper method to dump a generated Mustache Template subclass to the file cache.
685 *
686 * @throws Mustache_Exception_RuntimeException if unable to create the cache directory or write to $fileName.
687 *
688 * @param string $fileName
689 * @param string $source
690 *
691 * @codeCoverageIgnore
692 */
693 private function writeCacheFile($fileName, $source)
694 {
695 $dirName = dirname($fileName);
696 if (!is_dir($dirName)) {
697 $this->log(
698 Mustache_Logger::INFO,
699 'Creating Mustache template cache directory: "{dirName}"',
700 array('dirName' => $dirName)
701 );
702
703 @mkdir($dirName, 0777, true);
704 if (!is_dir($dirName)) {
705 throw new Mustache_Exception_RuntimeException(sprintf('Failed to create cache directory "%s".', $dirName));
706 }
707
708 }
709
710 $this->log(
711 Mustache_Logger::DEBUG,
712 'Caching compiled template to "{fileName}"',
713 array('fileName' => $fileName)
714 );
715
716 $tempFile = tempnam($dirName, basename($fileName));
717 if (false !== @file_put_contents($tempFile, $source)) {
718 if (@rename($tempFile, $fileName)) {
719 $mode = isset($this->cacheFileMode) ? $this->cacheFileMode : (0666 & ~umask());
720 @chmod($fileName, $mode);
721
722 return;
723 }
724
725 $this->log(
726 Mustache_Logger::ERROR,
727 'Unable to rename Mustache temp cache file: "{tempName}" -> "{fileName}"',
728 array('tempName' => $tempFile, 'fileName' => $fileName)
729 );
730 }
731
732 throw new Mustache_Exception_RuntimeException(sprintf('Failed to write cache file "%s".', $fileName));
733 }
734
735 /**
736 * Add a log record if logging is enabled.
737 *
738 * @param integer $level The logging level
739 * @param string $message The log message
740 * @param array $context The log context
741 */
742 private function log($level, $message, array $context = array())
743 {
744 if (isset($this->logger)) {
745 $this->logger->log($level, $message, $context);
746 }
747 }
748 }
749