Apply matching redirect even on KernelEvents::EXCEPTION

Created on 27 May 2023, about 1 year ago
Updated 13 September 2023, 10 months ago

I am hesitating between qualifying this as a minor bug or as a feature request...

Problem/Motivation

The site we're migrating from Drupal 7 used Polls + Advanced Polls. In Drupal 7, polls are nodes with a specific type, but in Drupal 8+, polls have their own entity type, so the poll which was available at path /node/123 will be avaliable at /poll/123.

We don't want to migrate a "placeholder" node for these changed routes - our intent is migrating a redirect entity which redirects any request made to /node/123 to /poll/123.

The problem is that this is not possible right now on certain conditions. We are able to properly save a new redirect entity, our issue is with admin language negotiator and how Drupal's kernel handles these routes:

  1. If we have a multilingual instance, \Drupal\language\EventSubscriber\LanguageRequestSubscriber is registered.

  2. This will call \Drupal\language\ConfigurableLanguageManager::getCurrentLanguage to get the interface language with admin language negotiation.

  3. When LanguageNegotiationUserAdmin tries to determine if the current route is an admin route in ::isAdminPath(), it tries to match the URL to the route collection, which then invokes e.g. parameter converters.

  4. Since the source path we're using does match to an entity route pattern (/node/{node}), Drupal tries to apply parameter converters.

  5. This will result in a ParamNotConvertedException (obviously, because we don't have a node with ID 123).

  6. So in Symfony\Component\HttpKernel::handle(), we will end at handleThrowable(),

  7. Which will then invoke Drupal\Core\EventSubscriber\DefaultExceptionHtmlSubscriber::on404() (core service: exception.default_html)

  8. When DefaultExceptionHtmlSubscriber instantiates the 404 sub-request in makeSubrequest, the place where it calls
    $parameters->add($this->redirectDestination->getAsArray() + ['_exception_statuscode' => $status_code]);
    

    ,it will also add a destination query to the subrequest.

  9. This subrequest is the thing that reaches RedirectRequestSubscriber::onKernelRequestCheckRedirect, but since this request contains a destination query (of course we won't see it because this is not the master request), RedirectChecker::canRedirect() will return FALSE, so the redirect we have won't be applied.

Steps to reproduce

  1. Install Drupal with at least two configurable language, with node and redirect modules.
  2. Enable Account administration pages language negotiator, and make it the first evaluated plugin.
  3. Add a Redirect which redirects from node/123 to e.g. /filter/tips.
  4. Create a user with access administration pages and access content permissions, and set and explicit admin language on the user profile's edit form. (The "default" root user also works.)
  5. Try to open the patch /node/123 with this user being logged in.

Expected result: User is redirected to /filter/tips.

Actual result: User gets a 404 response.

Proposed resolution

Subscribe to KernelEvents::EXCEPTION too with RedirectRequestSubscriber, and apply the same logic as it has right now for KernelEvents::REQUEST if the exception in the event is a NotFoundHttpException.

Remaining tasks

TDB.

User interface changes

Nothing.

API changes

RedirectRequestSubscriber also subscribes to KernelEvents::EXCEPTION and tries to apply redirects.

Data model changes

Nothing.

✨ Feature request
Status

Needs review

Version

1.0

Component

Code

Created by

🇭🇺Hungary huzooka Hungary 🇭🇺🇪🇺

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.69.0 2024