Problem/Motivation
STR:
- When a node is in a the middle of a book hierarchy
- Visit one if it's child pages and observe the breadcrumb.
- Then edit the node and change the title.
- Visit the child page again and see the breadcrumb still has the old title.
In addition, it seems likely that if there is some custom node access scheme, the breadcrumb would be cached and could be shown to users that don't have access.
Proposed resolution
In \Drupal\book\BookBreadcrumbBuilder::build
For each node loaded call $breadcrumb->addCacheableDependency()
For the access call, set $return_as_object to TRUE and apply it also using $breadcrumb->addCacheableDependency()
Remaining tasks
write patch
write tests
User interface changes
n/a
API changes
n/a
Data model changes
n/a
Comment | File | Size | Author |
---|---|---|---|
#40 | 2665410.patch | 11.21 KB | catch |
#40 | interdiff.txt | 879 bytes | catch |
#32 | 2665410.patch | 10.98 KB | catch |
#30 | 2665410.patch | 2.07 MB | catch |
| |||
#30 | interdiff.txt | 879 bytes | catch |
Comments
Comment #2
pwolanin CreditAttribution: pwolanin as a volunteer and at Acquia commentedQuick patch. NR for bot. Needs testing.
Comment #3
jibranIs this critical because of this?
Comment #4
pwolanin CreditAttribution: pwolanin as a volunteer and at Acquia commented@jibran - yes, that's why I marked it critical, but maintainers may, of course, triage it to lower.
Comment #5
Wim LeersComment #6
Wim LeersPatch looks good.
Comment #7
Wim LeersNW for tests.
Comment #8
pwolanin CreditAttribution: pwolanin as a volunteer commentedHere' some initial work on a test-only patch to show the bugs - should fail.
Comment #10
Wim LeersTest coverage looks good. Just nits for it. Upon fixing the nits & merging #2, this is RTBC as far as I'm concerned.
Super nit: missing trailing asterisk.
Nit:
[]
Nit: needs newline in between.
Comment #11
pwolanin CreditAttribution: pwolanin as a volunteer commented@Wim Leers - I think maybe we should test changes to the access result also? Any examples you know for that?
Comment #12
Wim Leers#2485683: REST entity resource missing entity & field access cacheability metadata is an example of such a test, that just went in.
Comment #13
pwolanin CreditAttribution: pwolanin as a volunteer commentedSo, am I missing somethign - seems like the access result cache tags are not being propagated?
Test-only is the interdiff to #2
Comment #14
pwolanin CreditAttribution: pwolanin as a volunteer commentedComment #17
Wim LeersI don't see any cache tag assertions in #13/#14.
Comment #18
pwolanin CreditAttribution: pwolanin as a volunteer commented@Wim Leers - in the module hook I'm doing:
$access->addCacheableDependency($config);
Changing that config makes the access check return denied. The last test line verifies the node page itself is a 403. But just before that, the denied node title is still found in the breadcrumb after the config is changed.
Comment #19
catchSince the access depends on the node title shouldn't this add the $node as a cacheable dependency too?
Comment #20
pwolanin CreditAttribution: pwolanin as a volunteer commentedThe node is already added as a cacheable dependency in the patch. That's the fix the 1st test verifies.
The variables just are named badly:
Though possibly we should add that as a cacheable dependency even if access is not allowed?
Comment #21
davidhernandezJust confirming the patch in #13 works while manually testing.
Comment #22
catchYes it needs to be a dependency either way.
Comment #23
Wim LeersYes.
But it's already doing that:
Unless I'm overlooking some code? Or some other code in book module is short-circuiting this incorrectly?
Comment #24
pwolanin CreditAttribution: pwolanin as a volunteer commented@Wim Leers - the question was about adding all the nodes as cacheable dependencies, or just the ones with allowed access, though a proper implementation of hook_node_access or hook_entity_access should already be doing that if the access is per node.
Comment #25
Wim LeersOops, I misread. Yes, the access result's cacheability metadata should already include the information it depends on, so that would indicate a bug in the access check logic involved there.
Comment #26
catchThe test implementation only sets $config as a dependency, but it also varies on $node->title(), so surely should set $node as a dependency too.
Here's a patch that does that, untested though...
Comment #28
catchOK that fixes 2 out of 4 assertions.
I think the other issue is that static config objects don't have cache tags by default, so
This is not actually invalidating any cache tags.
However https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Cache%21R...
This should set max age to 0 given static config doesn't implement CacheableDependencyInterface, so you'd expect it to still pass.
But, we don't bubble max age yet per #2352009: [pp-3] Bubbling of elements' max-age to the page's headers and the page cache.
So the $config cacheable dependency does nothing to the breadcrumbs.
Since this is only for a test, I've changed it to use state and a raw cache tag. Tests pass locally for me now.
Comment #29
Wim LeersWell, no, look at
\Drupal\Core\Config\Config::save()
:So I don't think #28 is a good idea, it makes the test depend on state, which indeed by definition is uncacheable.
Comment #30
catchDoh completely forgot that then missed it when looking at this.
That snippet you posted explains the test fail though - because the isNew() check will fail there - the test is the first time it gets saved so the cache tag never gets invalidated.
This should pass, interdiff against #26.
Comment #32
catchPatch fail...
Comment #33
Wim LeersOMG!!!! I don't yet understand how this can happen. But I think this should happen in
setUp()
then, because this is just extremely confusing.Comment #34
catchIt would probably be least confusing if we provided the default config in config/install with a value other than 'hide' - then it'll be installed when the module is, and the first save in the test will be an update instead of insert with no workaround in the test.
But this is also partly why I wanted to use state + cache tags because it's a fair bit of boilerplate just to get the access result to change between requests.
If no-one gets to it overnight I'll have a look tomorrow my time though.
Comment #35
Wim LeersThe value wouldn't even have to be something else than
? Because Config isn't smart enough to not save anything if no actual changes are made?So, yeah, +1 to putting default config in
config/install
. Not doing that is really the source of all confusion here AFAICT!Comment #36
catchThe test relies on it not being 'hide' until it gets saved, but yeah otherwise this would be fine. Shifting to needs work for the default config change.
Comment #37
Wim LeersOkay, then yes, let the default installed config set it to something other than
'hide'
.Phew, glad that it was just that.
Comment #38
pwolanin CreditAttribution: pwolanin as a volunteer commentedThanks for finding that behavior - not clearing the cache tag on creation seems like a possible core bug in the case shown here - that the module doesn't provide a default config?
Comment #39
Wim Leers#2040135: Caches dependent on simple config are only invalidated on form submissions introduced the code quoted in #29. I thought it was to not do unnecessary invalidations while installing. But turns out it was @Berdir that suggested this in #2040135-69: Caches dependent on simple config are only invalidated on form submissions. Because it's consistent with how we do cache tag invalidation for content entities — see
\Drupal\Core\Entity\Entity::invalidateTagsOnSave()
:AFAICT that still makes sense.
Comment #40
catchHere's the default config and reverting #31.
Comment #41
Wim LeersPerfect.
Comment #42
alexpottCommitted 70ca793 and pushed to 8.0.x and 8.1.x. Thanks!
At first I looked at the new config file added by the test module and wondered why it was not state but the test is neat as it uses the config to add a cacheable dependencies.
Added visibility to a couple of functions where it was missing.
Fixed some coding standards in the test. The standards are: Comments may not appear after statements, Return comment must be on the next line.