Commit 80f2ff71 authored by catch's avatar catch
Browse files

Issue #3489179 by godotislate, ghost of drupal past: Referring the same entity...

Issue #3489179 by godotislate, ghost of drupal past: Referring the same entity multiple times breaks _referringItem

(cherry picked from commit 40c1ab52)
parent d2b22e76
Loading
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -57,7 +57,14 @@ protected function getEntitiesToView(EntityReferenceFieldItemListInterface $item
        $item->_accessCacheability = CacheableMetadata::createFromObject($access);
        if ($access->isAllowed()) {
          // Add the referring item, in case the formatter needs it.
          $entity->_referringItem = $items[$delta];
          if (isset($entity->_referringItem) && ($entity->_referringItem !== $item)) {
            // If the entity is already being referenced by another field item,
            // clone the entity so that _referringItem is set to the correct
            // item in each instance.
            $entity = clone $entity;
            $item->entity = $entity;
          }
          $entity->_referringItem = $item;
          $entities[$delta] = $entity;
        }
      }
+38 −0
Original line number Diff line number Diff line
@@ -424,6 +424,44 @@ public function testLabelFormatter(): void {
    $this->assertEquals($build[0]['#plain_text'], $entity_with_user->get('user_id')->entity->label(), 'For inaccessible links, the label should be displayed in plain text.');
  }

  /**
   * Tests formatters set the correct _referringItem on referenced entities.
   */
  public function testFormatterReferencingItem(): void {
    $storage = \Drupal::entityTypeManager()->getStorage($this->entityType);
    // Create a referencing entity and confirm that the _referringItem property
    // on the referenced entity in the built render array's items is set to the
    // field item on the referencing entity.
    $referencing_entity_1 = $storage->create([
      'name' => $this->randomMachineName(),
      $this->fieldName => $this->referencedEntity,
    ]);
    $referencing_entity_1->save();
    $build_1 = $referencing_entity_1->get($this->fieldName)->view(['type' => 'entity_reference_entity_view']);
    $this->assertEquals($this->referencedEntity->id(), $build_1['#items'][0]->entity->id());
    $this->assertEquals($referencing_entity_1->id(), $build_1['#items'][0]->entity->_referringItem->getEntity()->id());
    $this->assertEquals($referencing_entity_1->id(), $build_1[0]['#' . $this->entityType]->_referringItem->getEntity()->id());
    // Create a second referencing entity and confirm that the _referringItem
    // property on the referenced entity in the built render array's items is
    // set to the field item on the second referencing entity.
    $referencing_entity_2 = $storage->create([
      'name' => $this->randomMachineName(),
      $this->fieldName => $this->referencedEntity,
    ]);
    $referencing_entity_2->save();
    $build_2 = $referencing_entity_2->get($this->fieldName)->view(['type' => 'entity_reference_entity_view']);
    $this->assertEquals($this->referencedEntity->id(), $build_2['#items'][0]->entity->id());
    $this->assertEquals($referencing_entity_2->id(), $build_2['#items'][0]->entity->_referringItem->getEntity()->id());
    $this->assertEquals($referencing_entity_2->id(), $build_2[0]['#' . $this->entityType]->_referringItem->getEntity()->id());
    // Confirm that the _referringItem property for the entity referenced by the
    // first referencing entity is still set to the field item on the first
    // referencing entity.
    $this->assertEquals($referencing_entity_1->id(), $build_1['#items'][0]->entity->_referringItem->getEntity()->id());
    // Confirm that the _referringItem property is not the same for the two
    // render arrays.
    $this->assertNotEquals($build_1['#items'][0]->entity->_referringItem->getEntity()->id(), $build_2['#items'][0]->entity->_referringItem->getEntity()->id());
  }

  /**
   * Sets field values and returns a render array.
   *
+7 −0
Original line number Diff line number Diff line
@@ -38,6 +38,13 @@ protected function getEntitiesToView(EntityReferenceFieldItemListInterface $item
          '_loaded' => TRUE,
          '_is_default' => TRUE,
        ]);
        if ($file->_referringItem) {
          // If the file entity is already being referenced by another field
          // item, clone it so that _referringItem is set to the correct item
          // in each instance.
          $file = clone $file;
          $items[0]->entity = $file;
        }
        $file->_referringItem = $items[0];
      }
    }
+21 −0
Original line number Diff line number Diff line
@@ -145,6 +145,27 @@ public function testDefaultImages(): void {
    $article = $this->drupalCreateNode(['type' => 'article']);
    $article_built = $this->drupalBuildEntityView($article);
    $this->assertEquals($default_images['field']->id(), $article_built[$field_name][0]['#item']->target_id, "A new article node without an image has the expected default image file ID of {$default_images['field']->id()}.");
    // Confirm that the default image entity _referringItem property is set to
    // the field item on the article node.
    $article_default_image_referring_entity = $article_built[$field_name][0]['#item']->entity->_referringItem->getEntity();
    $this->assertEquals($article->id(), $article_default_image_referring_entity->id());

    // Confirm that the image default is shown for another new article node.
    $article2 = $this->drupalCreateNode(['type' => 'article']);
    $article2_built = $this->drupalBuildEntityView($article2);
    $this->assertEquals($default_images['field']->id(), $article2_built[$field_name][0]['#item']->target_id, "A new article node without an image has the expected default image file ID of {$default_images['field']->id()}.");
    // Confirm that the default image entity _referringItem property is set to
    // the field item on the second article node.
    $article2_default_image_referring_entity = $article2_built[$field_name][0]['#item']->entity->_referringItem->getEntity();
    $this->assertEquals($article2->id(), $article2_default_image_referring_entity->id());
    // Confirm that the default image entity _referringItem property on the
    // first article is still set to the field item on the article node.
    $article_default_image_referring_entity = $article_built[$field_name][0]['#item']->entity->_referringItem->getEntity();
    $this->assertEquals($article->id(), $article_default_image_referring_entity->id());

    // Confirm that the _referringItem values for the default image entities on
    // the two nodes are referring to field items on different nodes.
    $this->assertNotEquals($article_default_image_referring_entity->id(), $article2_default_image_referring_entity->id());

    // Also check that the field renders without warnings when the label is
    // hidden.