4 * This file is part of Twig.
6 * (c) 2009 Fabien Potencier
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
13 * Twig base exception.
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).
21 * To help debugging template issues, this class tracks the original template
22 * name and line where the error occurred.
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.
32 * @author Fabien Potencier <fabien@symfony.com>
34 class Twig_Error
extends Exception
38 protected $rawMessage;
44 * Set both the line number and the filename to false to
45 * disable automatic guessing of the original template name
48 * Set the line number to -1 to enable its automatic guessing.
49 * Set the filename to null to enable its automatic guessing.
51 * By default, automatic guessing is enabled.
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
58 public function __construct($message, $lineno = -1, $filename = null, Exception
$previous = null)
60 if (version_compare(PHP_VERSION
, '5.3.0', '<')) {
61 $this->previous
= $previous;
62 parent
::__construct('');
64 parent
::__construct('', 0, $previous);
67 $this->lineno
= $lineno;
68 $this->filename
= $filename;
70 if (-1 === $this->lineno
|| null === $this->filename
) {
71 $this->guessTemplateInfo();
74 $this->rawMessage
= $message;
80 * Gets the raw message.
82 * @return string The raw message
84 public function getRawMessage()
86 return $this->rawMessage
;
90 * Gets the filename where the error occurred.
92 * @return string The filename
94 public function getTemplateFile()
96 return $this->filename
;
100 * Sets the filename where the error occurred.
102 * @param string $filename The filename
104 public function setTemplateFile($filename)
106 $this->filename
= $filename;
112 * Gets the template line where the error occurred.
114 * @return integer The template line
116 public function getTemplateLine()
118 return $this->lineno
;
122 * Sets the template line where the error occurred.
124 * @param integer $lineno The template line
126 public function setTemplateLine($lineno)
128 $this->lineno
= $lineno;
133 public function guess()
135 $this->guessTemplateInfo();
140 * For PHP < 5.3.0, provides access to the getPrevious() method.
142 * @param string $method The method name
143 * @param array $arguments The parameters to be passed to the method
145 * @return Exception The previous exception or null
147 * @throws BadMethodCallException
149 public function __call($method, $arguments)
151 if ('getprevious' == strtolower($method)) {
152 return $this->previous
;
155 throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
158 protected function updateRepr()
160 $this->message
= $this->rawMessage
;
163 if ('.' === substr($this->message
, -1)) {
164 $this->message
= substr($this->message
, 0, -1);
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
);
172 $filename = json_encode($this->filename
);
174 $this->message
.= sprintf(' in %s', $filename);
177 if ($this->lineno
&& $this->lineno
>= 0) {
178 $this->message
.= sprintf(' at line %d', $this->lineno
);
182 $this->message
.= '.';
186 protected function guessTemplateInfo()
189 $templateClass = null;
191 if (version_compare(phpversion(), '5.3.6', '>=')) {
192 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS
| DEBUG_BACKTRACE_PROVIDE_OBJECT
);
194 $backtrace = debug_backtrace();
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']);
208 // update template filename
209 if (null !== $template && null === $this->filename
) {
210 $this->filename
= $template->getTemplateName();
213 if (null === $template || $this->lineno
> -1) {
217 $r = new ReflectionObject($template);
218 $file = $r->getFileName();
220 $exceptions = array($e = $this);
221 while (($e instanceof self
|| method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
225 while ($e = array_pop($exceptions)) {
226 $traces = $e->getTrace();
227 while ($trace = array_shift($traces)) {
228 if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
232 foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
233 if ($codeLine <= $trace['line']) {
234 // update template line
235 $this->lineno
= $templateLine;