diff options
Diffstat (limited to 'inc/Twig/Error.php')
-rw-r--r-- | inc/Twig/Error.php | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/inc/Twig/Error.php b/inc/Twig/Error.php new file mode 100644 index 00000000..72d91a98 --- /dev/null +++ b/inc/Twig/Error.php | |||
@@ -0,0 +1,239 @@ | |||
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 | |||
190 | if (version_compare(phpversion(), '5.3.6', '>=')) { | ||
191 | $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT); | ||
192 | } else { | ||
193 | $backtrace = debug_backtrace(); | ||
194 | } | ||
195 | |||
196 | foreach ($backtrace as $trace) { | ||
197 | if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) { | ||
198 | if (null === $this->filename || $this->filename == $trace['object']->getTemplateName()) { | ||
199 | $template = $trace['object']; | ||
200 | } | ||
201 | } | ||
202 | } | ||
203 | |||
204 | // update template filename | ||
205 | if (null !== $template && null === $this->filename) { | ||
206 | $this->filename = $template->getTemplateName(); | ||
207 | } | ||
208 | |||
209 | if (null === $template || $this->lineno > -1) { | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | $r = new ReflectionObject($template); | ||
214 | $file = $r->getFileName(); | ||
215 | |||
216 | $exceptions = array($e = $this); | ||
217 | while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) { | ||
218 | $exceptions[] = $e; | ||
219 | } | ||
220 | |||
221 | while ($e = array_pop($exceptions)) { | ||
222 | $traces = $e->getTrace(); | ||
223 | while ($trace = array_shift($traces)) { | ||
224 | if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) { | ||
225 | continue; | ||
226 | } | ||
227 | |||
228 | foreach ($template->getDebugInfo() as $codeLine => $templateLine) { | ||
229 | if ($codeLine <= $trace['line']) { | ||
230 | // update template line | ||
231 | $this->lineno = $templateLine; | ||
232 | |||
233 | return; | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | } | ||