Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
12345 anikendra 1
<?php
2
/**
3
 * Exception Renderer
4
 *
5
 * Provides Exception rendering features. Which allow exceptions to be rendered
6
 * as HTML pages.
7
 *
8
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
9
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
10
 *
11
 * Licensed under The MIT License
12
 * For full copyright and license information, please see the LICENSE.txt
13
 * Redistributions of files must retain the above copyright notice.
14
 *
15
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
16
 * @link          http://cakephp.org CakePHP(tm) Project
17
 * @package       Cake.Error
18
 * @since         CakePHP(tm) v 2.0
19
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
20
 */
21
 
22
App::uses('Sanitize', 'Utility');
23
App::uses('Router', 'Routing');
24
App::uses('CakeResponse', 'Network');
25
App::uses('Controller', 'Controller');
26
 
27
/**
28
 * Exception Renderer.
29
 *
30
 * Captures and handles all unhandled exceptions. Displays helpful framework errors when debug > 1.
31
 * When debug < 1 a CakeException will render 404 or 500 errors. If an uncaught exception is thrown
32
 * and it is a type that ExceptionHandler does not know about it will be treated as a 500 error.
33
 *
34
 * ### Implementing application specific exception rendering
35
 *
36
 * You can implement application specific exception handling in one of a few ways:
37
 *
38
 * - Create a AppController::appError();
39
 * - Create a subclass of ExceptionRenderer and configure it to be the `Exception.renderer`
40
 *
41
 * #### Using AppController::appError();
42
 *
43
 * This controller method is called instead of the default exception handling. It receives the
44
 * thrown exception as its only argument. You should implement your error handling in that method.
45
 *
46
 * #### Using a subclass of ExceptionRenderer
47
 *
48
 * Using a subclass of ExceptionRenderer gives you full control over how Exceptions are rendered, you
49
 * can configure your class in your core.php, with `Configure::write('Exception.renderer', 'MyClass');`
50
 * You should place any custom exception renderers in `app/Lib/Error`.
51
 *
52
 * @package       Cake.Error
53
 */
54
class ExceptionRenderer {
55
 
56
/**
57
 * Controller instance.
58
 *
59
 * @var Controller
60
 */
61
	public $controller = null;
62
 
63
/**
64
 * template to render for CakeException
65
 *
66
 * @var string
67
 */
68
	public $template = '';
69
 
70
/**
71
 * The method corresponding to the Exception this object is for.
72
 *
73
 * @var string
74
 */
75
	public $method = '';
76
 
77
/**
78
 * The exception being handled.
79
 *
80
 * @var Exception
81
 */
82
	public $error = null;
83
 
84
/**
85
 * Creates the controller to perform rendering on the error response.
86
 * If the error is a CakeException it will be converted to either a 400 or a 500
87
 * code error depending on the code used to construct the error.
88
 *
89
 * @param Exception $exception Exception
90
 */
91
	public function __construct(Exception $exception) {
92
		$this->controller = $this->_getController($exception);
93
 
94
		if (method_exists($this->controller, 'appError')) {
95
			$this->controller->appError($exception);
96
			return;
97
		}
98
		$method = $template = Inflector::variable(str_replace('Exception', '', get_class($exception)));
99
		$code = $exception->getCode();
100
 
101
		$methodExists = method_exists($this, $method);
102
 
103
		if ($exception instanceof CakeException && !$methodExists) {
104
			$method = '_cakeError';
105
			if (empty($template) || $template === 'internalError') {
106
				$template = 'error500';
107
			}
108
		} elseif ($exception instanceof PDOException) {
109
			$method = 'pdoError';
110
			$template = 'pdo_error';
111
			$code = 500;
112
		} elseif (!$methodExists) {
113
			$method = 'error500';
114
			if ($code >= 400 && $code < 500) {
115
				$method = 'error400';
116
			}
117
		}
118
 
119
		$isNotDebug = !Configure::read('debug');
120
		if ($isNotDebug && $method === '_cakeError') {
121
			$method = 'error400';
122
		}
123
		if ($isNotDebug && $code == 500) {
124
			$method = 'error500';
125
		}
126
		$this->template = $template;
127
		$this->method = $method;
128
		$this->error = $exception;
129
	}
130
 
131
/**
132
 * Get the controller instance to handle the exception.
133
 * Override this method in subclasses to customize the controller used.
134
 * This method returns the built in `CakeErrorController` normally, or if an error is repeated
135
 * a bare controller will be used.
136
 *
137
 * @param Exception $exception The exception to get a controller for.
138
 * @return Controller
139
 */
140
	protected function _getController($exception) {
141
		App::uses('AppController', 'Controller');
142
		App::uses('CakeErrorController', 'Controller');
143
		if (!$request = Router::getRequest(true)) {
144
			$request = new CakeRequest();
145
		}
146
		$response = new CakeResponse();
147
 
148
		if (method_exists($exception, 'responseHeader')) {
149
			$response->header($exception->responseHeader());
150
		}
151
 
152
		if (class_exists('AppController')) {
153
			try {
154
				$controller = new CakeErrorController($request, $response);
155
				$controller->startupProcess();
156
			} catch (Exception $e) {
157
				if (!empty($controller) && $controller->Components->enabled('RequestHandler')) {
158
					$controller->RequestHandler->startup($controller);
159
				}
160
			}
161
		}
162
		if (empty($controller)) {
163
			$controller = new Controller($request, $response);
164
			$controller->viewPath = 'Errors';
165
		}
166
		return $controller;
167
	}
168
 
169
/**
170
 * Renders the response for the exception.
171
 *
172
 * @return void
173
 */
174
	public function render() {
175
		if ($this->method) {
176
			call_user_func_array(array($this, $this->method), array($this->error));
177
		}
178
	}
179
 
180
/**
181
 * Generic handler for the internal framework errors CakePHP can generate.
182
 *
183
 * @param CakeException $error The exception to render.
184
 * @return void
185
 */
186
	protected function _cakeError(CakeException $error) {
187
		$url = $this->controller->request->here();
188
		$code = ($error->getCode() >= 400 && $error->getCode() < 506) ? $error->getCode() : 500;
189
		$this->controller->response->statusCode($code);
190
		$this->controller->set(array(
191
			'code' => $code,
192
			'name' => h($error->getMessage()),
193
			'message' => h($error->getMessage()),
194
			'url' => h($url),
195
			'error' => $error,
196
			'_serialize' => array('code', 'name', 'message', 'url')
197
		));
198
		$this->controller->set($error->getAttributes());
199
		$this->_outputMessage($this->template);
200
	}
201
 
202
/**
203
 * Convenience method to display a 400 series page.
204
 *
205
 * @param Exception $error The exception to render.
206
 * @return void
207
 */
208
	public function error400($error) {
209
		$message = $error->getMessage();
210
		if (!Configure::read('debug') && $error instanceof CakeException) {
211
			$message = __d('cake', 'Not Found');
212
		}
213
		$url = $this->controller->request->here();
214
		$this->controller->response->statusCode($error->getCode());
215
		$this->controller->set(array(
216
			'name' => h($message),
217
			'message' => h($message),
218
			'url' => h($url),
219
			'error' => $error,
220
			'_serialize' => array('name', 'message', 'url')
221
		));
222
		$this->_outputMessage('error400');
223
	}
224
 
225
/**
226
 * Convenience method to display a 500 page.
227
 *
228
 * @param Exception $error The exception to render.
229
 * @return void
230
 */
231
	public function error500($error) {
232
		$message = $error->getMessage();
233
		if (!Configure::read('debug')) {
234
			$message = __d('cake', 'An Internal Error Has Occurred.');
235
		}
236
		$url = $this->controller->request->here();
237
		$code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500;
238
		$this->controller->response->statusCode($code);
239
		$this->controller->set(array(
240
			'name' => h($message),
241
			'message' => h($message),
242
			'url' => h($url),
243
			'error' => $error,
244
			'_serialize' => array('name', 'message', 'url')
245
		));
246
		$this->_outputMessage('error500');
247
	}
248
 
249
/**
250
 * Convenience method to display a PDOException.
251
 *
252
 * @param PDOException $error The exception to render.
253
 * @return void
254
 */
255
	public function pdoError(PDOException $error) {
256
		$url = $this->controller->request->here();
257
		$code = 500;
258
		$this->controller->response->statusCode($code);
259
		$this->controller->set(array(
260
			'code' => $code,
261
			'name' => h($error->getMessage()),
262
			'message' => h($error->getMessage()),
263
			'url' => h($url),
264
			'error' => $error,
265
			'_serialize' => array('code', 'name', 'message', 'url', 'error')
266
		));
267
		$this->_outputMessage($this->template);
268
	}
269
 
270
/**
271
 * Generate the response using the controller object.
272
 *
273
 * @param string $template The template to render.
274
 * @return void
275
 */
276
	protected function _outputMessage($template) {
277
		try {
278
			$this->controller->render($template);
279
			$this->controller->afterFilter();
280
			$this->controller->response->send();
281
		} catch (MissingViewException $e) {
282
			$attributes = $e->getAttributes();
283
			if (isset($attributes['file']) && strpos($attributes['file'], 'error500') !== false) {
284
				$this->_outputMessageSafe('error500');
285
			} else {
286
				$this->_outputMessage('error500');
287
			}
288
		} catch (MissingPluginException $e) {
289
			$attributes = $e->getAttributes();
290
			if (isset($attributes['plugin']) && $attributes['plugin'] === $this->controller->plugin) {
291
				$this->controller->plugin = null;
292
			}
293
			$this->_outputMessageSafe('error500');
294
		} catch (Exception $e) {
295
			$this->_outputMessageSafe('error500');
296
		}
297
	}
298
 
299
/**
300
 * A safer way to render error messages, replaces all helpers, with basics
301
 * and doesn't call component methods.
302
 *
303
 * @param string $template The template to render
304
 * @return void
305
 */
306
	protected function _outputMessageSafe($template) {
307
		$this->controller->layoutPath = null;
308
		$this->controller->subDir = null;
309
		$this->controller->viewPath = 'Errors';
310
		$this->controller->layout = 'error';
311
		$this->controller->helpers = array('Form', 'Html', 'Session');
312
 
313
		$view = new View($this->controller);
314
		$this->controller->response->body($view->render($template, 'error'));
315
		$this->controller->response->type('html');
316
		$this->controller->response->send();
317
	}
318
 
319
}