4

I'm trying to issue a 404 from a KernelEvents::REQUEST event, but it's resulting in the following error:

Fatal error: Maximum function nesting level of '256' reached, aborting! in /var/www/vendor/symfony/http-foundation/HeaderBag.php on line 162

Here's my class

<?php

namespace Drupal\my_module\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelEvents;

class MyClass implements EventSubscriberInterface {

  /**
   * {@inheritdoc}
   */
  static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = ['my404Check'];

    return $events;
  }

  public function my404Check(GetResponseEvent $event) {
    // Do some logic here to check if it should be a 404.
    throw new NotFoundHttpException();
  }

}

I'm guessing I can't throw exceptions here, but can't see any other documentation on how to issue the 404.

4

You can set a response early in a request event:

 public function my404Check(GetResponseEvent $event) {

    // only return a response for a master request
    if (!$event->isMasterRequest()) {
      return;
    }

    // Do some logic here to check if it should be a 404.

    $response = new Response('', Response::HTTP_NOT_FOUND);
    $event->setResponse($response);
  }

The event dispatcher checks if a response is already set and returns this response without executing any more code to build a Drupal response.

3
  • It might be worth noting that this approach won't invoke the theme handlers. i.e. Symfony (and Drupal)'s default 404 page handling will be bypassed, you'll literally get a fast 404 style blank white page. The "right" way to do it seems to involve only throwing an exception when if ($event->isMasterRequest()) { gives true per stackoverflow.com/questions/30617347/…
    – Clive
    Mar 30 '17 at 12:38
  • @Clive, good point, I'll add the check for the master request.
    – 4k4
    Mar 30 '17 at 12:48
  • Great, $event->isMasterRequest() was the trick I needed. Still seems to work with throw new NotFoundHttpException();
    – leon.nk
    Mar 30 '17 at 13:04
0

I know this is old, but in case someone else finds this... setting the response was not enough for me, I still ended up with the same 'fast 404' error page, even when checking for the master request (I cleared cache). I also would prefer to simply throw the NotFoundHttpException like anywhere else in my code rather than create the response manually.

With this approach, I simply 'transform' the exception I'm catching from the event into a the NotFoundHttpException. Note that I use a priority higher than core's ExceptionLoggingSubscriber to avoid double logging of the exception.

  /**
   * {@inheritdoc}
   *
   * Use priority > 50 to run before core's ExceptionLoggingSubscriber.
   */
  public static function getSubscribedEvents() {
    $events[KernelEvents::EXCEPTION][] = ['onException', 60];
    return $events;
  }

  /**
   * Return a 404.
   *
   * @param GetResponseForExceptionEvent $event
   */
  public function onException(GetResponseForExceptionEvent $event) {
    $e = $event->getException();
    if ({{CUSTOM LOGIC HERE}}) {
      $new_exception = new NotFoundHttpException($e->getMessage());
      $event->setException($new_exception);
    }
  }
0

I would like to post another solution, that I have found in the Rabbit Hole module:

public function my404Check(GetResponseEvent $event) {
  // Don't process events with HTTP exceptions - those have either been thrown
  // by us or have nothing to do with this module.
  if ($event->getRequest()->get('exception') != NULL) {
    return;
  }

  // Do some logic here to check if it should be a 404.

  $response = new Response('', Response::HTTP_NOT_FOUND);
  $event->setResponse($response);
}

The event dispatcher skips processing if request has an exception already. In addition you can check the exception type.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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