vendor/twig/twig/src/Error/Error.php line 96

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Twig.
  4.  *
  5.  * (c) Fabien Potencier
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Twig\Error;
  11. use Twig\Source;
  12. use Twig\Template;
  13. /**
  14.  * Twig base exception.
  15.  *
  16.  * This exception class and its children must only be used when
  17.  * an error occurs during the loading of a template, when a syntax error
  18.  * is detected in a template, or when rendering a template. Other
  19.  * errors must use regular PHP exception classes (like when the template
  20.  * cache directory is not writable for instance).
  21.  *
  22.  * To help debugging template issues, this class tracks the original template
  23.  * name and line where the error occurred.
  24.  *
  25.  * Whenever possible, you must set these information (original template name
  26.  * and line number) yourself by passing them to the constructor. If some or all
  27.  * these information are not available from where you throw the exception, then
  28.  * this class will guess them automatically (when the line number is set to -1
  29.  * and/or the name is set to null). As this is a costly operation, this
  30.  * can be disabled by passing false for both the name and the line number
  31.  * when creating a new instance of this class.
  32.  *
  33.  * @author Fabien Potencier <fabien@symfony.com>
  34.  */
  35. class Error extends \Exception
  36. {
  37.     private $lineno;
  38.     private $name;
  39.     private $rawMessage;
  40.     private $sourcePath;
  41.     private $sourceCode;
  42.     /**
  43.      * Constructor.
  44.      *
  45.      * By default, automatic guessing is enabled.
  46.      *
  47.      * @param string      $message The error message
  48.      * @param int         $lineno  The template line where the error occurred
  49.      * @param Source|null $source  The source context where the error occurred
  50.      */
  51.     public function __construct(string $messageint $lineno = -1Source $source null, \Exception $previous null)
  52.     {
  53.         parent::__construct(''0$previous);
  54.         if (null === $source) {
  55.             $name null;
  56.         } else {
  57.             $name $source->getName();
  58.             $this->sourceCode $source->getCode();
  59.             $this->sourcePath $source->getPath();
  60.         }
  61.         $this->lineno $lineno;
  62.         $this->name $name;
  63.         $this->rawMessage $message;
  64.         $this->updateRepr();
  65.     }
  66.     public function getRawMessage(): string
  67.     {
  68.         return $this->rawMessage;
  69.     }
  70.     public function getTemplateLine(): int
  71.     {
  72.         return $this->lineno;
  73.     }
  74.     public function setTemplateLine(int $lineno): void
  75.     {
  76.         $this->lineno $lineno;
  77.         $this->updateRepr();
  78.     }
  79.     public function getSourceContext(): ?Source
  80.     {
  81.         return $this->name ? new Source($this->sourceCode$this->name$this->sourcePath) : null;
  82.     }
  83.     public function setSourceContext(Source $source null): void
  84.     {
  85.         if (null === $source) {
  86.             $this->sourceCode $this->name $this->sourcePath null;
  87.         } else {
  88.             $this->sourceCode $source->getCode();
  89.             $this->name $source->getName();
  90.             $this->sourcePath $source->getPath();
  91.         }
  92.         $this->updateRepr();
  93.     }
  94.     public function guess(): void
  95.     {
  96.         $this->guessTemplateInfo();
  97.         $this->updateRepr();
  98.     }
  99.     public function appendMessage($rawMessage): void
  100.     {
  101.         $this->rawMessage .= $rawMessage;
  102.         $this->updateRepr();
  103.     }
  104.     private function updateRepr(): void
  105.     {
  106.         $this->message $this->rawMessage;
  107.         if ($this->sourcePath && $this->lineno 0) {
  108.             $this->file $this->sourcePath;
  109.             $this->line $this->lineno;
  110.             return;
  111.         }
  112.         $dot false;
  113.         if ('.' === substr($this->message, -1)) {
  114.             $this->message substr($this->message0, -1);
  115.             $dot true;
  116.         }
  117.         $questionMark false;
  118.         if ('?' === substr($this->message, -1)) {
  119.             $this->message substr($this->message0, -1);
  120.             $questionMark true;
  121.         }
  122.         if ($this->name) {
  123.             if (\is_string($this->name) || (\is_object($this->name) && method_exists($this->name'__toString'))) {
  124.                 $name sprintf('"%s"'$this->name);
  125.             } else {
  126.                 $name json_encode($this->name);
  127.             }
  128.             $this->message .= sprintf(' in %s'$name);
  129.         }
  130.         if ($this->lineno && $this->lineno >= 0) {
  131.             $this->message .= sprintf(' at line %d'$this->lineno);
  132.         }
  133.         if ($dot) {
  134.             $this->message .= '.';
  135.         }
  136.         if ($questionMark) {
  137.             $this->message .= '?';
  138.         }
  139.     }
  140.     private function guessTemplateInfo(): void
  141.     {
  142.         $template null;
  143.         $templateClass null;
  144.         $backtrace debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT);
  145.         foreach ($backtrace as $trace) {
  146.             if (isset($trace['object']) && $trace['object'] instanceof Template) {
  147.                 $currentClass = \get_class($trace['object']);
  148.                 $isEmbedContainer null === $templateClass false === strpos($templateClass$currentClass);
  149.                 if (null === $this->name || ($this->name == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
  150.                     $template $trace['object'];
  151.                     $templateClass = \get_class($trace['object']);
  152.                 }
  153.             }
  154.         }
  155.         // update template name
  156.         if (null !== $template && null === $this->name) {
  157.             $this->name $template->getTemplateName();
  158.         }
  159.         // update template path if any
  160.         if (null !== $template && null === $this->sourcePath) {
  161.             $src $template->getSourceContext();
  162.             $this->sourceCode $src->getCode();
  163.             $this->sourcePath $src->getPath();
  164.         }
  165.         if (null === $template || $this->lineno > -1) {
  166.             return;
  167.         }
  168.         $r = new \ReflectionObject($template);
  169.         $file $r->getFileName();
  170.         $exceptions = [$e $this];
  171.         while ($e $e->getPrevious()) {
  172.             $exceptions[] = $e;
  173.         }
  174.         while ($e array_pop($exceptions)) {
  175.             $traces $e->getTrace();
  176.             array_unshift($traces, ['file' => $e->getFile(), 'line' => $e->getLine()]);
  177.             while ($trace array_shift($traces)) {
  178.                 if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
  179.                     continue;
  180.                 }
  181.                 foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
  182.                     if ($codeLine <= $trace['line']) {
  183.                         // update template line
  184.                         $this->lineno $templateLine;
  185.                         return;
  186.                     }
  187.                 }
  188.             }
  189.         }
  190.     }
  191. }