Differences Between: [Versions 310 and 311] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]
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.1'; 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body