--- 2940605-recursion_global-94.patch 2022-10-21 16:31:01.570268100 +0200 +++ 2940605-99.patch 2022-10-21 16:51:59.379501600 +0200 @@ -44,7 +44,7 @@ } diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php -index 1a982bdc21..beb09afec8 100644 +index 5dbff76dd8..2f60d134bb 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php @@ -28,6 +28,11 @@ class EntityReferenceEntityFormatter extends EntityReferenceFormatterBase { @@ -52,10 +52,10 @@ * * @var int + * -+ * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. ++ * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. + * Use #recursion_keys in render arrays to prevent recursion. + * -+ * @see https://www.drupal.org/node/2940605 ++ * @see https://www.drupal.org/node/3316878 */ const RECURSIVE_RENDER_LIMIT = 20; @@ -64,10 +64,10 @@ * * @var array + * -+ * @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. ++ * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. + * Use #recursion_keys in render arrays to prevent recursion. + * -+ * @see https://www.drupal.org/node/2940605 ++ * @see https://www.drupal.org/node/3316878 */ protected static $recursiveRenderDepth = []; @@ -113,7 +113,7 @@ $elements[$delta] = $view_builder->view($entity, $view_mode, $entity->language()->getId()); diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php -index f95116e5f7..7312edef3d 100644 +index da19e3281f..d8dc56aea8 100644 --- a/core/lib/Drupal/Core/Render/Renderer.php +++ b/core/lib/Drupal/Core/Render/Renderer.php @@ -96,6 +96,13 @@ class Renderer implements RendererInterface { @@ -130,7 +130,7 @@ /** * Constructs a new Renderer. * -@@ -203,6 +210,7 @@ public function render(&$elements, $is_root_call = FALSE) { +@@ -206,6 +213,7 @@ public function render(&$elements, $is_root_call = FALSE) { catch (\Exception $e) { // Mark the ::rootRender() call finished due to this exception & re-throw. $this->isRenderingRoot = FALSE; @@ -138,7 +138,7 @@ throw $e; } } -@@ -374,7 +382,23 @@ protected function doRender(&$elements, $is_root_call = FALSE) { +@@ -385,7 +393,23 @@ protected function doRender(&$elements, $is_root_call = FALSE) { $elements['#cache']['max-age'] = $elements['#cache']['max-age'] ?? Cache::PERMANENT; $elements['#attached'] = $elements['#attached'] ?? []; @@ -163,7 +163,7 @@ if (!empty($elements['#printed'])) { // The #printed element contains all the bubbleable rendering metadata for // the subtree. -@@ -541,6 +565,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) { +@@ -557,6 +581,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) { // Rendering is finished, all necessary info collected! $context->bubble(); @@ -172,7 +172,7 @@ return $elements['#markup']; } diff --git a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php b/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php -index c025b2caf8..3c9774b593 100644 +index cd62a41ece..8287c2a03c 100644 --- a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php +++ b/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php @@ -6,7 +6,6 @@ @@ -191,7 +191,7 @@ /** * Tests the formatters functionality. -@@ -256,40 +256,63 @@ public function testEntityFormatterRecursiveRendering() { +@@ -259,40 +259,67 @@ public function testEntityFormatterRecursiveRendering() { $referencing_entity_1->{$this->fieldName}->entity = $referencing_entity_1; $referencing_entity_1->save(); @@ -200,6 +200,7 @@ + // Using a different view mode is not recursion. + $build = $view_builder->view($referencing_entity_1, 'teaser'); + $output = $renderer->renderRoot($build); ++ + // 2 occurrences of the entity title per entity. + $expected_occurrences = 4; + $actual_occurrences = substr_count($output, $referencing_entity_1->name->value); @@ -222,7 +223,7 @@ + // Repetition is not wrongly detected as recursion. + // entity_1 -> entity_1 + $output = $renderer->renderRoot($build); - $actual_occurrences = substr_count($output, $referencing_entity_1->name->value); + $actual_occurrences = substr_count($output, $referencing_entity_1->label()); $this->assertEquals($expected_occurrences, $actual_occurrences); - // Repeat the process with another entity in order to check that the @@ -238,8 +239,8 @@ $build = $view_builder->view($referencing_entity_2, 'default'); $output = $renderer->renderRoot($build); - -- $actual_occurrences = substr_count($output, $referencing_entity_2->name->value); -+ $actual_occurrences = substr_count($output, $referencing_entity_1->name->value); +- $actual_occurrences = substr_count($output, $referencing_entity_2->label()); ++ $actual_occurrences = substr_count($output, $referencing_entity_1->name ->value); $this->assertEquals($expected_occurrences, $actual_occurrences); - // Now render both entities at the same time and check again. @@ -248,30 +249,32 @@ + // entity_2 -> entity_1 $build = $view_builder->viewMultiple([$referencing_entity_1, $referencing_entity_2], 'default'); $output = $renderer->renderRoot($build); -- + + // entity_1 should be seen once as a parent and once as a child of entity_2. + $expected_occurrences = 4; - $actual_occurrences = substr_count($output, $referencing_entity_1->name->value); + $actual_occurrences = substr_count($output, $referencing_entity_1->label()); $this->assertEquals($expected_occurrences, $actual_occurrences); + + // entity_2 is seen only once, as a parent. + $expected_occurrences = 2; + $actual_occurrences = substr_count($output, $referencing_entity_2->name->value); + $this->assertEquals($expected_occurrences, $actual_occurrences); - ++ + // Indirect recursion is not ok. + // entity_2 -> entity_1 -> entity_2 + $referencing_entity_1->{$this->fieldName}->entity = $referencing_entity_2; + $referencing_entity_1->save(); + $build = $view_builder->view($referencing_entity_2, 'default'); + $output = $renderer->renderRoot($build); ++ + // Each entity should be seen once. + $expected_occurrences = 2; + $actual_occurrences = substr_count($output, $referencing_entity_1->name->value); + $this->assertEquals($expected_occurrences, $actual_occurrences); - $actual_occurrences = substr_count($output, $referencing_entity_2->name->value); + $actual_occurrences = substr_count($output, $referencing_entity_2->label()); $this->assertEquals($expected_occurrences, $actual_occurrences); } -@@ -337,6 +360,51 @@ public function testEntityReferenceRecursiveProtectionWithManyRenderedEntities() +@@ -340,6 +367,51 @@ public function testEntityReferenceRecursiveProtectionWithManyRenderedEntities() $this->assertEquals($expected_occurrences, $actual_occurrences); }