diff --git a/src/Plugin/Field/FieldType/EntityReferenceRevisionsItem.php b/src/Plugin/Field/FieldType/EntityReferenceRevisionsItem.php index 24b3224..8612c9d 100644 --- a/src/Plugin/Field/FieldType/EntityReferenceRevisionsItem.php +++ b/src/Plugin/Field/FieldType/EntityReferenceRevisionsItem.php @@ -282,6 +282,24 @@ class EntityReferenceRevisionsItem extends EntityReferenceItem implements Option } } if ($needs_save) { + + // Because ContentEntityBase::hasTranslationChanges() does not check for + // EntityReferenceRevisionsFieldItemList::hasAffectingChanges() on field + // items that are not translatable, hidden on translation forms and not + // in the default translation, this has to be handled here by setting + // setRevisionTranslationAffected on host translations that holds a + // reference that has been changed. + if ($is_affected && $host instanceof TranslatableRevisionableInterface) { + $languages = $host->getTranslationLanguages(); + foreach ($languages as $langcode => $language) { + $translation = $host->getTranslation($langcode); + if ($this->entity->hasTranslation($langcode) && $this->entity->getTranslation($langcode)->hasTranslationChanges() && $this->target_revision_id != $this->entity->getRevisionId()) { + $translation->setRevisionTranslationAffected(TRUE); + $translation->setRevisionTranslationAffectedEnforced(TRUE); + } + } + } + $this->entity->save(); } } diff --git a/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php b/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php index 1509e44..917381f 100644 --- a/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php +++ b/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php @@ -149,11 +149,37 @@ class EntityReferenceRevisionsCompositeTest extends EntityKernelTestBase { $this->assertNotEqual('2nd revision', $node->getTitle(), 'Node did not keep changed title after reversion.'); $this->assertNotEqual($original_composite_revision, $node->composite_reference[0]->target_revision_id, 'Composite entity got new revision when its host reverted to an old revision.'); - // Test that removing/changing composite references results in translation - // changes. + $node_storage = $this->entityTypeManager->getStorage('node'); + // Test that removing composite references results in translation changes. $node->set('composite_reference', []); $this->assertTrue($node->hasTranslationChanges()); + // Test that changing composite reference results in translation changes. + $changed_composite_reference = $composite; + $changed_composite_reference->set('name', 'Changing composite reference'); + $this->assertTrue($changed_composite_reference->isRevisionTranslationAffected()); + + $node->set('composite_reference', $changed_composite_reference); + $node->setNewRevision(); + $this->assertTrue($node->hasTranslationChanges()); + $node->save(); + $nid = $node->id(); + $node_storage->resetCache([$nid]); + /** @var \Drupal\node\NodeInterface $node */ + $node = $node_storage->load($nid); + + // Check the composite has changed. + $this->assertEquals('Changing composite reference', $node->get('composite_reference')->entity->getName()); + + // Make sure the node has 4 revisions. + $node_revisions_count = $node_storage->getQuery()->condition('nid', $nid)->allRevisions()->count()->execute(); + $this->assertEqual($node_revisions_count, 4); + + // Make sure the node has no revision with revision translation affected + // flag set to NULL. + $node_revisions_count = $node_storage->getQuery()->condition('nid', $nid)->allRevisions()->condition('revision_translation_affected', NULL, 'IS NULL')->count()->execute(); + $this->assertEqual($node_revisions_count, 0, 'Node has a revision with revision translation affected set to NULL'); + // Revert the changes to avoid interfering with the delete test. $node->set('composite_reference', $composite); diff --git a/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslationTest.php b/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslationTest.php index fbe4c14..7d55293 100644 --- a/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslationTest.php +++ b/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslationTest.php @@ -439,6 +439,104 @@ class EntityReferenceRevisionsCompositeTranslationTest extends EntityKernelTestB } + /** + * Tests that composite translations affects the host entity's translations. + */ + public function testCompositeTranslation() { + /** @var \Drupal\node\NodeStorageInterface $node_storage */ + $node_storage = $this->entityTypeManager->getStorage('node'); + + // Create a composite entity. + $composite = EntityTestCompositeRelationship::create([ + 'langcode' => 'en', + 'name' => 'Initial Source 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(); + + /** @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 that there is only 1 affected revision when creating a node. + $this->assertAffectedRevisionCount(1, $node); + // Assert there is no new composite revision after creating a host entity. + $this->assertRevisionCount(1, $composite); + + $node_de = $node->addTranslation('de', ['title' => 'New Node #1 DE'] + $node->toArray()); + $node_de = $node_storage->createRevision($node_de, FALSE); + + $node_de->get('composite_reference')->entity->getTranslation('de')->set('name', 'New 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->assertAffectedRevisionCount(1, $node_de); + $this->assertAffectedRevisionCount(1, $node); + + // Test that changing composite non default language (DE) reference results + // in translation changes for this language but not for the default + // language. + $node_de->get('composite_reference')->entity->getTranslation('de')->set('name', 'Change Composite #1 DE'); + $node_de->setNewRevision(); + $node_de->save(); + + $this->assertEquals('Change Composite #1 DE', $node_de->get('composite_reference')->entity->getTranslation('de')->getName()); + + // Make sure the node DE has one more affected translation revision. + $this->assertAffectedRevisionCount(2, $node_de); + // Make sure the node EN has only one 1 affected translation revision. + $this->assertAffectedRevisionCount(1, $node); + + // Test that changing composite in default language (EN) results in + // translation changes for this language but not for the DE language. + $node = $node_storage->load($node->id()); + $node->get('composite_reference')->entity->set('name', 'Update Source #1'); + $node->setNewRevision(); + $node->save(); + + $this->assertEquals('Update Source #1', $node->get('composite_reference')->entity->getTranslation('en')->getName()); + + // The node EN now has 2 affected translation revision. + $this->assertAffectedRevisionCount(2, $node); + // The node DE still has 2 affected translation revisions. + $this->assertAffectedRevisionCount(2, $node_de); + } + + /** + * Asserts the affected revision count of a certain entity. + * + * @param int $expected + * The expected count. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + */ + protected function assertAffectedRevisionCount($expected, EntityInterface $entity) { + $entity_type = $entity->getEntityType(); + $affected_revisions_count = $this->entityTypeManager->getStorage($entity_type->id()) + ->getQuery() + ->condition($entity_type->getKey('id'), $entity->id()) + ->condition($entity_type->getKey('langcode'), $entity->language()->getId()) + ->condition($entity_type->getKey('revision_translation_affected'), 1) + ->allRevisions() + ->count() + ->execute(); + + $this->assertEquals($expected, $affected_revisions_count); + } + /** * Asserts the revision count of an entity. *