Problem/Motivation
After one of the nodes was deleted, in a custom rest resource I tried to get the alias of the node from PathAliasManager::getAliasByPath(), but it returns with the internal path. I'am sure that the alias of the node was available, so I tried to find out the cause of the error.
Proposed resolution
I have found the related code at line 224 in PathAliasManager.
It has to be replaced from:
$this->noAlias[$langcode] = array_flip(array_diff_key($this->preloadedPathLookups[$langcode], array_keys($this->lookupMap[$langcode])));
to:
$this->noAlias[$langcode] = array_flip(array_diff($this->preloadedPathLookups[$langcode], array_keys($this->lookupMap[$langcode])));
because the preloadedPathLookups is an indexed array what contains paths as values, but the lookupMap contains paths as keys, and the array_keys() converts it to values and the new keys will be indexes, therefore the array_diff_key() always returns with the last value(s) of the preloadedPathLookups instead of really missing alias(es).
Comments
Comment #2
pauger commentedComment #3
pauger commentedComment #4
pauger commentedComment #6
albertosilvaConfirmed that this issue is returning the wrong internal path instead of its alias, even thought its alias is present. Also confirmed that using
array_diff_keyis incorrect and should bearray_diff.Applying the provided patch fixes it with no other side effect.
Comment #7
cilefen commentedThis needs regression test coverage.
Comment #8
albertosilvaAdding a test that should fail with current implementation that is wrongly using
array_diff_keyinstead ofarray_diff(please note that this test failing is the expected behavior).Current test for
Drupal\Tests\path_alias\Unit\AliasManagerTest::testGetAliasByPathCachedMatch()searches for a given path inside an array of cached paths. That cached array only contains one item (and the path we are searching for is in the first position), soarray_diff_keyworks by simple coincidence of positions in the array.This patch modifies that test so the cached array contains more that one item, and the path we are searching for is NOT in the first position. This makes
array_diff_keyfails because it is wrongly using the array key instead of its value.If this patch fails (the expected behavior), I'll send another patch with both the test and its fix, to confirm the problem is fixed.
Comment #9
albertosilvaAs expected, test from #8 failed, so I am posting again the same test along its fix. This patch is expected to pass as it fixes the problem.
Comment #10
albertosilvaRegression test coverage added.
Comment #11
albertosilvaMaking issue unassigned so it can be reviewed.
Comment #13
k3vin_nl commentedWe also experienced this issue, and I can confirm that the proposed change fixes the issue in our case.
Comment #15
krisahil commentedThis patch fixes another set of symptoms. I confirm this on Drupal 10.0.1. Here are the steps to reproduce the problem that the patch in #9 fixes:
After updating the second node for the second time, notice that you land on URL path /node/2. This seems to be a bug. You should have been sent to this node's alias. In fact, the "View" tab links to the aliased path.
The problem seems to be caused by the un-aliased paths cache in
\Drupal\path_alias\AliasManager::getAliasByPath.However, the patch in comment #9 fixes this on Drupal 10.
Comment #16
albertosilvaI've retested patches from #8 and #9 with Drupal 9.5, 10 and 10.1. All patches work as expected (#8 should fail, while #9 should pass).
Hence, I'm marking this as RTBC thanks to feedback from #13 and #15
Comment #17
xjm@albertosilva, in general, you should not RTBC your own patch. While others' manual testing can help confirm your fix is valid, it is not the same as a code review of the patch.
I suggest checking out the
#needs-review-queuechannel in the Drupal community Slack if you have an issue that's been waiting for a code review for a very long time.So we are essentially using
array_diff_key()when onlyarray_diff()should be used. This is one of those issues that makes me ask, "Why is it this way in the first place?" Are the array keys important? Were they ever? So, I checked.Finding out why
array_diff_key()was ever used.This led me to:
#3092090: Remove legacy Path Alias subsystem
In that issue, the key line is just moved from one namespace to another. So, back further we go:
Rinse and repeat until I finally get back to:
In that original issue, the first prototype had:
...and it sort of kept on in the issue from there.
Caching with
$system_pathslater introduced and was set to the cache with:So they both had integer keys at that point, and it continued to mostly work by accident
Also make note of comment #36 on that issue:
:)
Back to 10.1.x
TLDR, the issue summary explains why this is wrong; we want to compare path values to path values regardless of integer index keys. The IS explains why it's definitely a bug now, and the test coverage proves it.
I could mark this RTBC based on my own review, but then I couldn't commit it, so reaching out to the
#need-review-queuechannel for a peer code review.Comment #18
xjmTagging for a followup to better document the array structures of the various protected properties in the class.
Comment #19
xjmComment #20
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #need-reveiw-queue. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge require as a guide.
Ran just the test case from #9 without the fix and got
All green with the fix as we can see.
Thanks to @xjm for deep investigative work it appears changing this is the correct solution all along.
Opened https://www.drupal.org/project/drupal/issues/3331889 as the follow up
Comment #21
xjmOh! One very small thing I was reminded of based on @smustgrave's test result there.
Instead of
randomMachineName(), we should use a static value. There's a small chance the random machine name could end up being the same as the path if other parts of the test are refactored, or it could lead to other regressions. I'd suggest something self-explanatory like:/another/pathComment #22
albertosilva@xjm thanks for the investigative work, and sorry for marking it RTBC. The original patch was provided by @pauger, to which I later added the missing test. My intent was to validate @pauger's solution, not mine. Lesson learned.
I've fixed the test, removing the
randomMachineNameyou mentioned, replacing it with/another/pathComment #23
smustgrave commentedMoving back to RTBC with the update.
Comment #27
xjmJust a note @albertosilva for future reference, you should always provide an interdiff when you upload a changed patch to an issue:
https://www.drupal.org/docs/develop/git/using-git-to-contribute-to-drupa...
(Only necessary when using patches, not with merge requests.)
In this case the patch is small enough that I can easily see what was changed, so I went ahead with reviewing it anyway. :) Committed to 10.1.x, and cherry-picked to 10.0.x and 9.5.x as a patch-eligible, non-disruptive bugfix. Thanks!
Comment #28
larowlanRemoving duplicate tag.
Code makes sense and archeology from xjm helps understand that this has always been a bug.
Comment #29
xjmComment #30
xjmComment #31
smustgrave commentedconfused thought I did open the follow up?
Comment #32
xjm@smustgrave You did; @larowlan and I just had a bit of a cross-post-a-thon. :)