Просмотр файла engine/classes/lib/Twig/Error.php

Размер файла: 7.32Kb
  1. <?php
  2.  
  3. /*
  4. * This file is part of Twig.
  5. *
  6. * (c) 2009 Fabien Potencier
  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. * Twig base exception.
  14. *
  15. * This exception class and its children must only be used when
  16. * an error occurs during the loading of a template, when a syntax error
  17. * is detected in a template, or when rendering a template. Other
  18. * errors must use regular PHP exception classes (like when the template
  19. * cache directory is not writable for instance).
  20. *
  21. * To help debugging template issues, this class tracks the original template
  22. * name and line where the error occurred.
  23. *
  24. * Whenever possible, you must set these information (original template name
  25. * and line number) yourself by passing them to the constructor. If some or all
  26. * these information are not available from where you throw the exception, then
  27. * this class will guess them automatically (when the line number is set to -1
  28. * and/or the filename is set to null). As this is a costly operation, this
  29. * can be disabled by passing false for both the filename and the line number
  30. * when creating a new instance of this class.
  31. *
  32. * @author Fabien Potencier <fabien@symfony.com>
  33. */
  34. class Twig_Error extends Exception
  35. {
  36. protected $lineno;
  37. protected $filename;
  38. protected $rawMessage;
  39. protected $previous;
  40.  
  41. /**
  42. * Constructor.
  43. *
  44. * Set both the line number and the filename to false to
  45. * disable automatic guessing of the original template name
  46. * and line number.
  47. *
  48. * Set the line number to -1 to enable its automatic guessing.
  49. * Set the filename to null to enable its automatic guessing.
  50. *
  51. * By default, automatic guessing is enabled.
  52. *
  53. * @param string $message The error message
  54. * @param integer $lineno The template line where the error occurred
  55. * @param string $filename The template file name where the error occurred
  56. * @param Exception $previous The previous exception
  57. */
  58. public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
  59. {
  60. if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  61. $this->previous = $previous;
  62. parent::__construct('');
  63. } else {
  64. parent::__construct('', 0, $previous);
  65. }
  66.  
  67. $this->lineno = $lineno;
  68. $this->filename = $filename;
  69.  
  70. if (-1 === $this->lineno || null === $this->filename) {
  71. $this->guessTemplateInfo();
  72. }
  73.  
  74. $this->rawMessage = $message;
  75.  
  76. $this->updateRepr();
  77. }
  78.  
  79. /**
  80. * Gets the raw message.
  81. *
  82. * @return string The raw message
  83. */
  84. public function getRawMessage()
  85. {
  86. return $this->rawMessage;
  87. }
  88.  
  89. /**
  90. * Gets the filename where the error occurred.
  91. *
  92. * @return string The filename
  93. */
  94. public function getTemplateFile()
  95. {
  96. return $this->filename;
  97. }
  98.  
  99. /**
  100. * Sets the filename where the error occurred.
  101. *
  102. * @param string $filename The filename
  103. */
  104. public function setTemplateFile($filename)
  105. {
  106. $this->filename = $filename;
  107.  
  108. $this->updateRepr();
  109. }
  110.  
  111. /**
  112. * Gets the template line where the error occurred.
  113. *
  114. * @return integer The template line
  115. */
  116. public function getTemplateLine()
  117. {
  118. return $this->lineno;
  119. }
  120.  
  121. /**
  122. * Sets the template line where the error occurred.
  123. *
  124. * @param integer $lineno The template line
  125. */
  126. public function setTemplateLine($lineno)
  127. {
  128. $this->lineno = $lineno;
  129.  
  130. $this->updateRepr();
  131. }
  132.  
  133. public function guess()
  134. {
  135. $this->guessTemplateInfo();
  136. $this->updateRepr();
  137. }
  138.  
  139. /**
  140. * For PHP < 5.3.0, provides access to the getPrevious() method.
  141. *
  142. * @param string $method The method name
  143. * @param array $arguments The parameters to be passed to the method
  144. *
  145. * @return Exception The previous exception or null
  146. *
  147. * @throws BadMethodCallException
  148. */
  149. public function __call($method, $arguments)
  150. {
  151. if ('getprevious' == strtolower($method)) {
  152. return $this->previous;
  153. }
  154.  
  155. throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
  156. }
  157.  
  158. protected function updateRepr()
  159. {
  160. $this->message = $this->rawMessage;
  161.  
  162. $dot = false;
  163. if ('.' === substr($this->message, -1)) {
  164. $this->message = substr($this->message, 0, -1);
  165. $dot = true;
  166. }
  167.  
  168. if ($this->filename) {
  169. if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
  170. $filename = sprintf('"%s"', $this->filename);
  171. } else {
  172. $filename = json_encode($this->filename);
  173. }
  174. $this->message .= sprintf(' in %s', $filename);
  175. }
  176.  
  177. if ($this->lineno && $this->lineno >= 0) {
  178. $this->message .= sprintf(' at line %d', $this->lineno);
  179. }
  180.  
  181. if ($dot) {
  182. $this->message .= '.';
  183. }
  184. }
  185.  
  186. protected function guessTemplateInfo()
  187. {
  188. $template = null;
  189. $templateClass = null;
  190.  
  191. if (version_compare(phpversion(), '5.3.6', '>=')) {
  192. $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
  193. } else {
  194. $backtrace = debug_backtrace();
  195. }
  196.  
  197. foreach ($backtrace as $trace) {
  198. if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
  199. $currentClass = get_class($trace['object']);
  200. $isEmbedContainer = 0 === strpos($templateClass, $currentClass);
  201. if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
  202. $template = $trace['object'];
  203. $templateClass = get_class($trace['object']);
  204. }
  205. }
  206. }
  207.  
  208. // update template filename
  209. if (null !== $template && null === $this->filename) {
  210. $this->filename = $template->getTemplateName();
  211. }
  212.  
  213. if (null === $template || $this->lineno > -1) {
  214. return;
  215. }
  216.  
  217. $r = new ReflectionObject($template);
  218. $file = $r->getFileName();
  219.  
  220. // hhvm has a bug where eval'ed files comes out as the current directory
  221. if (is_dir($file)) {
  222. $file = '';
  223. }
  224.  
  225. $exceptions = array($e = $this);
  226. while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
  227. $exceptions[] = $e;
  228. }
  229.  
  230. while ($e = array_pop($exceptions)) {
  231. $traces = $e->getTrace();
  232. while ($trace = array_shift($traces)) {
  233. if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
  234. continue;
  235. }
  236.  
  237. foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
  238. if ($codeLine <= $trace['line']) {
  239. // update template line
  240. $this->lineno = $templateLine;
  241.  
  242. return;
  243. }
  244. }
  245. }
  246. }
  247. }
  248. }