Error.php 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) 2009 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. /**
  11. * Twig base exception.
  12. *
  13. * @package twig
  14. * @author Fabien Potencier <fabien@symfony.com>
  15. */
  16. class Twig_Error extends Exception
  17. {
  18. protected $lineno;
  19. protected $filename;
  20. protected $rawMessage;
  21. protected $previous;
  22. /**
  23. * Constructor.
  24. *
  25. * @param string $message The error message
  26. * @param integer $lineno The template line where the error occurred
  27. * @param string $filename The template file name where the error occurred
  28. * @param Exception $previous The previous exception
  29. */
  30. public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
  31. {
  32. if (-1 === $lineno || null === $filename) {
  33. list($lineno, $filename) = $this->findTemplateInfo(null !== $previous ? $previous : $this, $lineno, $filename);
  34. }
  35. $this->lineno = $lineno;
  36. $this->filename = $filename;
  37. $this->rawMessage = $message;
  38. $this->updateRepr();
  39. if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  40. $this->previous = $previous;
  41. parent::__construct($this->message);
  42. } else {
  43. parent::__construct($this->message, 0, $previous);
  44. }
  45. }
  46. /**
  47. * Gets the raw message.
  48. *
  49. * @return string The raw message
  50. */
  51. public function getRawMessage()
  52. {
  53. return $this->rawMessage;
  54. }
  55. /**
  56. * Gets the filename where the error occurred.
  57. *
  58. * @return string The filename
  59. */
  60. public function getTemplateFile()
  61. {
  62. return $this->filename;
  63. }
  64. /**
  65. * Sets the filename where the error occurred.
  66. *
  67. * @param string $filename The filename
  68. */
  69. public function setTemplateFile($filename)
  70. {
  71. $this->filename = $filename;
  72. $this->updateRepr();
  73. }
  74. /**
  75. * Gets the template line where the error occurred.
  76. *
  77. * @return integer The template line
  78. */
  79. public function getTemplateLine()
  80. {
  81. return $this->lineno;
  82. }
  83. /**
  84. * Sets the template line where the error occurred.
  85. *
  86. * @param integer $lineno The template line
  87. */
  88. public function setTemplateLine($lineno)
  89. {
  90. $this->lineno = $lineno;
  91. $this->updateRepr();
  92. }
  93. /**
  94. * For PHP < 5.3.0, provides access to the getPrevious() method.
  95. *
  96. * @param string $method The method name
  97. * @param array $arguments The parameters to be passed to the method
  98. *
  99. * @return Exception The previous exception or null
  100. */
  101. public function __call($method, $arguments)
  102. {
  103. if ('getprevious' == strtolower($method)) {
  104. return $this->previous;
  105. }
  106. throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
  107. }
  108. protected function updateRepr()
  109. {
  110. $this->message = $this->rawMessage;
  111. $dot = false;
  112. if ('.' === substr($this->message, -1)) {
  113. $this->message = substr($this->message, 0, -1);
  114. $dot = true;
  115. }
  116. if (null !== $this->filename) {
  117. $this->message .= sprintf(' in %s', is_string($this->filename) ? '"'.$this->filename.'"' : json_encode($this->filename));
  118. }
  119. if ($this->lineno >= 0) {
  120. $this->message .= sprintf(' at line %d', $this->lineno);
  121. }
  122. if ($dot) {
  123. $this->message .= '.';
  124. }
  125. }
  126. protected function findTemplateInfo(Exception $e, $currentLine, $currentFile)
  127. {
  128. if (!function_exists('token_get_all')) {
  129. return array($currentLine, $currentFile);
  130. }
  131. $traces = $e->getTrace();
  132. foreach ($traces as $i => $trace) {
  133. if (!isset($trace['class']) || 'Twig_Template' === $trace['class']) {
  134. continue;
  135. }
  136. $r = new ReflectionClass($trace['class']);
  137. if (!$r->implementsInterface('Twig_TemplateInterface')) {
  138. continue;
  139. }
  140. if (!is_file($r->getFilename())) {
  141. // probably an eval()'d code
  142. return array($currentLine, $currentFile);
  143. }
  144. if (0 === $i) {
  145. $line = $e->getLine();
  146. } else {
  147. $line = isset($traces[$i - 1]['line']) ? $traces[$i - 1]['line'] : -log(0);
  148. }
  149. $tokens = token_get_all(file_get_contents($r->getFilename()));
  150. $templateline = -1;
  151. $template = null;
  152. foreach ($tokens as $token) {
  153. if (isset($token[2]) && $token[2] >= $line) {
  154. return array($templateline, $template);
  155. }
  156. if (T_COMMENT === $token[0] && null === $template && preg_match('#/\* +(.+) +\*/#', $token[1], $match)) {
  157. $template = $match[1];
  158. } elseif (T_COMMENT === $token[0] && preg_match('#^//\s*line (\d+)\s*$#', $token[1], $match)) {
  159. $templateline = $match[1];
  160. }
  161. }
  162. return array($currentLine, $template);
  163. }
  164. return array($currentLine, $currentFile);
  165. }
  166. }