CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.8 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.8
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • BaseErrorHandler
  • Debugger
  • ErrorHandler
  • ExceptionRenderer

Interfaces

  • ExceptionRendererInterface

Exceptions

  • FatalErrorException
  • PHP7ErrorException
  1: <?php
  2: /**
  3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5:  *
  6:  * Licensed under The MIT License
  7:  * For full copyright and license information, please see the LICENSE.txt
  8:  * Redistributions of files must retain the above copyright notice.
  9:  *
 10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 11:  * @link          https://cakephp.org CakePHP(tm) Project
 12:  * @since         2.0.0
 13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
 14:  */
 15: namespace Cake\Error;
 16: 
 17: use Cake\Controller\Controller;
 18: use Cake\Core\App;
 19: use Cake\Core\Configure;
 20: use Cake\Core\Exception\Exception as CakeException;
 21: use Cake\Core\Exception\MissingPluginException;
 22: use Cake\Event\Event;
 23: use Cake\Http\Exception\HttpException;
 24: use Cake\Http\Response;
 25: use Cake\Http\ServerRequest;
 26: use Cake\Http\ServerRequestFactory;
 27: use Cake\Routing\DispatcherFactory;
 28: use Cake\Routing\Router;
 29: use Cake\Utility\Inflector;
 30: use Cake\View\Exception\MissingTemplateException;
 31: use Exception;
 32: use PDOException;
 33: 
 34: /**
 35:  * Exception Renderer.
 36:  *
 37:  * Captures and handles all unhandled exceptions. Displays helpful framework errors when debug is true.
 38:  * When debug is false a ExceptionRenderer will render 404 or 500 errors. If an uncaught exception is thrown
 39:  * and it is a type that ExceptionHandler does not know about it will be treated as a 500 error.
 40:  *
 41:  * ### Implementing application specific exception rendering
 42:  *
 43:  * You can implement application specific exception handling by creating a subclass of
 44:  * ExceptionRenderer and configure it to be the `exceptionRenderer` in config/error.php
 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 config/app.php.
 50:  */
 51: class ExceptionRenderer implements ExceptionRendererInterface
 52: {
 53:     /**
 54:      * The exception being handled.
 55:      *
 56:      * @var \Exception
 57:      */
 58:     protected $error;
 59: 
 60:     /**
 61:      * Controller instance.
 62:      *
 63:      * @var \Cake\Controller\Controller
 64:      */
 65:     protected $controller;
 66: 
 67:     /**
 68:      * Template to render for Cake\Core\Exception\Exception
 69:      *
 70:      * @var string
 71:      */
 72:     protected $template = '';
 73: 
 74:     /**
 75:      * The method corresponding to the Exception this object is for.
 76:      *
 77:      * @var string
 78:      */
 79:     protected $method = '';
 80: 
 81:     /**
 82:      * If set, this will be request used to create the controller that will render
 83:      * the error.
 84:      *
 85:      * @var \Cake\Http\ServerRequest|null
 86:      */
 87:     protected $request = null;
 88: 
 89:     /**
 90:      * Creates the controller to perform rendering on the error response.
 91:      * If the error is a Cake\Core\Exception\Exception it will be converted to either a 400 or a 500
 92:      * code error depending on the code used to construct the error.
 93:      *
 94:      * @param \Exception $exception Exception.
 95:      * @param \Cake\Http\ServerRequest $request The request - if this is set it will be used instead of creating a new one
 96:      */
 97:     public function __construct(Exception $exception, ServerRequest $request = null)
 98:     {
 99:         $this->error = $exception;
100:         $this->request = $request;
101:         $this->controller = $this->_getController();
102:     }
103: 
104:     /**
105:      * Returns the unwrapped exception object in case we are dealing with
106:      * a PHP 7 Error object
107:      *
108:      * @param \Exception $exception The object to unwrap
109:      * @return \Exception|\Error
110:      */
111:     protected function _unwrap($exception)
112:     {
113:         return $exception instanceof PHP7ErrorException ? $exception->getError() : $exception;
114:     }
115: 
116:     /**
117:      * Get the controller instance to handle the exception.
118:      * Override this method in subclasses to customize the controller used.
119:      * This method returns the built in `ErrorController` normally, or if an error is repeated
120:      * a bare controller will be used.
121:      *
122:      * @return \Cake\Controller\Controller
123:      * @triggers Controller.startup $controller
124:      */
125:     protected function _getController()
126:     {
127:         $request = $this->request;
128:         $routerRequest = Router::getRequest(true);
129:         // Fallback to the request in the router or make a new one from
130:         // $_SERVER
131:         if ($request === null) {
132:             $request = $routerRequest ?: ServerRequestFactory::fromGlobals();
133:         }
134: 
135:         // If the current request doesn't have routing data, but we
136:         // found a request in the router context copy the params over
137:         if ($request->getParam('controller') === false && $routerRequest !== null) {
138:             $request = $request->withAttribute('params', $routerRequest->getAttribute('params'));
139:         }
140: 
141:         $response = new Response();
142:         $controller = null;
143: 
144:         try {
145:             $namespace = 'Controller';
146:             $prefix = $request->getParam('prefix');
147:             if ($prefix) {
148:                 if (strpos($prefix, '/') === false) {
149:                     $namespace .= '/' . Inflector::camelize($prefix);
150:                 } else {
151:                     $prefixes = array_map(
152:                         'Cake\Utility\Inflector::camelize',
153:                         explode('/', $prefix)
154:                     );
155:                     $namespace .= '/' . implode('/', $prefixes);
156:                 }
157:             }
158: 
159:             $class = App::className('Error', $namespace, 'Controller');
160:             if (!$class && $namespace !== 'Controller') {
161:                 $class = App::className('Error', 'Controller', 'Controller');
162:             }
163: 
164:             /* @var \Cake\Controller\Controller $controller */
165:             $controller = new $class($request, $response);
166:             $controller->startupProcess();
167:             $startup = true;
168:         } catch (Exception $e) {
169:             $startup = false;
170:         }
171: 
172:         // Retry RequestHandler, as another aspect of startupProcess()
173:         // could have failed. Ignore any exceptions out of startup, as
174:         // there could be userland input data parsers.
175:         if ($startup === false && !empty($controller) && isset($controller->RequestHandler)) {
176:             try {
177:                 $event = new Event('Controller.startup', $controller);
178:                 $controller->RequestHandler->startup($event);
179:             } catch (Exception $e) {
180:             }
181:         }
182:         if (empty($controller)) {
183:             $controller = new Controller($request, $response);
184:         }
185: 
186:         return $controller;
187:     }
188: 
189:     /**
190:      * Renders the response for the exception.
191:      *
192:      * @return \Cake\Http\Response The response to be sent.
193:      */
194:     public function render()
195:     {
196:         $exception = $this->error;
197:         $code = $this->_code($exception);
198:         $method = $this->_method($exception);
199:         $template = $this->_template($exception, $method, $code);
200:         $unwrapped = $this->_unwrap($exception);
201: 
202:         if (method_exists($this, $method)) {
203:             return $this->_customMethod($method, $unwrapped);
204:         }
205: 
206:         $message = $this->_message($exception, $code);
207:         $url = $this->controller->getRequest()->getRequestTarget();
208:         $response = $this->controller->getResponse();
209: 
210:         if ($exception instanceof CakeException) {
211:             foreach ((array)$exception->responseHeader() as $key => $value) {
212:                 $response = $response->withHeader($key, $value);
213:             }
214:         }
215:         $response = $response->withStatus($code);
216: 
217:         $viewVars = [
218:             'message' => $message,
219:             'url' => h($url),
220:             'error' => $unwrapped,
221:             'code' => $code,
222:             '_serialize' => ['message', 'url', 'code']
223:         ];
224: 
225:         $isDebug = Configure::read('debug');
226:         if ($isDebug) {
227:             $viewVars['trace'] = Debugger::formatTrace($unwrapped->getTrace(), [
228:                 'format' => 'array',
229:                 'args' => false
230:             ]);
231:             $viewVars['file'] = $exception->getFile() ?: 'null';
232:             $viewVars['line'] = $exception->getLine() ?: 'null';
233:             $viewVars['_serialize'][] = 'file';
234:             $viewVars['_serialize'][] = 'line';
235:         }
236:         $this->controller->set($viewVars);
237: 
238:         if ($unwrapped instanceof CakeException && $isDebug) {
239:             $this->controller->set($unwrapped->getAttributes());
240:         }
241:         $this->controller->response = $response;
242: 
243:         return $this->_outputMessage($template);
244:     }
245: 
246:     /**
247:      * Render a custom error method/template.
248:      *
249:      * @param string $method The method name to invoke.
250:      * @param \Exception $exception The exception to render.
251:      * @return \Cake\Http\Response The response to send.
252:      */
253:     protected function _customMethod($method, $exception)
254:     {
255:         $result = call_user_func([$this, $method], $exception);
256:         $this->_shutdown();
257:         if (is_string($result)) {
258:             $result = $this->controller->response->withStringBody($result);
259:         }
260: 
261:         return $result;
262:     }
263: 
264:     /**
265:      * Get method name
266:      *
267:      * @param \Exception $exception Exception instance.
268:      * @return string
269:      */
270:     protected function _method(Exception $exception)
271:     {
272:         $exception = $this->_unwrap($exception);
273:         list(, $baseClass) = namespaceSplit(get_class($exception));
274: 
275:         if (substr($baseClass, -9) === 'Exception') {
276:             $baseClass = substr($baseClass, 0, -9);
277:         }
278: 
279:         $method = Inflector::variable($baseClass) ?: 'error500';
280: 
281:         return $this->method = $method;
282:     }
283: 
284:     /**
285:      * Get error message.
286:      *
287:      * @param \Exception $exception Exception.
288:      * @param int $code Error code.
289:      * @return string Error message
290:      */
291:     protected function _message(Exception $exception, $code)
292:     {
293:         $exception = $this->_unwrap($exception);
294:         $message = $exception->getMessage();
295: 
296:         if (!Configure::read('debug') &&
297:             !($exception instanceof HttpException)
298:         ) {
299:             if ($code < 500) {
300:                 $message = __d('cake', 'Not Found');
301:             } else {
302:                 $message = __d('cake', 'An Internal Error Has Occurred.');
303:             }
304:         }
305: 
306:         return $message;
307:     }
308: 
309:     /**
310:      * Get template for rendering exception info.
311:      *
312:      * @param \Exception $exception Exception instance.
313:      * @param string $method Method name.
314:      * @param int $code Error code.
315:      * @return string Template name
316:      */
317:     protected function _template(Exception $exception, $method, $code)
318:     {
319:         $exception = $this->_unwrap($exception);
320:         $isHttpException = $exception instanceof HttpException;
321: 
322:         if (!Configure::read('debug') && !$isHttpException || $isHttpException) {
323:             $template = 'error500';
324:             if ($code < 500) {
325:                 $template = 'error400';
326:             }
327: 
328:             return $this->template = $template;
329:         }
330: 
331:         $template = $method ?: 'error500';
332: 
333:         if ($exception instanceof PDOException) {
334:             $template = 'pdo_error';
335:         }
336: 
337:         return $this->template = $template;
338:     }
339: 
340:     /**
341:      * Get HTTP status code.
342:      *
343:      * @param \Exception $exception Exception.
344:      * @return int A valid HTTP error status code.
345:      */
346:     protected function _code(Exception $exception)
347:     {
348:         $code = 500;
349: 
350:         $exception = $this->_unwrap($exception);
351:         $errorCode = $exception->getCode();
352:         if ($errorCode >= 400 && $errorCode < 600) {
353:             $code = $errorCode;
354:         }
355: 
356:         return $code;
357:     }
358: 
359:     /**
360:      * Generate the response using the controller object.
361:      *
362:      * @param string $template The template to render.
363:      * @return \Cake\Http\Response A response object that can be sent.
364:      */
365:     protected function _outputMessage($template)
366:     {
367:         try {
368:             $this->controller->render($template);
369: 
370:             return $this->_shutdown();
371:         } catch (MissingTemplateException $e) {
372:             $attributes = $e->getAttributes();
373:             if (isset($attributes['file']) && strpos($attributes['file'], 'error500') !== false) {
374:                 return $this->_outputMessageSafe('error500');
375:             }
376: 
377:             return $this->_outputMessage('error500');
378:         } catch (MissingPluginException $e) {
379:             $attributes = $e->getAttributes();
380:             if (isset($attributes['plugin']) && $attributes['plugin'] === $this->controller->getPlugin()) {
381:                 $this->controller->setPlugin(null);
382:             }
383: 
384:             return $this->_outputMessageSafe('error500');
385:         } catch (Exception $e) {
386:             return $this->_outputMessageSafe('error500');
387:         }
388:     }
389: 
390:     /**
391:      * A safer way to render error messages, replaces all helpers, with basics
392:      * and doesn't call component methods.
393:      *
394:      * @param string $template The template to render.
395:      * @return \Cake\Http\Response A response object that can be sent.
396:      */
397:     protected function _outputMessageSafe($template)
398:     {
399:         $helpers = ['Form', 'Html'];
400:         $this->controller->helpers = $helpers;
401:         $builder = $this->controller->viewBuilder();
402:         $builder->setHelpers($helpers, false)
403:             ->setLayoutPath('')
404:             ->setTemplatePath('Error');
405:         $view = $this->controller->createView('View');
406: 
407:         $this->controller->response = $this->controller->response
408:             ->withType('html')
409:             ->withStringBody($view->render($template, 'error'));
410: 
411:         return $this->controller->response;
412:     }
413: 
414:     /**
415:      * Run the shutdown events.
416:      *
417:      * Triggers the afterFilter and afterDispatch events.
418:      *
419:      * @return \Cake\Http\Response The response to serve.
420:      */
421:     protected function _shutdown()
422:     {
423:         $this->controller->dispatchEvent('Controller.shutdown');
424:         $dispatcher = DispatcherFactory::create();
425:         $eventManager = $dispatcher->getEventManager();
426:         foreach ($dispatcher->filters() as $filter) {
427:             $eventManager->on($filter);
428:         }
429:         $args = [
430:             'request' => $this->controller->request,
431:             'response' => $this->controller->response
432:         ];
433:         $result = $dispatcher->dispatchEvent('Dispatcher.afterDispatch', $args);
434: 
435:         return $result->getData('response');
436:     }
437: 
438:     /**
439:      * Magic accessor for properties made protected.
440:      *
441:      * @param string $name Name of the attribute to get.
442:      * @return mixed
443:      */
444:     public function __get($name)
445:     {
446:         $protected = [
447:             'error',
448:             'controller',
449:             'template',
450:             'method',
451:         ];
452:         if (in_array($name, $protected, true)) {
453:             deprecationWarning(sprintf(
454:                 'ExceptionRenderer::$%s is now protected and should no longer be accessed in public context.',
455:                 $name
456:             ));
457:         }
458: 
459:         return $this->{$name};
460:     }
461: 
462:     /**
463:      * Magic setter for properties made protected.
464:      *
465:      * @param string $name Name to property.
466:      * @param mixed $value Value for property.
467:      * @return void
468:      */
469:     public function __set($name, $value)
470:     {
471:         $protected = [
472:             'error',
473:             'controller',
474:             'template',
475:             'method',
476:         ];
477:         if (in_array($name, $protected, true)) {
478:             deprecationWarning(sprintf(
479:                 'ExceptionRenderer::$%s is now protected and should no longer be accessed in public context.',
480:                 $name
481:             ));
482:         }
483: 
484:         $this->{$name} = $value;
485:     }
486: 
487:     /**
488:      * Returns an array that can be used to describe the internal state of this
489:      * object.
490:      *
491:      * @return array
492:      */
493:     public function __debugInfo()
494:     {
495:         return [
496:             'error' => $this->error,
497:             'request' => $this->request,
498:             'controller' => $this->controller,
499:             'template' => $this->template,
500:             'method' => $this->method,
501:         ];
502:     }
503: }
504: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs