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:
- If we have a multilingual instance,
\Drupal\language\EventSubscriber\LanguageRequestSubscriber is registered.
- This will call
\Drupal\language\ConfigurableLanguageManager::getCurrentLanguage to get the interface language
with admin language negotiation.
- 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.
- Since the source path we're using does match to an entity route pattern (
/node/{node}), Drupal tries to apply parameter converters.
- This will result in a
ParamNotConvertedException (obviously, because we don't have a node with ID 123).
- So in
Symfony\Component\HttpKernel::handle(), we will end at handleThrowable(),
- Which will then invoke
Drupal\Core\EventSubscriber\DefaultExceptionHtmlSubscriber::on404() (core service: exception.default_html)
- 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.
- 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
- Install Drupal with at least two configurable language, with
node and redirect modules.
- Enable Account administration pages language negotiator, and make it the first evaluated plugin.
- Add a Redirect which redirects from
node/123 to e.g. /filter/tips.
- 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.)
- 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.