Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
13532 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
			return $this->controller->appError($exception);
96
		}
97
		$method = $template = Inflector::variable(str_replace('Exception', '', get_class($exception)));
98
		$code = $exception->getCode();
99
 
100
		$methodExists = method_exists($this, $method);
101
 
102
		if ($exception instanceof CakeException && !$methodExists) {
103
			$method = '_cakeError';
104
			if (empty($template) || $template === 'internalError') {
105
				$template = 'error500';
106
			}
107
		} elseif ($exception instanceof PDOException) {
108
			$method = 'pdoError';
109
			$template = 'pdo_error';
110
			$code = 500;
111
		} elseif (!$methodExists) {
112
			$method = 'error500';
113
			if ($code >= 400 && $code < 500) {
114
				$method = 'error400';
115
			}
116
		}
117
 
118
		$isNotDebug = !Configure::read('debug');
119
		if ($isNotDebug && $method === '_cakeError') {
120
			$method = 'error400';
121
		}
122
		if ($isNotDebug && $code == 500) {
123
			$method = 'error500';
124
		}
125
		$this->template = $template;
126
		$this->method = $method;
127
		$this->error = $exception;
128
	}
129
 
130
/**
131
 * Get the controller instance to handle the exception.
132
 * Override this method in subclasses to customize the controller used.
133
 * This method returns the built in `CakeErrorController` normally, or if an error is repeated
134
 * a bare controller will be used.
135
 *
136
 * @param Exception $exception The exception to get a controller for.
137
 * @return Controller
138
 */
139
	protected function _getController($exception) {
140
		App::uses('AppController', 'Controller');
141
		App::uses('CakeErrorController', 'Controller');
142
		if (!$request = Router::getRequest(true)) {
143
			$request = new CakeRequest();
144
		}
145
		$response = new CakeResponse();
146
 
147
		if (method_exists($exception, 'responseHeader')) {
148
			$response->header($exception->responseHeader());
149
		}
150
 
151
		if (class_exists('AppController')) {
152
			try {
153
				$controller = new CakeErrorController($request, $response);
154
				$controller->startupProcess();
155
			} catch (Exception $e) {
156
				if (!empty($controller) && $controller->Components->enabled('RequestHandler')) {
157
					$controller->RequestHandler->startup($controller);
158
				}
159
			}
160
		}
161
		if (empty($controller)) {
162
			$controller = new Controller($request, $response);
163
			$controller->viewPath = 'Errors';
164
		}
165
		return $controller;
166
	}
167
 
168
/**
169
 * Renders the response for the exception.
170
 *
171
 * @return void
172
 */
173
	public function render() {
174
		if ($this->method) {
175
			call_user_func_array(array($this, $this->method), array($this->error));
176
		}
177
	}
178
 
179
/**
180
 * Generic handler for the internal framework errors CakePHP can generate.
181
 *
182
 * @param CakeException $error
183
 * @return void
184
 */
185
	protected function _cakeError(CakeException $error) {
186
		$url = $this->controller->request->here();
187
		$code = ($error->getCode() >= 400 && $error->getCode() < 506) ? $error->getCode() : 500;
188
		$this->controller->response->statusCode($code);
189
		$this->controller->set(array(
190
			'code' => $code,
191
			'url' => h($url),
192
			'name' => h($error->getMessage()),
193
			'error' => $error,
194
			'_serialize' => array('code', 'url', 'name')
195
		));
196
		$this->controller->set($error->getAttributes());
197
		$this->_outputMessage($this->template);
198
	}
199
 
200
/**
201
 * Convenience method to display a 400 series page.
202
 *
203
 * @param Exception $error
204
 * @return void
205
 */
206
	public function error400($error) {
207
		$message = $error->getMessage();
208
		if (!Configure::read('debug') && $error instanceof CakeException) {
209
			$message = __d('cake', 'Not Found');
210
		}
211
		$url = $this->controller->request->here();
212
		$this->controller->response->statusCode($error->getCode());
213
		$this->controller->set(array(
214
			'name' => h($message),
215
			'url' => h($url),
216
			'error' => $error,
217
			'_serialize' => array('name', 'url')
218
		));
219
		$this->_outputMessage('error400');
220
	}
221
 
222
/**
223
 * Convenience method to display a 500 page.
224
 *
225
 * @param Exception $error
226
 * @return void
227
 */
228
	public function error500($error) {
229
		$message = $error->getMessage();
230
		if (!Configure::read('debug')) {
231
			$message = __d('cake', 'An Internal Error Has Occurred.');
232
		}
233
		$url = $this->controller->request->here();
234
		$code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500;
235
		$this->controller->response->statusCode($code);
236
		$this->controller->set(array(
237
			'name' => h($message),
238
			'message' => h($url),
239
			'error' => $error,
240
			'_serialize' => array('name', 'message')
241
		));
242
		$this->_outputMessage('error500');
243
	}
244
 
245
/**
246
 * Convenience method to display a PDOException.
247
 *
248
 * @param PDOException $error
249
 * @return void
250
 */
251
	public function pdoError(PDOException $error) {
252
		$url = $this->controller->request->here();
253
		$code = 500;
254
		$this->controller->response->statusCode($code);
255
		$this->controller->set(array(
256
			'code' => $code,
257
			'url' => h($url),
258
			'name' => h($error->getMessage()),
259
			'error' => $error,
260
			'_serialize' => array('code', 'url', 'name', 'error')
261
		));
262
		$this->_outputMessage($this->template);
263
	}
264
 
265
/**
266
 * Generate the response using the controller object.
267
 *
268
 * @param string $template The template to render.
269
 * @return void
270
 */
271
	protected function _outputMessage($template) {
272
		try {
273
			$this->controller->render($template);
274
			$this->controller->afterFilter();
275
			$this->controller->response->send();
276
		} catch (MissingViewException $e) {
277
			$attributes = $e->getAttributes();
278
			if (isset($attributes['file']) && strpos($attributes['file'], 'error500') !== false) {
279
				$this->_outputMessageSafe('error500');
280
			} else {
281
				$this->_outputMessage('error500');
282
			}
283
		} catch (Exception $e) {
284
			$this->_outputMessageSafe('error500');
285
		}
286
	}
287
 
288
/**
289
 * A safer way to render error messages, replaces all helpers, with basics
290
 * and doesn't call component methods.
291
 *
292
 * @param string $template The template to render
293
 * @return void
294
 */
295
	protected function _outputMessageSafe($template) {
296
		$this->controller->layoutPath = null;
297
		$this->controller->subDir = null;
298
		$this->controller->viewPath = 'Errors';
299
		$this->controller->layout = 'error';
300
		$this->controller->helpers = array('Form', 'Html', 'Session');
301
 
302
		$view = new View($this->controller);
303
		$this->controller->response->body($view->render($template, 'error'));
304
		$this->controller->response->type('html');
305
		$this->controller->response->send();
306
	}
307
 
308
}