Problem/Motivation
If you add a language-unspecified alias for a page that already has an alias in the default language, the language-unspecified alias will sporadically appear around the site.
Steps to reproduce
use Drupal\Core\Language\LanguageInterface;
// Generate paths to test with.
$source = '/' . uniqid('alias_test');
$base = '/' . uniqid('alias_test') . '_';
/** @var \Drupal\Core\Path\AliasStorageInterface $storage */
$storage = \Drupal::service('path.alias_storage');
// Save a couple of aliases.
$storage->save($source, $base . 'en', 'en');
$storage->save($source, $base . 'und', LanguageInterface::LANGCODE_NOT_SPECIFIED);
// Search for an individual alias. Should find the en alias we added above.
$found_one = $storage->lookupPathAlias($source, 'en');
print "$found_one\n";
// Search for multiple aliases. Should also find the en alias from above.
$found_multi = $storage->preloadPathAlias([$source], 'en');
print "$found_multi[$source]\n";
// Woops, it found the und alias instead!
// Cleanup.
$storage->delete(['source' => $source]);
Proposed resolution
Change the sort order of the query prepared in \Drupal\path_alias\AliasRepository::preloadPathAlias
so that the in:: addLanguageFallback
applies its sorts in the correct order too.
This will also require changing slightly how the results are fetched from the query by this method.
Fix is in
MR 5250
All others MRs can be closed
Remaining tasks
None that I'm aware of.
User interface changes
URL paths should now be consistent, rather than depend on the unpredictable nature of what methods were called first, what was cached etc. So this might introduce some change for path aliases on some sites, but should do so in a consistent way, fixing the essentially non-deterministic way it was working before.
API changes
None.
Data model changes
None
Comment | File | Size | Author |
---|
Issue fork drupal-2745755
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
vasi CreditAttribution: vasi at Evolving Web commentedIt looks like we don't have any tests for preloadPathAlias, so I wrote some. These fail, for two reasons:
Comment #3
vasi CreditAttribution: vasi at Evolving Web commentedComment #4
vasi CreditAttribution: vasi at Evolving Web commentedHere's a patch that gets the new tests passing. I think it was just a swapped greater-than sign.
Comment #8
vasi CreditAttribution: vasi at Evolving Web commentedIn addition to just making links sometimes look wrong, this is currently breaking blocks on our site. The request_path block condition ends up comparing against the und path instead of the language-specific path, which is not expected.
Comment #9
vasi CreditAttribution: vasi at Evolving Web commentedFixed the comment so it correctly explains the new code.
Comment #10
mvcIn particular, the behaviour now will be unexpected if url_alias.source is the same for two paths, which is a legitimate thing to do on multilingual sites.
This looks good except that calling
if (!empty($preloaded))
is redundant after addingempty($preloaded)
above for performance.Comment #11
mvcFixing status
Comment #12
vasi CreditAttribution: vasi at Evolving Web commentedOn reflection, Drupal's current behaviour when $preloaded is empty is not relevant to this issue. It was unexpected to me that it would return all paths, but that's not entirely crazy, so I backed out that part of my patch, and adjusted the tests to match. I also added to the phpDoc so that the behaviour is specified, and others won't be surprised.
Comment #13
vasi CreditAttribution: vasi at Evolving Web commentedComment #14
mvcComment #15
Wim LeersThis is modifying
AliasStorage
.This is expanding the functional test coverage.
\Drupal\KernelTests\Core\Path\AliasStorageTest
.Comment #16
vasi CreditAttribution: vasi at Evolving Web commentedThanks! Added a pretty extensive test.
Comment #17
Wim LeersImpressive!
Comment #18
Gábor HojtsyDiscussed this at Baltimore. We figured that changing the order does not only change the result order of the specific vs. general alias but also the preferred alias if there are multiple aliases for the same path. So this could result in a backwards incompatible change (other than for the bug being fixed).
Comment #19
vasi CreditAttribution: vasi at Evolving Web commentedAfter some thought, I've realized doesn't change the preferred alias if there are multiple aliases for the same path. We have
$select->orderBy('pid', 'ASC');
, so the latest-added alias in the appropriate language will always be preferred, both with and without this patch.Added some test data to show that this is the case.
Comment #26
efrainhThe patch on #19 was already merged:
When upgrading from 8.7.6 to 8.8 I got this message:
https://www.drupal.org/files/issues/2745755-19.patch (AliasStorage::preloadPathAlias() incorrectly prioritizes UND aliases; https://www.drupal.org/project/drupal/issues/2745755)
Could not apply patch! Skipping. The error was: Cannot apply patch https://www.drupal.org/files/issues/2745755-19.patch
Reviewing the code it already contains the patch so we don't need this patch in 8.8!!.
Comment #27
james.williams CreditAttribution: james.williams at ComputerMinds commented@efrainh no, the changes in the latest patch is not already in Drupal core, the patch just doesn't apply any more because the affected files changed. There is now a
Drupal\Core\Path\AliasStorage::addLanguageFallback()
method in D8.8, which is where the change would be needed instead. In D9.1 though, that class has been almost completely gutted, and the fallback change would need applying toDrupal\path_alias\AliasRepository::addLanguageFallback()
. The tests would no doubt need changing up accordingly too.So I'm adding the re-roll tag too, but I suspect this will not be a trivial re-roll.
Comment #28
james.williams CreditAttribution: james.williams at ComputerMinds commentedAs Gábor pointed out, this change might fix a bug, but would be a BC break. So I think it now has to wait for D10 :-/
Comment #29
Steven Jones CreditAttribution: Steven Jones as a volunteer commentedComing here from #3135440 where language hierarchy needs to solve basically the same problem/bug that core has, but for multiple languages instead of two.
Moving the target version to 11, and will open a issue fork to work on this.
Comment #30
Steven Jones CreditAttribution: Steven Jones as a volunteer commentedSo as mentioned in #27 the code has moved on a bit, so I've focused on bringing over the tests from #16 that tested out
\Drupal\path_alias\AliasRepository::preloadPathAlias
.And then I've implemented a fix.
The real problem here is that preloadPathAlias processes the result set and prefers aliases at the end, whereas all the other methods use the first row in the result set.
This is explained when setting the sort order of the
base_table.id
field:But this change in ordering is never made in
addLanguageFallback
so I've introduced a badly named parameter that'll reverse the ordering when appropriate.Comment #32
Steven Jones CreditAttribution: Steven Jones as a volunteer commentedComment #33
Steven Jones CreditAttribution: Steven Jones as a volunteer commented...and I've just read that I'm supposed to be using patches, unless I explain why I'd like to change over to MRs:
It's been 7 years since the last patch, and the world has moved on, MRs are more/faster/better. Hope that's enough!
Comment #34
Steven Jones CreditAttribution: Steven Jones as a volunteer commentedThere we go, as expected the MR tests pass, but the tests-only version fails.
Comment #35
smustgrave CreditAttribution: smustgrave at Mobomo commentedThanks for reviving this one. Think we will need a change record for the new parameter, examples are always good too in the CR.
Searching http://grep.xnddx.ru/search?text=addLanguageFallback&filename=
https://www.drupal.org/project/variants or https://www.drupal.org/project/language_hierarchy may be doing something with this. Lightly took a look.
Comment #36
Steven Jones CreditAttribution: Steven Jones as a volunteer commented@smustgrave thanks, do you happen to have an example of a CR for documenting adding a new parameter to a protected method?
As for language hierarchy, yes, we're all over this in #3135440: LH limits to 1 alias when preloading multiple aliases :)
Comment #37
smustgrave CreditAttribution: smustgrave at Mobomo commentedThis is a pretty basic one https://www.drupal.org/node/3372008
Comment #38
Steven Jones CreditAttribution: Steven Jones as a volunteer commentedI was writing out the change notice, when I thought that actually this all seems really ugly: that for one method that wants the results in a different order we need to thread this parameter around etc. Seems a lot like tail wagging the dog.
Then I realised that it was only because
preloadPathAlias
wants to usefetchAllKeyed
that we need to do this at all.If this method does a fraction more work, then everything can be nice and consistent and actually all the queries generated by the
\Drupal\path_alias\AliasRepository
class can actually have the same order by clauses, meaning that everything is consistent and easier to reason about anyway.So...I've added that approach to the MR, which now means there's no API change.
I'm also not sure if I agree with @Gábor Hojtsy in #18 that this change is now* a BC break, since, at the moment, depending on your configuration results are simply inconsistent. If
preloadPathAlias
is called, you'll get one set of aliases, but if you were to calllookupBySystemPath
then you might get a different one for the same set of data.Core has no control over the order and use of these functions really, so I don't think you can consider this weird bug a feature that can't be fixed in a minor or even patch release.
*: Also when @Gábor Hojtsy wrote #18 the patch on this issue was essentially inverting the sort to shift the problem to the methods that only seek to return on alias, so yeah, that would have been the same bug, but a different presentation.
Setting this back to Needs review to get some more feedback on this change of tack.
Comment #39
smustgrave CreditAttribution: smustgrave at Mobomo commentedNot sure I can speak on it but if a new solution is taken the issue summary will need ot be updated to reflect that.
Comment #40
Steven Jones CreditAttribution: Steven Jones as a volunteer commentedComment #41
smustgrave CreditAttribution: smustgrave at Mobomo commentedSo circled back to this one
Test-only feature shows the issue.
Hiding patches as fix is in MR, also highlighted it in the IS.
Looking at the change itself nothing seems glaring so going to mark it.
Comment #44
catchCommitted/pushed to 11.x and cherry-picked to 10.2.x, thanks!
I deleted the change record because it was for a different approach to the final one.