[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * This file is part of Twig. 5 * 6 * (c) Fabien Potencier 7 * (c) Armin Ronacher 8 * 9 * For the full copyright and license information, please view the LICENSE 10 * file that was distributed with this source code. 11 */ 12 13 namespace Twig; 14 15 use Twig\Error\Error; 16 use Twig\Error\LoaderError; 17 use Twig\Error\RuntimeError; 18 19 /** 20 * Default base class for compiled templates. 21 * 22 * This class is an implementation detail of how template compilation currently 23 * works, which might change. It should never be used directly. Use $twig->load() 24 * instead, which returns an instance of \Twig\TemplateWrapper. 25 * 26 * @author Fabien Potencier <fabien@symfony.com> 27 * 28 * @internal 29 */ 30 abstract class Template implements \Twig_TemplateInterface 31 { 32 /** 33 * @internal 34 */ 35 protected static $cache = []; 36 37 protected $parent; 38 protected $parents = []; 39 protected $env; 40 protected $blocks = []; 41 protected $traits = []; 42 protected $sandbox; 43 44 public function __construct(Environment $env) 45 { 46 $this->env = $env; 47 } 48 49 /** 50 * @internal this method will be removed in 2.0 and is only used internally to provide an upgrade path from 1.x to 2.0 51 */ 52 public function __toString() 53 { 54 return $this->getTemplateName(); 55 } 56 57 /** 58 * Returns the template name. 59 * 60 * @return string The template name 61 */ 62 abstract public function getTemplateName(); 63 64 /** 65 * Returns debug information about the template. 66 * 67 * @return array Debug information 68 */ 69 public function getDebugInfo() 70 { 71 return []; 72 } 73 74 /** 75 * Returns the template source code. 76 * 77 * @return string The template source code 78 * 79 * @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead 80 */ 81 public function getSource() 82 { 83 @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); 84 85 return ''; 86 } 87 88 /** 89 * Returns information about the original template source code. 90 * 91 * @return Source 92 */ 93 public function getSourceContext() 94 { 95 return new Source('', $this->getTemplateName()); 96 } 97 98 /** 99 * @deprecated since 1.20 (to be removed in 2.0) 100 */ 101 public function getEnvironment() 102 { 103 @trigger_error('The '.__METHOD__.' method is deprecated since version 1.20 and will be removed in 2.0.', E_USER_DEPRECATED); 104 105 return $this->env; 106 } 107 108 /** 109 * Returns the parent template. 110 * 111 * This method is for internal use only and should never be called 112 * directly. 113 * 114 * @param array $context 115 * 116 * @return \Twig_TemplateInterface|TemplateWrapper|false The parent template or false if there is no parent 117 * 118 * @internal 119 */ 120 public function getParent(array $context) 121 { 122 if (null !== $this->parent) { 123 return $this->parent; 124 } 125 126 try { 127 $parent = $this->doGetParent($context); 128 129 if (false === $parent) { 130 return false; 131 } 132 133 if ($parent instanceof self || $parent instanceof TemplateWrapper) { 134 return $this->parents[$parent->getSourceContext()->getName()] = $parent; 135 } 136 137 if (!isset($this->parents[$parent])) { 138 $this->parents[$parent] = $this->loadTemplate($parent); 139 } 140 } catch (LoaderError $e) { 141 $e->setSourceContext(null); 142 $e->guess(); 143 144 throw $e; 145 } 146 147 return $this->parents[$parent]; 148 } 149 150 protected function doGetParent(array $context) 151 { 152 return false; 153 } 154 155 public function isTraitable() 156 { 157 return true; 158 } 159 160 /** 161 * Displays a parent block. 162 * 163 * This method is for internal use only and should never be called 164 * directly. 165 * 166 * @param string $name The block name to display from the parent 167 * @param array $context The context 168 * @param array $blocks The current set of blocks 169 */ 170 public function displayParentBlock($name, array $context, array $blocks = []) 171 { 172 $name = (string) $name; 173 174 if (isset($this->traits[$name])) { 175 $this->traits[$name][0]->displayBlock($name, $context, $blocks, false); 176 } elseif (false !== $parent = $this->getParent($context)) { 177 $parent->displayBlock($name, $context, $blocks, false); 178 } else { 179 throw new RuntimeError(sprintf('The template has no parent and no traits defining the "%s" block.', $name), -1, $this->getSourceContext()); 180 } 181 } 182 183 /** 184 * Displays a block. 185 * 186 * This method is for internal use only and should never be called 187 * directly. 188 * 189 * @param string $name The block name to display 190 * @param array $context The context 191 * @param array $blocks The current set of blocks 192 * @param bool $useBlocks Whether to use the current set of blocks 193 */ 194 public function displayBlock($name, array $context, array $blocks = [], $useBlocks = true) 195 { 196 $name = (string) $name; 197 198 if ($useBlocks && isset($blocks[$name])) { 199 $template = $blocks[$name][0]; 200 $block = $blocks[$name][1]; 201 } elseif (isset($this->blocks[$name])) { 202 $template = $this->blocks[$name][0]; 203 $block = $this->blocks[$name][1]; 204 } else { 205 $template = null; 206 $block = null; 207 } 208 209 // avoid RCEs when sandbox is enabled 210 if (null !== $template && !$template instanceof self) { 211 throw new \LogicException('A block must be a method on a \Twig\Template instance.'); 212 } 213 214 if (null !== $template) { 215 try { 216 $template->$block($context, $blocks); 217 } catch (Error $e) { 218 if (!$e->getSourceContext()) { 219 $e->setSourceContext($template->getSourceContext()); 220 } 221 222 // this is mostly useful for \Twig\Error\LoaderError exceptions 223 // see \Twig\Error\LoaderError 224 if (-1 === $e->getTemplateLine()) { 225 $e->guess(); 226 } 227 228 throw $e; 229 } catch (\Exception $e) { 230 $e = new RuntimeError(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getSourceContext(), $e); 231 $e->guess(); 232 233 throw $e; 234 } 235 } elseif (false !== $parent = $this->getParent($context)) { 236 $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false); 237 } else { 238 @trigger_error(sprintf('Silent display of undefined block "%s" in template "%s" is deprecated since version 1.29 and will throw an exception in 2.0. Use the "block(\'%s\') is defined" expression to test for block existence.', $name, $this->getTemplateName(), $name), E_USER_DEPRECATED); 239 } 240 } 241 242 /** 243 * Renders a parent block. 244 * 245 * This method is for internal use only and should never be called 246 * directly. 247 * 248 * @param string $name The block name to render from the parent 249 * @param array $context The context 250 * @param array $blocks The current set of blocks 251 * 252 * @return string The rendered block 253 */ 254 public function renderParentBlock($name, array $context, array $blocks = []) 255 { 256 if ($this->env->isDebug()) { 257 ob_start(); 258 } else { 259 ob_start(function () { return ''; }); 260 } 261 $this->displayParentBlock($name, $context, $blocks); 262 263 return ob_get_clean(); 264 } 265 266 /** 267 * Renders a block. 268 * 269 * This method is for internal use only and should never be called 270 * directly. 271 * 272 * @param string $name The block name to render 273 * @param array $context The context 274 * @param array $blocks The current set of blocks 275 * @param bool $useBlocks Whether to use the current set of blocks 276 * 277 * @return string The rendered block 278 */ 279 public function renderBlock($name, array $context, array $blocks = [], $useBlocks = true) 280 { 281 if ($this->env->isDebug()) { 282 ob_start(); 283 } else { 284 ob_start(function () { return ''; }); 285 } 286 $this->displayBlock($name, $context, $blocks, $useBlocks); 287 288 return ob_get_clean(); 289 } 290 291 /** 292 * Returns whether a block exists or not in the current context of the template. 293 * 294 * This method checks blocks defined in the current template 295 * or defined in "used" traits or defined in parent templates. 296 * 297 * @param string $name The block name 298 * @param array $context The context 299 * @param array $blocks The current set of blocks 300 * 301 * @return bool true if the block exists, false otherwise 302 */ 303 public function hasBlock($name, array $context = null, array $blocks = []) 304 { 305 if (null === $context) { 306 @trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED); 307 308 return isset($this->blocks[(string) $name]); 309 } 310 311 if (isset($blocks[$name])) { 312 return $blocks[$name][0] instanceof self; 313 } 314 315 if (isset($this->blocks[$name])) { 316 return true; 317 } 318 319 if (false !== $parent = $this->getParent($context)) { 320 return $parent->hasBlock($name, $context); 321 } 322 323 return false; 324 } 325 326 /** 327 * Returns all block names in the current context of the template. 328 * 329 * This method checks blocks defined in the current template 330 * or defined in "used" traits or defined in parent templates. 331 * 332 * @param array $context The context 333 * @param array $blocks The current set of blocks 334 * 335 * @return array An array of block names 336 */ 337 public function getBlockNames(array $context = null, array $blocks = []) 338 { 339 if (null === $context) { 340 @trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED); 341 342 return array_keys($this->blocks); 343 } 344 345 $names = array_merge(array_keys($blocks), array_keys($this->blocks)); 346 347 if (false !== $parent = $this->getParent($context)) { 348 $names = array_merge($names, $parent->getBlockNames($context)); 349 } 350 351 return array_unique($names); 352 } 353 354 /** 355 * @return Template|TemplateWrapper 356 */ 357 protected function loadTemplate($template, $templateName = null, $line = null, $index = null) 358 { 359 try { 360 if (\is_array($template)) { 361 return $this->env->resolveTemplate($template); 362 } 363 364 if ($template instanceof self || $template instanceof TemplateWrapper) { 365 return $template; 366 } 367 368 if ($template === $this->getTemplateName()) { 369 $class = \get_class($this); 370 if (false !== $pos = strrpos($class, '___', -1)) { 371 $class = substr($class, 0, $pos); 372 } 373 374 return $this->env->loadClass($class, $template, $index); 375 } 376 377 return $this->env->loadTemplate($template, $index); 378 } catch (Error $e) { 379 if (!$e->getSourceContext()) { 380 $e->setSourceContext($templateName ? new Source('', $templateName) : $this->getSourceContext()); 381 } 382 383 if ($e->getTemplateLine() > 0) { 384 throw $e; 385 } 386 387 if (!$line) { 388 $e->guess(); 389 } else { 390 $e->setTemplateLine($line); 391 } 392 393 throw $e; 394 } 395 } 396 397 /** 398 * @internal 399 * 400 * @return Template 401 */ 402 protected function unwrap() 403 { 404 return $this; 405 } 406 407 /** 408 * Returns all blocks. 409 * 410 * This method is for internal use only and should never be called 411 * directly. 412 * 413 * @return array An array of blocks 414 */ 415 public function getBlocks() 416 { 417 return $this->blocks; 418 } 419 420 public function display(array $context, array $blocks = []) 421 { 422 $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks)); 423 } 424 425 public function render(array $context) 426 { 427 $level = ob_get_level(); 428 if ($this->env->isDebug()) { 429 ob_start(); 430 } else { 431 ob_start(function () { return ''; }); 432 } 433 try { 434 $this->display($context); 435 } catch (\Exception $e) { 436 while (ob_get_level() > $level) { 437 ob_end_clean(); 438 } 439 440 throw $e; 441 } catch (\Throwable $e) { 442 while (ob_get_level() > $level) { 443 ob_end_clean(); 444 } 445 446 throw $e; 447 } 448 449 return ob_get_clean(); 450 } 451 452 protected function displayWithErrorHandling(array $context, array $blocks = []) 453 { 454 try { 455 $this->doDisplay($context, $blocks); 456 } catch (Error $e) { 457 if (!$e->getSourceContext()) { 458 $e->setSourceContext($this->getSourceContext()); 459 } 460 461 // this is mostly useful for \Twig\Error\LoaderError exceptions 462 // see \Twig\Error\LoaderError 463 if (-1 === $e->getTemplateLine()) { 464 $e->guess(); 465 } 466 467 throw $e; 468 } catch (\Exception $e) { 469 $e = new RuntimeError(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getSourceContext(), $e); 470 $e->guess(); 471 472 throw $e; 473 } 474 } 475 476 /** 477 * Auto-generated method to display the template with the given context. 478 * 479 * @param array $context An array of parameters to pass to the template 480 * @param array $blocks An array of blocks to pass to the template 481 */ 482 abstract protected function doDisplay(array $context, array $blocks = []); 483 484 /** 485 * Returns a variable from the context. 486 * 487 * This method is for internal use only and should never be called 488 * directly. 489 * 490 * This method should not be overridden in a sub-class as this is an 491 * implementation detail that has been introduced to optimize variable 492 * access for versions of PHP before 5.4. This is not a way to override 493 * the way to get a variable value. 494 * 495 * @param array $context The context 496 * @param string $item The variable to return from the context 497 * @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not 498 * 499 * @return mixed The content of the context variable 500 * 501 * @throws RuntimeError if the variable does not exist and Twig is running in strict mode 502 * 503 * @internal 504 */ 505 final protected function getContext($context, $item, $ignoreStrictCheck = false) 506 { 507 if (!\array_key_exists($item, $context)) { 508 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { 509 return; 510 } 511 512 throw new RuntimeError(sprintf('Variable "%s" does not exist.', $item), -1, $this->getSourceContext()); 513 } 514 515 return $context[$item]; 516 } 517 518 /** 519 * Returns the attribute value for a given array/object. 520 * 521 * @param mixed $object The object or array from where to get the item 522 * @param mixed $item The item to get from the array or object 523 * @param array $arguments An array of arguments to pass if the item is an object method 524 * @param string $type The type of attribute (@see \Twig\Template constants) 525 * @param bool $isDefinedTest Whether this is only a defined check 526 * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not 527 * 528 * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true 529 * 530 * @throws RuntimeError if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false 531 * 532 * @internal 533 */ 534 protected function getAttribute($object, $item, array $arguments = [], $type = self::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) 535 { 536 // array 537 if (self::METHOD_CALL !== $type) { 538 $arrayItem = \is_bool($item) || \is_float($item) ? (int) $item : $item; 539 540 if (((\is_array($object) || $object instanceof \ArrayObject) && (isset($object[$arrayItem]) || \array_key_exists($arrayItem, $object))) 541 || ($object instanceof \ArrayAccess && isset($object[$arrayItem])) 542 ) { 543 if ($isDefinedTest) { 544 return true; 545 } 546 547 return $object[$arrayItem]; 548 } 549 550 if (self::ARRAY_CALL === $type || !\is_object($object)) { 551 if ($isDefinedTest) { 552 return false; 553 } 554 555 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { 556 return; 557 } 558 559 if ($object instanceof \ArrayAccess) { 560 $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object)); 561 } elseif (\is_object($object)) { 562 $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object)); 563 } elseif (\is_array($object)) { 564 if (empty($object)) { 565 $message = sprintf('Key "%s" does not exist as the array is empty.', $arrayItem); 566 } else { 567 $message = sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object))); 568 } 569 } elseif (self::ARRAY_CALL === $type) { 570 if (null === $object) { 571 $message = sprintf('Impossible to access a key ("%s") on a null variable.', $item); 572 } else { 573 $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); 574 } 575 } elseif (null === $object) { 576 $message = sprintf('Impossible to access an attribute ("%s") on a null variable.', $item); 577 } else { 578 $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); 579 } 580 581 throw new RuntimeError($message, -1, $this->getSourceContext()); 582 } 583 } 584 585 if (!\is_object($object)) { 586 if ($isDefinedTest) { 587 return false; 588 } 589 590 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { 591 return; 592 } 593 594 if (null === $object) { 595 $message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item); 596 } elseif (\is_array($object)) { 597 $message = sprintf('Impossible to invoke a method ("%s") on an array.', $item); 598 } else { 599 $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); 600 } 601 602 throw new RuntimeError($message, -1, $this->getSourceContext()); 603 } 604 605 // object property 606 if (self::METHOD_CALL !== $type && !$object instanceof self) { // \Twig\Template does not have public properties, and we don't want to allow access to internal ones 607 if (isset($object->$item) || \array_key_exists((string) $item, $object)) { 608 if ($isDefinedTest) { 609 return true; 610 } 611 612 if ($this->env->hasExtension('\Twig\Extension\SandboxExtension')) { 613 $this->env->getExtension('\Twig\Extension\SandboxExtension')->checkPropertyAllowed($object, $item); 614 } 615 616 return $object->$item; 617 } 618 } 619 620 $class = \get_class($object); 621 622 // object method 623 if (!isset(self::$cache[$class])) { 624 // get_class_methods returns all methods accessible in the scope, but we only want public ones to be accessible in templates 625 if ($object instanceof self) { 626 $ref = new \ReflectionClass($class); 627 $methods = []; 628 629 foreach ($ref->getMethods(\ReflectionMethod::IS_PUBLIC) as $refMethod) { 630 // Accessing the environment from templates is forbidden to prevent untrusted changes to the environment 631 if ('getenvironment' !== strtolower($refMethod->name)) { 632 $methods[] = $refMethod->name; 633 } 634 } 635 } else { 636 $methods = get_class_methods($object); 637 } 638 // sort values to have consistent behavior, so that "get" methods win precedence over "is" methods 639 sort($methods); 640 641 $cache = []; 642 643 foreach ($methods as $method) { 644 $cache[$method] = $method; 645 $cache[$lcName = strtolower($method)] = $method; 646 647 if ('g' === $lcName[0] && 0 === strpos($lcName, 'get')) { 648 $name = substr($method, 3); 649 $lcName = substr($lcName, 3); 650 } elseif ('i' === $lcName[0] && 0 === strpos($lcName, 'is')) { 651 $name = substr($method, 2); 652 $lcName = substr($lcName, 2); 653 } else { 654 continue; 655 } 656 657 // skip get() and is() methods (in which case, $name is empty) 658 if ($name) { 659 if (!isset($cache[$name])) { 660 $cache[$name] = $method; 661 } 662 if (!isset($cache[$lcName])) { 663 $cache[$lcName] = $method; 664 } 665 } 666 } 667 self::$cache[$class] = $cache; 668 } 669 670 $call = false; 671 if (isset(self::$cache[$class][$item])) { 672 $method = self::$cache[$class][$item]; 673 } elseif (isset(self::$cache[$class][$lcItem = strtolower($item)])) { 674 $method = self::$cache[$class][$lcItem]; 675 } elseif (isset(self::$cache[$class]['__call'])) { 676 $method = $item; 677 $call = true; 678 } else { 679 if ($isDefinedTest) { 680 return false; 681 } 682 683 if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { 684 return; 685 } 686 687 throw new RuntimeError(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), -1, $this->getSourceContext()); 688 } 689 690 if ($isDefinedTest) { 691 return true; 692 } 693 694 if ($this->env->hasExtension('\Twig\Extension\SandboxExtension')) { 695 $this->env->getExtension('\Twig\Extension\SandboxExtension')->checkMethodAllowed($object, $method); 696 } 697 698 // Some objects throw exceptions when they have __call, and the method we try 699 // to call is not supported. If ignoreStrictCheck is true, we should return null. 700 try { 701 if (!$arguments) { 702 $ret = $object->$method(); 703 } else { 704 $ret = \call_user_func_array([$object, $method], $arguments); 705 } 706 } catch (\BadMethodCallException $e) { 707 if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) { 708 return; 709 } 710 throw $e; 711 } 712 713 // @deprecated in 1.28 714 if ($object instanceof \Twig_TemplateInterface) { 715 $self = $object->getTemplateName() === $this->getTemplateName(); 716 $message = sprintf('Calling "%s" on template "%s" from template "%s" is deprecated since version 1.28 and won\'t be supported anymore in 2.0.', $item, $object->getTemplateName(), $this->getTemplateName()); 717 if ('renderBlock' === $method || 'displayBlock' === $method) { 718 $message .= sprintf(' Use block("%s"%s) instead).', $arguments[0], $self ? '' : ', template'); 719 } elseif ('hasBlock' === $method) { 720 $message .= sprintf(' Use "block("%s"%s) is defined" instead).', $arguments[0], $self ? '' : ', template'); 721 } elseif ('render' === $method || 'display' === $method) { 722 $message .= sprintf(' Use include("%s") instead).', $object->getTemplateName()); 723 } 724 @trigger_error($message, E_USER_DEPRECATED); 725 726 return '' === $ret ? '' : new Markup($ret, $this->env->getCharset()); 727 } 728 729 return $ret; 730 } 731 } 732 733 class_alias('Twig\Template', 'Twig_Template');
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |