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