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.7 Red Velvet API

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