Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
In practice, every single render array is varied by two cache contexts already:
'theme'
, because any render array that uses the theme system is tied to a theme'languages:interface'
, because almost all render arrays uset()
But we don't vary every single render array by those automatically, we put the burden on EntityViewBuilder
, BlockViewBuilder
etc. to define those cache contexts.
Proposed resolution
Add a container parameter that contains the default cache contexts and apply this when rendering/render caching.
Remaining tasks
None.
User interface changes
None.
API changes
None.
Beta phase evaluation
Issue category | Bug — this is basically adding what Drupal should already be doing and is fixing the regression of removing the functionality of drupal_render_cid_parts(). |
---|---|
Issue priority | Major because because necessary to ship with a non-WTF DX: repetition all over. |
Prioritized changes | The main goal of this issue is DX/performance |
Disruption | Zero disruption. |
Comment | File | Size | Author |
---|---|---|---|
#36 | renderer_default_cache_contexts-2453059-36.patch | 30.36 KB | Wim Leers |
Comments
Comment #1
Wim LeersHere's an initial patch that sets
'theme'
. We'll have to add'languages:interface'
once #2432837: Make cache contexts hierarchical (e.g. 'user' is more specific than 'user.roles') lands.Comment #3
Wim LeersChasing HEAD.
Comment #5
Wim LeersGreen.
Comment #6
effulgentsia CreditAttribution: effulgentsia at Acquia commented+1 to the issue title. That D8 HEAD doesn't do this is a regression from D7: https://api.drupal.org/api/drupal/includes%21common.inc/function/drupal_...
Not sure about making these two configurable though. Because in the case of 'theme', doRender() actually calls $this->theme->render(), so seems like it should force it. In the case of 'languages:interface', doRender() doesn't call t() itself, so setting that is more a convenience to allow lots of other places not to have to, but if we then proceed to make all those places not do it themselves, then that essentially is an implicit contract that the renderer will.
Having a container parameter for additional ones might make sense, but perhaps out of scope for this issue?
Comment #7
Wim LeersGood point about
'theme'
being always required. But I'm not sure it's worth the effort to special case'theme'
— there are a zillion other ways you can break Drupal by changing settings, configuration or container parameters. Besides, I could argue that somebody could swap out the theme manager to make Drupal unthemed (think headless Drupal), at which point omitting the "theme" cache tag would be valid.We cannot reasonably expect every render array that uses
t()
(which is probably >98%) to specify the'languages:interface'
cache context, so I think an implicit contract there is acceptable. That's basically also what the D7 function you linked to does.Therefore I think that the simplest and clearest way to do this, and to make it easily extensible, is to keep it as a container parameter. But if you feel strongly about this, I could definitely live with those two being hardcoded in
\Drupal\Core\Render\Renderer
.Comment #8
effulgentsia CreditAttribution: effulgentsia at Acquia commentedGood point about container parameters. But I think D8 has come a long way in reducing the fragility of settings and configuration. So I think my only objection then is having the name "config" in the parameter name. How about
renderer.required_cache_contexts
?Comment #9
Wim LeersSounds good :)
Thanks for the initial review. Now we just have to wait for the blocker to land, so that we can do
'language:interface'
here too. Or do you think we should already proceed and land this?Comment #10
effulgentsia CreditAttribution: effulgentsia at Acquia commentedUnless this is blocking other work, I think it can wait on the other issue.
Comment #11
Wim Leers#2432837: Make cache contexts hierarchical (e.g. 'user' is more specific than 'user.roles') landed, this is now unblocked!
Next step: #9.
Comment #12
Wim LeersFirst, a rebase.
Comment #13
Wim LeersAnd now with #9 done: wherever the
languages
cache context was added, it was actually the interface language that was intended, so'languages:' . LanguageInterface::TYPE_INTERFACE
should've been used. But until #2432837: Make cache contexts hierarchical (e.g. 'user' is more specific than 'user.roles') (which just landed), that distinction didn't exist yet.Comment #14
Wim LeersI missed one bit.
Comment #15
Wim Leers@effulgentsia remarked
Comment #18
Wim LeersFixing the failures in #13/#14.
Comment #23
Wim LeersComment #25
Fabianx CreditAttribution: Fabianx commentedI think we only need this when:
drupal_is_multilingual()
which means more than one language is configured at a given time.
I am not sure what the D8 equivalent is for that though.
Don't we need this only when setting cache data?
This is a _lot_ of unnecessary de-duplication we need to do.
Good idea :)
CNW per 2.
Comment #26
BerdirDoes it really hurt if the context is always there? If there's only one language, it will simple always have the same value, that shouldn't hurt much?
Comment #27
Wim Leers#25.1/#26:
Exactly.
#25.2:
At first, I was only setting it when caching data. But that doesn't work. It needs to happen always, because if on a page there is nothing that is render cacheable, we still want those cache contexts to be set.
What we could do, is set it on cache gets and when doing root rendering. See
proposed_interdiff.txt
to see what that'd look like. It trades cleanliness/maintainability for duplication/performance. Moving it into a helper method would help make it more maintainable, at the cost of a smaller performance gain.Personally, I think we should go for maintainability in
Renderer
for now. We know we can still optimize the cacheability-handling of render array rendering, it's better to do all optimization work there after #2429287: [meta] Finalize the cache contexts API & DX/usage, enable a leap forward in performance.Comment #28
Wim LeersGreen.
Comment #29
Fabianx CreditAttribution: Fabianx for Drupal Association commentedYes, indeed we can only set this when:
I think adding this if around the won't hurt or do you see a case where we would need it on another level?
That would be almost as clean as the proposed solution, but avoid an even larger percentage of Cache Context merging per page rendering.
--
Besides that this is RTBC from my side.
Comment #30
Fabianx CreditAttribution: Fabianx for Drupal Association commentedI thought for debuggability reasons we should maybe make 'rendered' now also a required cache context.
Then I changed my mind as we never want anyone to remove that one as its kinda internal ...
Comment #31
Wim LeersExcellent idea! Best of both patches :) Much simpler!
Comment #32
Wim LeersDone.
Added beta evaluation.
I don't think a CR will be necessary, but I will update the docs under https://www.drupal.org/developing/api/8/render once this lands.
Comment #34
Fabianx CreditAttribution: Fabianx for Drupal Association commentedRe-classifying as a bug:
This is the replacement for drupal_render_cid_parts() and hence can be considered a regression from Drupal 7.
Comment #35
Fabianx CreditAttribution: Fabianx for Drupal Association commentedComment #36
Wim LeersChanges:
sites/default/default.services.yml
were lost; restored them.Comment #37
Fabianx CreditAttribution: Fabianx for Drupal Association commentedNice! :)
I am honestly not sure, but might imagine it might be safer to use renderPlain instead?
But we can leave it also as renderRoot for now.
This looks great now!
RTBC!
We could use some doc updates and do we need to update any of the old CRs? I am not sure.
Comment #38
Wim Leers#37.2: we only need to use
::renderRoot()
in those few cases because we're expecting to look at the final rendered result, which we expect to include the default render cache contexts. And "looking at the final rendered result" -> "userenderRoot()
". That's all.Documentation updated at https://www.drupal.org/developing/api/8/render/arrays/cacheability/bubbling.
I don't think CR updates are necessary: the reason we do this is precisely to allow people to not have to think about using
t()
nor actively think about the negotiated theme when building render arrays: thanks to this patch, they can continue to not add cache contexts for those cases.Comment #39
alexpottThis issue addresses a major bug and is allowed per https://www.drupal.org/core/beta-changes. Committed 2847b59 and pushed to 8.0.x. Thanks!