You are here

public function EntityReferenceRevisionsCompositeTranslationTest::testCompositePendingRevisionTranslation in Entity Reference Revisions 8

Test the storage for handling pending revisions with translations.

File

tests/src/Kernel/EntityReferenceRevisionsCompositeTranslationTest.php, line 139

Class

EntityReferenceRevisionsCompositeTranslationTest
Tests the entity_reference_revisions composite relationship.

Namespace

Drupal\Tests\entity_reference_revisions\Kernel

Code

public function testCompositePendingRevisionTranslation() {

  /** @var \Drupal\node\NodeStorageInterface $node_storage */
  $node_storage = \Drupal::entityTypeManager()
    ->getStorage('node');

  // Create a nested composite entity.
  $nested_composite = EntityTestCompositeRelationship::create([
    'langcode' => 'en',
    'name' => 'Initial Nested Source Composite',
  ]);
  $nested_composite
    ->save();

  // Create a composite entity.
  $composite = EntityTestCompositeRelationship::create([
    'langcode' => 'en',
    'name' => 'Initial Source Composite',
    'field_untranslatable' => 'Initial untranslatable field',
    'composite_reference' => $nested_composite,
  ]);
  $composite
    ->save();

  // Create a node with a reference to the test composite entity.
  $node = Node::create([
    'langcode' => 'en',
    'title' => 'Initial Source Node',
    'type' => 'article',
    'composite_reference' => $composite,
  ]);
  $node
    ->save();
  $initial_revision_id = $node
    ->getRevisionId();

  /** @var \Drupal\node\NodeInterface $node */
  $node = $node_storage
    ->load($node
    ->id());

  // Assert that there is only 1 revision when creating a node.
  $this
    ->assertRevisionCount(1, $node);

  // Assert there is no new composite revision after creating a host entity.
  $this
    ->assertRevisionCount(1, $composite);

  // Assert there is no new composite revision after creating a host entity.
  $this
    ->assertRevisionCount(1, $nested_composite);

  // Create a second nested composite entity.
  $second_nested_composite = EntityTestCompositeRelationship::create([
    'langcode' => 'en',
    'name' => 'Initial Nested Composite #2',
  ]);

  // Add a pending revision.
  $node = $node_storage
    ->createRevision($node, FALSE);
  $node
    ->get('composite_reference')->entity
    ->get('composite_reference')
    ->appendItem($second_nested_composite);
  $node
    ->save();
  $pending_en_revision_id = $node
    ->getRevisionId();
  $this
    ->assertRevisionCount(2, $node);
  $this
    ->assertRevisionCount(2, $composite);
  $this
    ->assertRevisionCount(2, $nested_composite);
  $this
    ->assertRevisionCount(1, $second_nested_composite);

  // Create a DE translation, start as a draft to replicate the behavior of
  // the UI.
  $node_de = $node
    ->addTranslation('de', [
    'title' => 'New Node #1 DE',
  ] + $node
    ->toArray());
  $node_de = $node_storage
    ->createRevision($node_de, FALSE);

  // Despite starting of the draft revision, creating draft of the translation
  // uses the paragraphs of the default revision.
  $this
    ->assertCount(1, $node_de
    ->get('composite_reference')->entity
    ->get('composite_reference'));
  $node_de
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->set('name', 'New Composite #1 DE');
  $node_de
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->set('name', 'New Nested Composite #1 DE');
  $node_de
    ->isDefaultRevision(TRUE);
  $violations = $node_de
    ->validate();
  foreach ($violations as $violation) {
    $this
      ->fail($violation
      ->getPropertyPath() . ': ' . $violation
      ->getMessage());
  }
  $this
    ->assertEquals(0, count($violations));
  $node_de
    ->save();
  $this
    ->assertRevisionCount(3, $node);
  $this
    ->assertRevisionCount(3, $composite);
  $this
    ->assertRevisionCount(3, $nested_composite);
  $this
    ->assertRevisionCount(1, $second_nested_composite);

  // Update the translation as a pending revision for both the composite and
  // the node.
  $node_de
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->set('name', 'Pending Revision Composite #1 DE');
  $node_de
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->set('name', 'Pending Nested Composite #1 DE');
  $node_de
    ->set('title', 'Pending Revision Node #1 DE');
  $node_de
    ->setNewRevision(TRUE);
  $node_de
    ->isDefaultRevision(FALSE);
  $violations = $node_de
    ->validate();
  foreach ($violations as $violation) {
    $this
      ->fail($violation
      ->getMessage());
  }
  $this
    ->assertEquals(0, count($violations));
  $node_de
    ->save();
  $this
    ->assertRevisionCount(4, $node);
  $this
    ->assertRevisionCount(4, $composite);
  $this
    ->assertRevisionCount(4, $nested_composite);
  $this
    ->assertRevisionCount(1, $second_nested_composite);

  /** @var \Drupal\node\NodeInterface $node_de */
  $node_de = $node_storage
    ->loadRevision($node_de
    ->getRevisionId());
  $this
    ->assertFalse($node_de
    ->isDefaultRevision());
  $this
    ->assertFalse((bool) $node_de
    ->isRevisionTranslationAffected());
  $this
    ->assertTrue((bool) $node_de
    ->getTranslation('de')
    ->isRevisionTranslationAffected());
  $this
    ->assertEquals('Pending Revision Node #1 DE', $node_de
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('Initial Source Node', $node_de
    ->label());
  $this
    ->assertFalse($node_de
    ->get('composite_reference')->entity
    ->isDefaultRevision());
  $this
    ->assertEquals('Pending Revision Composite #1 DE', $node_de
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('Pending Nested Composite #1 DE', $node_de
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('Initial untranslatable field', $node_de
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->get('field_untranslatable')->value);
  $this
    ->assertEquals('Initial Source Composite', $node_de
    ->get('composite_reference')->entity
    ->label());

  // Reload the default revision of the node, make sure that the composite
  // there is unchanged.
  $node = $node_storage
    ->load($node
    ->id());
  $this
    ->assertTrue($node
    ->hasTranslation('de'));
  $this
    ->assertEquals('Initial Source Node', $node
    ->label());
  $this
    ->assertTrue($node
    ->get('composite_reference')->entity
    ->hasTranslation('de'));
  $this
    ->assertEquals('Initial Source Composite', $node
    ->get('composite_reference')->entity
    ->label());

  // Create a FR translation, start as a draft to replicate the behavior of
  // the UI.
  $node_fr = $node
    ->addTranslation('fr', [
    'title' => 'Pending Revision Node #1 FR',
  ] + $node
    ->toArray());
  $node_fr = $node_storage
    ->createRevision($node_fr, FALSE);
  $node_fr
    ->get('composite_reference')->entity
    ->getTranslation('fr')
    ->set('name', 'Pending Revision Composite #1 FR');
  $node_fr
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->getTranslation('fr')
    ->set('name', 'Pending Nested Composite #1 FR');
  $violations = $node_fr
    ->validate();
  $this
    ->assertEquals(0, count($violations));
  $node_fr
    ->save();

  // Now assert that all 3 revisions exist as expected. Two translation
  // pending revisions, each composite has the original revision as parent
  // without any existing translation.

  /** @var \Drupal\node\NodeInterface $node_fr */
  $node_fr = $node_storage
    ->loadRevision($node_fr
    ->getRevisionId());
  $this
    ->assertFalse($node_fr
    ->isDefaultRevision());
  $this
    ->assertTrue($node_fr
    ->hasTranslation('de'));
  $this
    ->assertFalse((bool) $node_fr
    ->isRevisionTranslationAffected());
  $this
    ->assertTrue((bool) $node_fr
    ->getTranslation('fr')
    ->isRevisionTranslationAffected());
  $this
    ->assertEquals('Pending Revision Node #1 FR', $node_fr
    ->getTranslation('fr')
    ->label());
  $this
    ->assertEquals('Initial Source Node', $node_fr
    ->label());
  $this
    ->assertFalse($node_fr
    ->get('composite_reference')->entity
    ->isDefaultRevision());
  $this
    ->assertTrue($node_fr
    ->get('composite_reference')->entity
    ->hasTranslation('de'));
  $this
    ->assertEquals('Pending Revision Composite #1 FR', $node_fr
    ->get('composite_reference')->entity
    ->getTranslation('fr')
    ->label());
  $this
    ->assertEquals('Pending Nested Composite #1 FR', $node_fr
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->getTranslation('fr')
    ->label());
  $this
    ->assertEquals('Initial untranslatable field', $node_fr
    ->get('composite_reference')->entity
    ->getTranslation('fr')
    ->get('field_untranslatable')->value);
  $this
    ->assertEquals('Initial Source Composite', $node_fr
    ->get('composite_reference')->entity
    ->label());
  $node_de = $node_storage
    ->loadRevision($node_de
    ->getRevisionId());
  $this
    ->assertFalse($node_de
    ->isDefaultRevision());
  $this
    ->assertFalse($node_de
    ->hasTranslation('fr'));
  $this
    ->assertEquals('Pending Revision Node #1 DE', $node_de
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('Initial Source Node', $node_de
    ->label());
  $this
    ->assertFalse($node_de
    ->get('composite_reference')->entity
    ->isDefaultRevision());
  $this
    ->assertFalse($node_de
    ->get('composite_reference')->entity
    ->hasTranslation('fr'));
  $this
    ->assertEquals('Pending Revision Composite #1 DE', $node_de
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('Pending Nested Composite #1 DE', $node_de
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('Initial untranslatable field', $node_de
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->get('field_untranslatable')->value);
  $this
    ->assertEquals('Initial Source Composite', $node_de
    ->get('composite_reference')->entity
    ->label());

  // Reload the default revision of the node, make sure that the composite
  // there is unchanged.
  $node = $node_storage
    ->load($node
    ->id());
  $this
    ->assertTrue($node
    ->hasTranslation('de'));
  $this
    ->assertEquals('Initial Source Node', $node
    ->label());
  $this
    ->assertTrue($node
    ->get('composite_reference')->entity
    ->hasTranslation('de'));
  $this
    ->assertEquals('Initial Source Composite', $node
    ->get('composite_reference')->entity
    ->label());

  // Create another pending EN revision and make that the default.
  $node = $node_storage
    ->loadRevision($pending_en_revision_id);
  $new_revision = $node_storage
    ->createRevision($node);
  $new_revision
    ->get('composite_reference')->entity
    ->set('name', 'Updated Source Composite');
  $new_revision
    ->get('composite_reference')->entity
    ->set('field_untranslatable', 'Updated untranslatable field');
  $new_revision
    ->setTitle('Updated Source Node');
  $new_revision
    ->get('composite_reference')->entity
    ->get('composite_reference')[1]->entity
    ->set('name', 'Draft Nested Source Composite #2');
  $violations = $new_revision
    ->validate();
  $this
    ->assertEquals(0, count($violations));
  $new_revision
    ->save();

  // Assert the two english revisions.
  // Reload the default revision of the node, make sure that the composite
  // there is unchanged.
  $node = $node_storage
    ->load($node
    ->id());
  $this
    ->assertTrue($node
    ->isDefaultRevision());
  $this
    ->assertTrue($node
    ->hasTranslation('de'));
  $this
    ->assertFalse($node
    ->hasTranslation('fr'));
  $this
    ->assertTrue((bool) $node
    ->isRevisionTranslationAffected());
  $this
    ->assertEquals('Updated Source Node', $node
    ->label());
  $this
    ->assertTrue($node
    ->get('composite_reference')->entity
    ->isDefaultRevision());
  $this
    ->assertTrue($node
    ->get('composite_reference')->entity
    ->hasTranslation('de'));
  $this
    ->assertFalse($node
    ->get('composite_reference')->entity
    ->hasTranslation('fr'));
  $this
    ->assertEquals('Updated Source Composite', $node
    ->get('composite_reference')->entity
    ->label());
  $this
    ->assertEquals('Initial Nested Source Composite', $node
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->label());
  $this
    ->assertEquals('Draft Nested Source Composite #2', $node
    ->get('composite_reference')->entity
    ->get('composite_reference')[1]->entity
    ->label());
  $this
    ->assertEquals('Updated untranslatable field', $node
    ->get('composite_reference')->entity
    ->get('field_untranslatable')->value);
  $node_initial = $node_storage
    ->loadRevision($initial_revision_id);
  $this
    ->assertFalse($node_initial
    ->isDefaultRevision());
  $this
    ->assertFalse($node_initial
    ->hasTranslation('de'));
  $this
    ->assertFalse($node_initial
    ->hasTranslation('fr'));
  $this
    ->assertEquals('Initial Source Node', $node_initial
    ->label());
  $this
    ->assertFalse($node_initial
    ->get('composite_reference')->entity
    ->isDefaultRevision());
  $this
    ->assertFalse($node_initial
    ->get('composite_reference')->entity
    ->hasTranslation('de'));
  $this
    ->assertEquals('Initial Source Composite', $node_initial
    ->get('composite_reference')->entity
    ->label());
  $this
    ->assertEquals('Initial Nested Source Composite', $node_initial
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->label());
  $this
    ->assertEquals('Initial untranslatable field', $node_initial
    ->get('composite_reference')->entity
    ->get('field_untranslatable')->value);
  $this
    ->assertCount(1, $node_initial
    ->get('composite_reference')->entity
    ->get('composite_reference'));

  // The current node_fr pending revision still has the initial value before
  // "merging" it, but it will get the new value for the untranslatable field
  // in the new revision.
  $node_fr = $node_storage
    ->loadRevision($node_fr
    ->getRevisionId());
  $this
    ->assertEquals('Initial untranslatable field', $node_fr
    ->get('composite_reference')->entity
    ->get('field_untranslatable')->value);
  $this
    ->assertCount(1, $node_fr
    ->get('composite_reference')->entity
    ->get('composite_reference'));

  // Now publish the FR pending revision and also add a translation for
  // the second composite that it now has.
  $new_revision = $node_storage
    ->createRevision($node_fr
    ->getTranslation('fr'));
  $this
    ->assertCount(2, $new_revision
    ->get('composite_reference')->entity
    ->get('composite_reference'));
  $new_revision
    ->get('composite_reference')->entity
    ->get('composite_reference')[1]->entity
    ->getTranslation('fr')
    ->set('name', 'FR Nested Composite #2');
  $violations = $new_revision
    ->validate();
  $this
    ->assertEquals(0, count($violations));
  $new_revision
    ->save();
  $this
    ->assertRevisionCount(7, $node);
  $this
    ->assertRevisionCount(7, $composite);
  $this
    ->assertRevisionCount(7, $nested_composite);
  $this
    ->assertRevisionCount(3, $second_nested_composite);

  // The new default revision should now have the updated english source,
  // original german translation and the french pending revision.
  $node = $node_storage
    ->load($node
    ->id());
  $this
    ->assertTrue($node
    ->isDefaultRevision());
  $this
    ->assertTrue($node
    ->hasTranslation('de'));
  $this
    ->assertTrue($node
    ->hasTranslation('fr'));
  $this
    ->assertFalse((bool) $node
    ->isRevisionTranslationAffected());
  $this
    ->assertTrue((bool) $node
    ->getTranslation('fr')
    ->isRevisionTranslationAffected());
  $this
    ->assertEquals('Updated Source Node', $node
    ->label());
  $this
    ->assertTrue($node
    ->get('composite_reference')->entity
    ->isDefaultRevision());
  $this
    ->assertTrue($node
    ->get('composite_reference')->entity
    ->hasTranslation('de'));
  $this
    ->assertTrue($node
    ->get('composite_reference')->entity
    ->hasTranslation('fr'));
  $this
    ->assertEquals('Pending Revision Node #1 FR', $node
    ->getTranslation('fr')
    ->label());
  $this
    ->assertEquals('Pending Revision Composite #1 FR', $node
    ->get('composite_reference')->entity
    ->getTranslation('fr')
    ->label());
  $this
    ->assertEquals('Pending Nested Composite #1 FR', $node
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->getTranslation('fr')
    ->label());
  $this
    ->assertEquals('New Node #1 DE', $node
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('New Composite #1 DE', $node
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('New Nested Composite #1 DE', $node
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('Updated Source Composite', $node
    ->get('composite_reference')->entity
    ->label());
  $this
    ->assertEquals('Updated untranslatable field', $node
    ->get('composite_reference')->entity
    ->get('field_untranslatable')->value);
  $this
    ->assertEquals('Draft Nested Source Composite #2', $node
    ->get('composite_reference')->entity
    ->get('composite_reference')[1]->entity
    ->label());
  $this
    ->assertEquals('FR Nested Composite #2', $node
    ->get('composite_reference')->entity
    ->get('composite_reference')[1]->entity
    ->getTranslation('fr')
    ->label());

  // Now publish the DE pending revision as well.
  $new_revision = $node_storage
    ->createRevision($node_de
    ->getTranslation('de'));
  $violations = $new_revision
    ->validate();
  $this
    ->assertCount(2, $new_revision
    ->get('composite_reference')->entity
    ->get('composite_reference'));
  $this
    ->assertEquals(0, count($violations));
  $new_revision
    ->save();
  $this
    ->assertRevisionCount(8, $node);
  $this
    ->assertRevisionCount(8, $composite);
  $this
    ->assertRevisionCount(8, $nested_composite);
  $this
    ->assertRevisionCount(4, $second_nested_composite);

  // The new default revision should now have the updated source and both
  // translations.
  $node = $node_storage
    ->load($node
    ->id());
  $this
    ->assertTrue($node
    ->isDefaultRevision());
  $this
    ->assertTrue($node
    ->hasTranslation('de'));
  $this
    ->assertTrue($node
    ->hasTranslation('fr'));
  $this
    ->assertFalse((bool) $node
    ->isRevisionTranslationAffected());
  $this
    ->assertFalse((bool) $node
    ->getTranslation('fr')
    ->isRevisionTranslationAffected());
  $this
    ->assertTrue((bool) $node
    ->getTranslation('de')
    ->isRevisionTranslationAffected());
  $this
    ->assertEquals('Updated Source Node', $node
    ->label());
  $this
    ->assertTrue($node
    ->get('composite_reference')->entity
    ->isDefaultRevision());
  $this
    ->assertTrue($node
    ->get('composite_reference')->entity
    ->hasTranslation('de'));
  $this
    ->assertTrue($node
    ->get('composite_reference')->entity
    ->hasTranslation('fr'));
  $this
    ->assertEquals('Pending Revision Node #1 FR', $node
    ->getTranslation('fr')
    ->label());
  $this
    ->assertEquals('Pending Revision Composite #1 FR', $node
    ->get('composite_reference')->entity
    ->getTranslation('fr')
    ->label());
  $this
    ->assertEquals('Pending Revision Node #1 DE', $node
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('Pending Revision Composite #1 DE', $node
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('Pending Nested Composite #1 DE', $node
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->label());
  $this
    ->assertEquals('Updated Source Composite', $node
    ->get('composite_reference')->entity
    ->label());
  $this
    ->assertEquals('Updated untranslatable field', $node
    ->get('composite_reference')->entity
    ->get('field_untranslatable')->value);
  $this
    ->assertEquals('Draft Nested Source Composite #2', $node
    ->get('composite_reference')->entity
    ->get('composite_reference')[1]->entity
    ->label());
  $this
    ->assertEquals('FR Nested Composite #2', $node
    ->get('composite_reference')->entity
    ->get('composite_reference')[1]->entity
    ->getTranslation('fr')
    ->label());

  // The second nested composite of DE inherited the default values for its
  // translation.
  $this
    ->assertEquals('Draft Nested Source Composite #2', $node
    ->get('composite_reference')->entity
    ->get('composite_reference')[1]->entity
    ->getTranslation('de')
    ->label());

  // Simulate creating a new pending revision like
  // \Drupal\content_moderation\EntityTypeInfo::entityPrepareForm().
  $new_revision = $node_storage
    ->createRevision($node);
  $revision_key = $new_revision
    ->getEntityType()
    ->getKey('revision');
  $new_revision
    ->set($revision_key, $new_revision
    ->getLoadedRevisionId());
  $new_revision
    ->save();
  $this
    ->assertEquals('Pending Nested Composite #1 DE', $new_revision
    ->get('composite_reference')->entity
    ->get('composite_reference')->entity
    ->getTranslation('de')
    ->label());
}