Issue #3374253 by TwoD, smustgrave: The renderer throws away cache metadata from access result if it is not allowed

merge-requests/3933/head
catch 2023-07-14 23:26:34 +01:00
parent 349e4c5dcb
commit d0337fa72b
3 changed files with 45 additions and 12 deletions

View File

@ -233,6 +233,14 @@ class Renderer implements RendererInterface {
if ($elements['#access'] instanceof AccessResultInterface) {
$this->addCacheableDependency($elements, $elements['#access']);
if (!$elements['#access']->isAllowed()) {
// Abort, but bubble new cache metadata from the access result.
$context = $this->getCurrentRenderContext();
if (!isset($context)) {
throw new \LogicException("Render context is empty, because render() was called outside of a renderRoot() or renderPlain() call. Use renderPlain()/renderRoot() or #lazy_builder/#pre_render instead.");
}
$context->push(new BubbleableMetadata());
$context->update($elements);
$context->bubble();
return '';
}
}
@ -592,7 +600,7 @@ class Renderer implements RendererInterface {
/**
* Returns the current render context.
*
* @return \Drupal\Core\Render\RenderContext
* @return \Drupal\Core\Render\RenderContext|null
* The current render context.
*/
protected function getCurrentRenderContext() {

View File

@ -625,11 +625,6 @@ parameters:
count: 1
path: lib/Drupal/Core/Render/MainContent/HtmlRenderer.php
-
message: "#^Variable \\$context in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: lib/Drupal/Core/Render/Renderer.php
-
message: "#^Variable \\$transaction in isset\\(\\) always exists and is not nullable\\.$#"
count: 1

View File

@ -791,13 +791,47 @@ class RendererTest extends RendererTestBase {
$this->assertEquals($this->renderer->renderRoot($element), $element['#foo'] . $element['#bar'], 'Passing arguments to theme functions works');
}
/**
* Provides a list of access conditions and expected cache metadata.
*
* @return array
*/
public function providerRenderCache() {
return [
'full access' => [
NULL,
[
'render_cache_tag',
'render_cache_tag_child:1',
'render_cache_tag_child:2',
],
],
'no child access' => [
AccessResult::forbidden()
->addCacheTags([
'render_cache_tag_child_access:1',
'render_cache_tag_child_access:2',
]),
[
'render_cache_tag',
'render_cache_tag_child:1',
'render_cache_tag_child:2',
'render_cache_tag_child_access:1',
'render_cache_tag_child_access:2',
],
],
];
}
/**
* @covers ::render
* @covers ::doRender
* @covers \Drupal\Core\Render\RenderCache::get
* @covers \Drupal\Core\Render\RenderCache::set
*
* @dataProvider providerRenderCache
*/
public function testRenderCache() {
public function testRenderCache($child_access, $expected_tags) {
$this->setUpRequest();
$this->setupMemoryCache();
@ -809,6 +843,7 @@ class RendererTest extends RendererTestBase {
],
'#markup' => '',
'child' => [
'#access' => $child_access,
'#cache' => [
'keys' => ['render_cache_test_child'],
'tags' => ['render_cache_tag_child:1', 'render_cache_tag_child:2'],
@ -831,11 +866,6 @@ class RendererTest extends RendererTestBase {
// Test that cache tags are correctly collected from the render element,
// including the ones from its subchild.
$expected_tags = [
'render_cache_tag',
'render_cache_tag_child:1',
'render_cache_tag_child:2',
];
$this->assertEquals($expected_tags, $element['#cache']['tags'], 'Cache tags were collected from the element and its subchild.');
// The cache item also has a 'rendered' cache tag.