1

I'm currently using an Event Subscriber to catch exceptions and return a plain-text message response to the user (instead of the default white screen of death).

Is there a way to return a templated response (using the site's theme, similar to a Controller's response) from the event subscriber in Drupal 9/10?

4
  • There was a method for this in D7, but it was broken between D7 and D8, and has still not been repaired. You can use the patch from this issue however: drupal.org/project/drupal/issues/2720109
    – Jaypan
    Jan 13, 2023 at 18:16
  • This issue is about the Drupal 7 perspective on fatal errors. Catching an exception in an Symfony event subscriber is not a fatal error and you are in full control to set an HTML response instead of a plain-text message.
    – 4uk4
    Jan 13, 2023 at 19:36
  • Well, the D7 functionality in core was not properly upgraded to D8 (and still hasn't been). It's a core API that is meant to handle this issue.
    – Jaypan
    Jan 13, 2023 at 19:52
  • This is not the only API change because of Symfony. I find the Symfony exception handling far more capable. Core provides HTML exception subscribers for 4xx exceptions and fall backs to plain text error messages in case of 5xx exceptions. It would be no problem to add a custom event subscribers (what the OP is trying to do) to catch 5xx exceptions and set an HTML response.
    – 4uk4
    Jan 14, 2023 at 10:45

1 Answer 1

2

This depends on the exceptions you want to catch.

Example for 5xx HTTP exceptions:

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\EventSubscriber\DefaultExceptionHtmlSubscriber;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

/**
 * Exception subscriber for handling 5xx exceptions
 */
class MymoduleExceptionSubscriber extends DefaultExceptionHtmlSubscriber {

  protected static function getPriority() {
    return -129;
  }

  protected function getHandledFormats() {
    return ['html'];
  }

  /**
   * Handles a 5xx error for HTML.
   *
   * @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
   *   The event to process.
   */
  public function on5xx(ExceptionEvent $event) {
    if (($exception = $event->getThrowable()) && $exception instanceof HttpExceptionInterface) {
      $this->makeSubrequest($event, '/my5xxcontroller', $exception->getStatusCode());
    }
  }

}

Example for all exceptions (only for demonstration purpose, better check for the exceptions you want to catch):

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\EventSubscriber\DefaultExceptionHtmlSubscriber;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

/**
 * Exception subscriber for handling all exceptions
 */
class MymoduleExceptionSubscriber extends DefaultExceptionHtmlSubscriber {

  protected static function getPriority() {
    return -129;
  }

  protected function getHandledFormats() {
    return ['html'];
  }

  /**
   * Handles all exceptions for HTML
   *
   * @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
   *   The event to process.
   */
  public function onException(ExceptionEvent $event) {
    $request = $event->getRequest();
    $handled_formats = $this->getHandledFormats();
    $format = $request->query->get(MainContentViewSubscriber::WRAPPER_FORMAT, $request->getRequestFormat());
    if (empty($handled_formats) || in_array($format, $handled_formats)) {
      $this->makeSubrequest($event, '/my5xxcontroller', 500);
    }
  }

}

mymodule.services.yml

services:
  mymodule.5xx_subscriber:
    class: Drupal\mymodule\EventSubscriber\MymoduleExceptionSubscriber
    tags:
      - { name: event_subscriber }
    arguments: ['@http_kernel', '@logger.channel.php', '@redirect.destination', '@router.no_access_checks']

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.