From 2ee934d4672fd9904932a6c151c7f114d189c3d4 Mon Sep 17 00:00:00 2001 From: Lee Rowlands <lee.rowlands@previousnext.com.au> Date: Wed, 31 Jan 2024 08:33:06 +1000 Subject: [PATCH] Issue #2885098 by philipnorton42, gapple, ksbuble, MerryHamster, Suresh Prabhu Parkala, joelpittet, vsujeetkumar, amjad1233, bakulahluwalia, mohit1604: Node RSS Views plugin causes wrong entity_view output to be cached (cherry picked from commit 7768575562e261269298dce480bf2c88acfd62b4) --- .../modules/node/src/Plugin/views/row/Rss.php | 3 + .../views.view.test_node_article_feed.yml | 207 ++++++++++++++++++ .../tests/src/Functional/NodeRssCacheTest.php | 87 ++++++++ 3 files changed, 297 insertions(+) create mode 100644 core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_article_feed.yml create mode 100644 core/modules/node/tests/src/Functional/NodeRssCacheTest.php diff --git a/core/modules/node/src/Plugin/views/row/Rss.php b/core/modules/node/src/Plugin/views/row/Rss.php index a8fe007502fc..4a74d4da167f 100644 --- a/core/modules/node/src/Plugin/views/row/Rss.php +++ b/core/modules/node/src/Plugin/views/row/Rss.php @@ -113,6 +113,9 @@ public function render($row) { $build = \Drupal::entityTypeManager() ->getViewBuilder('node') ->view($node, $build_mode); + // Add rss key to cache to differentiate this from other caches. + $build['#cache']['keys'][] = 'view_rss'; + unset($build['#theme']); if (!empty($node->rss_namespaces)) { diff --git a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_article_feed.yml b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_article_feed.yml new file mode 100644 index 000000000000..089e263a9dfb --- /dev/null +++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_article_feed.yml @@ -0,0 +1,207 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + - node.type.article + module: + - node + - user +id: test_node_article_feed +label: 'Test Node Article Feed' +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'access content' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: mini + options: + items_per_page: 10 + offset: 0 + id: 0 + total_pages: null + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: ‹‹ + next: ›› + style: + type: default + options: + grouping: { } + row_class: '' + default_row_class: true + uses_fields: false + row: + type: fields + options: + inline: { } + separator: '' + hide_empty: false + default_field_elements: true + fields: + title: + id: title + table: node_field_data + field: title + entity_type: node + entity_field: title + label: '' + alter: + alter_text: false + make_link: false + absolute: false + trim: false + word_boundary: false + ellipsis: false + strip_tags: false + html: false + hide_empty: false + empty_zero: false + settings: + link_to_entity: true + plugin_id: field + relationship: none + group_type: group + admin_label: '' + exclude: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_alter_empty: true + click_sort_column: value + type: string + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + filters: + status: + value: '1' + table: node_field_data + field: status + plugin_id: boolean + entity_type: node + entity_field: status + id: status + expose: + operator: '' + operator_limit_selection: false + operator_list: { } + group: 1 + type: + id: type + table: node_field_data + field: type + value: + article: article + entity_type: node + entity_field: type + plugin_id: bundle + expose: + operator_limit_selection: false + operator_list: { } + sorts: + created: + id: created + table: node_field_data + field: created + order: DESC + entity_type: node + entity_field: created + plugin_id: date + relationship: none + group_type: group + admin_label: '' + exposed: false + expose: + label: '' + granularity: second + header: { } + footer: { } + empty: { } + relationships: { } + arguments: { } + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url.query_args + - 'user.node_grants:view' + - user.permissions + tags: { } + feed_1: + display_plugin: feed + id: feed_1 + display_title: 'Test Feed' + position: 1 + display_options: + display_extenders: { } + row: + type: node_rss + options: + relationship: none + view_mode: teaser + path: test-node-article-feed + display_description: '' + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - 'user.node_grants:view' + - user.permissions + tags: { } diff --git a/core/modules/node/tests/src/Functional/NodeRssCacheTest.php b/core/modules/node/tests/src/Functional/NodeRssCacheTest.php new file mode 100644 index 000000000000..326be9c37da4 --- /dev/null +++ b/core/modules/node/tests/src/Functional/NodeRssCacheTest.php @@ -0,0 +1,87 @@ +<?php + +namespace Drupal\Tests\node\Functional; + +use Drupal\filter\Entity\FilterFormat; +use Drupal\views\Tests\ViewTestData; + +/** + * Ensures that RSS render cache doesn't interfere with other caches. + * + * Create a node, render that node as a teaser in the RSS feed, ensure that + * the RSS teaser render doesn't contain tags from the default theme. + * + * @group node + */ +class NodeRssCacheTest extends NodeTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = ['node_test', 'views', 'node_test_views']; + + /** + * {@inheritdoc} + */ + public static $testViews = ['test_node_article_feed']; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + ViewTestData::createTestViews(static::class, ['node_test_views']); + + // Use bypass node access permission here, because the test class uses + // hook_grants_alter() to deny access to everyone on node_access + // queries. + $user = $this->drupalCreateUser([ + 'bypass node access', + 'access content', + 'create article content', + ]); + $this->drupalLogin($user); + } + + /** + * Ensure the RSS teaser render does not interfere with default theme cache. + */ + public function testNodeRssCacheContent() { + // Only the plain_text text format is available by default, which escapes + // all HTML. + FilterFormat::create([ + 'format' => 'full_html', + 'name' => 'Full HTML', + 'filters' => [], + ])->save(); + + // Create the test node. + $node = $this->drupalCreateNode([ + 'type' => 'article', + 'promote' => 1, + 'title' => 'Article Test Title', + 'body' => [ + 'value' => '<p>Article test text.</p>', + 'format' => 'full_html', + ], + ]); + + // Render the node in the RSS feed view as a teaser. + $this->drupalGet('test-node-article-feed'); + + // Render the teaser normally. + $viewBuilder = $this->container->get('entity_type.manager')->getViewBuilder('node'); + $build = $viewBuilder->view($node, 'teaser'); + $output = $this->container->get('renderer')->renderPlain($build); + + // Teaser must contain an "<article" tag from the stable9 theme. + $this->assertStringContainsString('<article', (string) $output); + } + +} -- GitLab