annotate core/lib/Drupal/Core/EventSubscriber/HttpExceptionSubscriberBase.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 4c8ae668cc8c
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Core\EventSubscriber;
Chris@0 4
Chris@0 5 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
Chris@0 6 use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
Chris@0 7 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
Chris@0 8 use Symfony\Component\HttpKernel\KernelEvents;
Chris@0 9
Chris@0 10 /**
Chris@0 11 * Utility base class for exception subscribers.
Chris@0 12 *
Chris@0 13 * A subscriber may extend this class and implement getHandledFormats() to
Chris@0 14 * indicate which request formats it will respond to. Then implement an on*()
Chris@0 15 * method for any error code (HTTP response code) that should be handled. For
Chris@0 16 * example, to handle a specific error code like 404 Not Found messages add the
Chris@0 17 * method:
Chris@0 18 *
Chris@0 19 * @code
Chris@0 20 * public function on404(GetResponseForExceptionEvent $event) {}
Chris@0 21 * @endcode
Chris@0 22 *
Chris@0 23 * To implement a fallback for the entire 4xx class of codes, implement the
Chris@0 24 * method:
Chris@0 25 *
Chris@0 26 * @code
Chris@0 27 * public function on4xx(GetResponseForExceptionEvent $event) {}
Chris@0 28 * @endcode
Chris@0 29 *
Chris@0 30 * That method should then call $event->setResponse() to set the response object
Chris@0 31 * for the exception. Alternatively, it may opt not to do so and then other
Chris@0 32 * listeners will have the opportunity to handle the exception.
Chris@0 33 *
Chris@0 34 * Note: Core provides several important exception listeners by default. In most
Chris@0 35 * cases, setting the priority of a contrib listener to the default of 0 will
Chris@0 36 * do what you expect and handle the exceptions you'd expect it to handle.
Chris@0 37 * If a custom priority is set, be aware of the following core-registered
Chris@0 38 * listeners.
Chris@0 39 *
Chris@0 40 * - Fast404ExceptionHtmlSubscriber: 200. This subscriber will return a
Chris@0 41 * minimalist, high-performance 404 page for HTML requests. It is not
Chris@0 42 * recommended to have a priority higher than this one as it will only slow
Chris@0 43 * down that use case.
Chris@0 44 * - ExceptionLoggingSubscriber: 50. This subscriber logs all exceptions but
Chris@0 45 * does not handle them. Do not register a listener with a higher priority
Chris@0 46 * unless you want exceptions to not get logged, which makes debugging more
Chris@0 47 * difficult.
Chris@0 48 * - DefaultExceptionSubscriber: -256. The subscriber of last resort, this will
Chris@0 49 * provide generic handling for any exception. A listener with a lower
Chris@0 50 * priority will never get called.
Chris@0 51 *
Chris@0 52 * All other core-provided exception handlers have negative priorities so most
Chris@0 53 * module-provided listeners will naturally take precedence over them.
Chris@0 54 */
Chris@0 55 abstract class HttpExceptionSubscriberBase implements EventSubscriberInterface {
Chris@0 56
Chris@0 57 /**
Chris@0 58 * Specifies the request formats this subscriber will respond to.
Chris@0 59 *
Chris@0 60 * @return array
Chris@0 61 * An indexed array of the format machine names that this subscriber will
Chris@0 62 * attempt to process, such as "html" or "json". Returning an empty array
Chris@0 63 * will apply to all formats.
Chris@0 64 *
Chris@0 65 * @see \Symfony\Component\HttpFoundation\Request
Chris@0 66 */
Chris@0 67 abstract protected function getHandledFormats();
Chris@0 68
Chris@0 69 /**
Chris@0 70 * Specifies the priority of all listeners in this class.
Chris@0 71 *
Chris@0 72 * The default priority is 1, which is very low. To have listeners that have
Chris@0 73 * a "first attempt" at handling exceptions return a higher priority.
Chris@0 74 *
Chris@0 75 * @return int
Chris@0 76 * The event priority of this subscriber.
Chris@0 77 */
Chris@0 78 protected static function getPriority() {
Chris@0 79 return 0;
Chris@0 80 }
Chris@0 81
Chris@0 82 /**
Chris@0 83 * Handles errors for this subscriber.
Chris@0 84 *
Chris@0 85 * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
Chris@0 86 * The event to process.
Chris@0 87 */
Chris@0 88 public function onException(GetResponseForExceptionEvent $event) {
Chris@0 89 $exception = $event->getException();
Chris@0 90
Chris@0 91 // Make the exception available for example when rendering a block.
Chris@0 92 $request = $event->getRequest();
Chris@0 93 $request->attributes->set('exception', $exception);
Chris@0 94
Chris@0 95 $handled_formats = $this->getHandledFormats();
Chris@0 96
Chris@0 97 $format = $request->query->get(MainContentViewSubscriber::WRAPPER_FORMAT, $request->getRequestFormat());
Chris@0 98
Chris@0 99 if ($exception instanceof HttpExceptionInterface && (empty($handled_formats) || in_array($format, $handled_formats))) {
Chris@0 100 $method = 'on' . $exception->getStatusCode();
Chris@0 101 // Keep just the leading number of the status code to produce either a
Chris@0 102 // on400 or a 500 method callback.
Chris@0 103 $method_fallback = 'on' . substr($exception->getStatusCode(), 0, 1) . 'xx';
Chris@0 104 // We want to allow the method to be called and still not set a response
Chris@0 105 // if it has additional filtering logic to determine when it will apply.
Chris@0 106 // It is therefore the method's responsibility to set the response on the
Chris@0 107 // event if appropriate.
Chris@0 108 if (method_exists($this, $method)) {
Chris@0 109 $this->$method($event);
Chris@0 110 }
Chris@0 111 elseif (method_exists($this, $method_fallback)) {
Chris@0 112 $this->$method_fallback($event);
Chris@0 113 }
Chris@0 114 }
Chris@0 115 }
Chris@0 116
Chris@0 117 /**
Chris@0 118 * Registers the methods in this class that should be listeners.
Chris@0 119 *
Chris@0 120 * @return array
Chris@0 121 * An array of event listener definitions.
Chris@0 122 */
Chris@0 123 public static function getSubscribedEvents() {
Chris@0 124 $events[KernelEvents::EXCEPTION][] = ['onException', static::getPriority()];
Chris@0 125 return $events;
Chris@0 126 }
Chris@0 127
Chris@0 128 }