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 fa83359c0f7997b3d5b6fd8ddd56d06f23f57151..2692d84e114d740ca79a142e10e85b9a0f401ce3 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php @@ -168,6 +168,10 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $recursive_render_id = $items->getFieldDefinition()->getTargetEntityTypeId() . $items->getFieldDefinition()->getTargetBundle() . $items->getName() + // We include the referencing entity, so we can render default images + // without hitting recursive protections. + . $items->getEntity()->id() + . $entity->getEntityTypeId() . $entity->id(); if (isset(static::$recursiveRenderDepth[$recursive_render_id])) { diff --git a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php b/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php index d4be1dadc4e404d28b90ce767a418f3820c6d371..aaee7d080ffbac1933693704dcdd949ee362a499 100644 --- a/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php +++ b/core/modules/field/tests/src/Kernel/EntityReference/EntityReferenceFormatterTest.php @@ -277,6 +277,49 @@ public function testEntityFormatterRecursiveRendering() { $this->assertEqual($actual_occurrences, $expected_occurrences); } + /** + * Renders the same entity referenced from different places. + */ + public function testEntityReferenceRecursiveProtectionWithManyRenderedEntities() { + $formatter = 'entity_reference_entity_view'; + $view_builder = $this->entityManager->getViewBuilder($this->entityType); + + // Set the default view mode to use the 'entity_reference_entity_view' + // formatter. + entity_get_display($this->entityType, $this->bundle, 'default') + ->setComponent($this->fieldName, [ + 'type' => $formatter, + ]) + ->save(); + + $storage = $this->entityManager->getStorage($this->entityType); + /** @var \Drupal\Core\Entity\ContentEntityInterface $referenced_entity */ + $referenced_entity = $storage->create(['name' => $this->randomMachineName()]); + + $range = range(0, 30); + $referencing_entities = array_map(function () use ($storage, $referenced_entity) { + $referencing_entity = $storage->create([ + 'name' => $this->randomMachineName(), + $this->fieldName => $referenced_entity, + ]); + $referencing_entity->save(); + return $referencing_entity; + }, $range); + + $build = $view_builder->viewMultiple($referencing_entities, 'default'); + $output = $this->render($build); + + // The title of entity_test entities is printed twice by default, so we have + // to multiply the formatter's recursive rendering protection limit by 2. + // Additionally, we have to take into account 2 additional occurrences of + // the entity title because we're rendering the full entity, not just the + // reference field. + $expected_occurrences = 30 * 2 + 2; + $actual_occurrences = substr_count($output, $referenced_entity->get('name')->value); + $this->assertEquals($expected_occurrences, $actual_occurrences); + } + + /** * Tests the label formatter. */