Problem/Motivation
When you are using URL aliases (module path_alias
) on nodes and then try to build a URL object via Drupal\Core\Url::fromUri('internal:/language-prefix/your-alias')
it will not create the correct URL object if the alias belongs to a language that is different from the language of the current page request.
There are several components involved, which is making it hard for me to tell which component is having the issue. It is more like the interaction of the components seems to be problematic while each part on its own is working as intended.
The call stack will look something like this:
Drupal\Core\Url::fromUri()
Drupal\Core\Url::fromInternalUri()
Drupal\Core\Path\PathValidator::getUrlIfValidWithoutAccessCheck()
Drupal\Core\Path\PathValidator::getUrl()
Drupal\Core\Path\PathValidator::getPathAttributes()
Drupal\Core\PathProcessor\PathProcessorManager::processInbound()
There are two path processors that may be relevant in this scenario.
The processor method Drupal\language\HttpKernal\PathProcessorLanguage::processInbound()
is removing the language prefix from the given path. It has to do it so that following path processors get the original path without the language prefix, however, this is the point where the intended language for the alias gets lost.
The processor method Drupal\path_alias\PathProcessor\AliasPathProcessor::processInbound()
should actually find the correct route by calling Drupal\path_alias\AliasManager::getPathByAlias()
, but it does not provide a language in which the alias should be searched for and the AliasManager
will therefore fall back to the language of the given request.
The URL alias will not be found. The URL object will be unrouted.
As a side note: The method Url::fromUri()
does have a second argument $options
in which we can provide a language, however, that language is not passed to the path processors. So even if we knew the language of the alias in advance (which we don't in this scenario), the alias would still not be recognised correctly. The resulting URL object would have the correct language set, but it would still be unrouted.
Steps to reproduce
Have a Drupal system with languages English (default, no path prefix) and German (path prefix "de").
Have a node with translations in English and German. English URL alias: "foo/bar". German URL alias: "de-foo/de-bar".
The URLs would be /foo/bar
and /de/de-foo/de-bar
.
Load any page in English (without language path prefix) and during the request execute the following code:
\Drupal\Code\Url::fromUri('internal:/de/de-foo/de-bar');
The resulting URL object is marked as unrouted.
As described before, the following code will not produce the correct result either:
\Drupal\Code\Url::fromUri('internal:/de/de-foo/de-bar', ['language' => \Drupal::languageManager->getLanguage('de')]);
Now load any page in German (language path prefix "de") and execute the same code. The resulting URL object will be correct.
Proposed resolution
I guess the best way to approach this issue would be to update Drupal\Core\Path\PathValidator
(getUrl()
or getPathAttributes()
). I am not sure if all languages should be used to find the correct alias record. The language is already encoded in the given path "/de/". However, there may also be fallback languages involved.
To be honest, I am not even sure if this is an actual bug or if the method Url::fromUri()
should just not be used like that. I know at least one module (trailing_slash
) that is using it in this way and it fails to perform its actions properly because of that.
Another way to deal with the issue would probably be to let the method Url::fromUri()
pass the given language (from its options) to the path validator (and to its path processors) so that the AliasPathProcessor
knows in which language the alias should be searched for. The problem of having to know the language in advance would remain, but I can see that this is just the overall limit of this function.
Please let me know your thoughts on this. Should the method Url::fromUri()
just not be used like that? Or is it a valid use-case and therefore a bug?