Problem/Motivation
Calling $this->getContextValue($context_name) from within a block's ::blockAccess() or ::access() causes a fatal exception, because the contexts haven't been mapped to the block plugin before that function is called.
In BlockAccessControlHandler, it correctly maps context for all of the visibility conditions, so the conditions are able to use context, but the block plugin itself can't!
Proposed resolution
Map contexts for the block plugin in BlockAccessControlHandler before calling ->access()!
Remaining tasks
Write patch- Get review
- Commit!
User interface changes
None.
API changes
None.
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| #11 | interdiff.txt | 923 bytes | dsnopek |
| #11 | drupal8-block-access-contexts-2635238-11.patch | 3.21 KB | dsnopek |
Comments
Comment #2
dsnopekHere's a patch! This code is by @EclipseGC - I just added the try/catch.
Comment #3
dsnopekComment #4
tim.plunkettIf things worked as expected, we should also be able to remove the getRuntimeContexts/applyContextMapping calls from BlockViewBuilder.
But \Drupal\block\BlockViewBuilder::lazyBuilder() purposefully does a fresh entity_load() :(
Comment #5
phenaproximaComment #6
phenaproximaThis patch makes sense to me. Two things jump out, though:
Nit:
$entity->getPlugin()is called several times. Maybe call it once and then re-use the return value? That might make it a bit easier to read.If it's reasonably easy to do, can the failure be logged? Either that, or don't catch the exception at all -- to me, this looks as if we may be swallowing potentially useful debugging info.
Comment #7
eclipsegc commentedIf we don't catch it, the page won't render. And we don't want to log it because missing contexts on conditions is treated a access/visibility = false in core.
Eclipse
Comment #8
dsnopekre #6.2 and #7 (reworded slightly): catching that exception and making access forbidden is exactly what we're doing when context fails to map for the conditions (only a few lines above the code added by this patch). So, this is just doing the exact same thing for the block plugins own access checks as we're already doing for the visibility conditions.
Comment #9
phenaproximaOkay, I didn't know that. Makes sense. Thanks @EclipseGc and @dsnopek for clearing that up. Maybe we can add a comment to that effect, just so it's not a WTF for others?
Comment #10
dsnopekHere's an update that addresses phenaproxima's review in #6.1 and #9. It adds a simple comment that just refers to the comment right above the code we add which does this for conditions.
But now I have a question/concern... When we're missing contexts for the conditions above, we also do
->setMaxAge(0):Based on that comment (assuming I'm understanding it correctly) I think we need to do that in our patch too, right?
Comment #11
dsnopekDiscussed briefly with @berdir on IRC - he confirmed that we'll need to do the
->setCacheMaxAge(0)bit too. So, I added that and copied the @todo from above as well (so we can removed that when #2521956: Missing contexts prevent caching of block access is fixed).Comment #12
berdirLooks good to me. We've discussed the exception catching at length in #2620126: No way to handle 'optional' contexts without try/catch, this is the way it works now, as bad as it (IMHO) is.
Quickly discussed in IRC that we now do the assignment twice. But we can't change that, since we re-load those blocks again due to the lazy builder approach, sadly.
Comment #13
eclipsegc commentedHuge ++ from me on this.
Eclipse
Comment #14
berdir#2620126: No way to handle 'optional' contexts without try/catch was major and was closed as a duplicate, so setting this to major.
Comment #15
wim leersPatch looks good. Particularly the max-age zero bit.
Comment #16
alexpottI know @catch has has some reservations about this patch - I'm going to assign it to @catch to make sure that they're accounted for.
Comment #17
catchI still really dislike having to do the try/catch around the exception like this, it's not an exceptional (excuse pun) situation like Symfony HTTP exceptions (which we had an equivalent of with special DRUPAL_NOT_FOUND and drupal_not_found() return values and request short-circuiting), or form handling which similarly needs to short-circuit the request logic - this is just a method that gets some stuff and returns some stuff back or not.
The patch here is OK as a minimal fix in 8.0.x though, so committed/pushed to that and 8.1.x - and re-opening #2620126: No way to handle 'optional' contexts without try/catch.
Committed/pushed to 8.1.x and cherry-picked to 8.0.x. Thanks!
Comment #20
dsnopekThanks, everyone, for your help on this! And thanks, @catch, for committing despite the less than ideal situation with exceptions!