From c3ed391da36fe4b3039fb6afb27a61369f41189d Mon Sep 17 00:00:00 2001
From: Henrik Danielsson <h.danielsson@gmail.com>
Date: Sun, 17 Dec 2023 04:23:43 +0100
Subject: [PATCH 1/2] Only sync default state for new revisions, unless the
 parent changes to be the default revision.

---
 .../EntityReferenceRevisionsItem.php          |  8 ++-
 .../EntityReferenceRevisionsCompositeTest.php | 69 +++++++++++++++++++
 2 files changed, 74 insertions(+), 3 deletions(-)

diff --git a/src/Plugin/Field/FieldType/EntityReferenceRevisionsItem.php b/src/Plugin/Field/FieldType/EntityReferenceRevisionsItem.php
index 895a885..34da1e9 100644
--- a/src/Plugin/Field/FieldType/EntityReferenceRevisionsItem.php
+++ b/src/Plugin/Field/FieldType/EntityReferenceRevisionsItem.php
@@ -274,11 +274,13 @@ class EntityReferenceRevisionsItem extends EntityReferenceItem implements Option
       if ($is_affected && !$host->isNew() && $this->entity && $this->entity->getEntityType()->get('entity_revision_parent_id_field')) {
         if ($host->isNewRevision()) {
           $this->entity->setNewRevision();
+          // Additionally ensure that the default revision state is kept synced.
+          $this->entity->isDefaultRevision($host->isDefaultRevision());
           $needs_save = TRUE;
         }
-        // Additionally ensure that the default revision state is kept in sync.
-        if ($this->entity && $host->isDefaultRevision() != $this->entity->isDefaultRevision()) {
-          $this->entity->isDefaultRevision($host->isDefaultRevision());
+        elseif (!$host->wasDefaultRevision() && $host->isDefaultRevision() && !$this->entity->isDefaultRevision()) {
+          // Ensure that the default revision is synced when the parent changes.
+          $this->entity->isDefaultRevision(TRUE);
           $needs_save = TRUE;
         }
       }
diff --git a/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php b/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php
index 6be1424..93f80f1 100644
--- a/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php
+++ b/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\entity_reference_revisions\Kernel;
 
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\entity_composite_relationship_test\Entity\EntityTestCompositeRelationship;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
@@ -77,6 +78,7 @@ class EntityReferenceRevisionsCompositeTest extends EntityKernelTestBase {
       'settings' => array(
         'target_type' => 'entity_test_composite'
       ),
+      'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
     ));
     $field_storage->save();
     $field = FieldConfig::create(array(
@@ -452,6 +454,73 @@ class EntityReferenceRevisionsCompositeTest extends EntityKernelTestBase {
     // Ensure the second revision still exists.
     $composite2_revision = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($composite2_rev_id);
     $this->assertNotNull($composite2_revision);
+
+    // Set a new pending revision, composite entity should have a new revision
+    // as well, but it should not be the default.
+    $node->setNewRevision(TRUE);
+    $node->isDefaultRevision(FALSE);
+    $second_composite_name = $this->randomMachineName();
+    // Add another composite entity, which will be a default revision.
+    $second_composite = EntityTestCompositeRelationship::create([
+      'uuid' => $this->randomMachineName(),
+      'name' => $second_composite_name,
+    ]);
+    $node->composite_reference[1] = $second_composite;
+    $node->save();
+    // Ensure that we saved a new revision ID, the first composite is not the
+    // default, but the second one is.
+    $node_latest_revision_id = $node->getRevisionId();
+    $composite3_rev_id = $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($composite->id());
+    $this->assertNotEquals($node_original_revision_id, $node_latest_revision_id);
+    $this->assertNotEquals($composite3_rev_id, $composite2_rev_id);
+    $composite3_revision = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($composite3_rev_id);
+    $this->assertFalse($composite3_revision->isDefaultRevision());
+    $this->assertSame($second_composite_name, $second_composite->label());
+
+    // Update the pending revision, ensuring updates persist.
+    $second_composite_rev_id = $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($second_composite->id());
+    $first_composite_new_name = $this->randomMachineName();
+    $second_composite_new_name = $this->randomMachineName();
+    $node->composite_reference[0]->entity->name->value = $first_composite_new_name;
+    $node->composite_reference[0]->entity->setNeedsSave(TRUE);
+    $node->composite_reference[1]->entity->name->value = $second_composite_new_name;
+    $node->composite_reference[1]->entity->setNeedsSave(TRUE);
+    $node->save();
+
+    $this->assertEquals($node_latest_revision_id, $node->getRevisionId());
+    // The first composite was updated, and not made a default revision.
+    $this->assertEquals($composite3_rev_id, $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($composite->id()));
+    $this->assertEquals($second_composite_rev_id, $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($second_composite->id()));
+    $composite3_revision = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($composite3_rev_id);
+    $this->assertFalse($composite3_revision->isDefaultRevision());
+    $this->assertEquals($first_composite_new_name, $composite3_revision->label());
+    // The second composite was updated, and stayed the default revision.
+    $second_composite = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($second_composite_rev_id);
+    $this->assertTrue($second_composite->isDefaultRevision());
+    $this->assertEquals($second_composite_new_name, $second_composite->label());
+
+    // Make the pending revision default, ensuring updates persist.
+    // Change the name of the first composite, it should be saved automatically
+    // because it must become the default revision.
+    $first_composite_new_name = $this->randomMachineName();
+    $node->composite_reference[0]->entity->name->value = $first_composite_new_name;
+    $node->isDefaultRevision(TRUE);
+    $node->save();
+
+    // The node did not get a new revision.
+    $this->assertEquals($node_latest_revision_id, $node->getRevisionId());
+    $this->assertTrue($node->isDefaultRevision());
+    // The first composite was updated, and made a default revision.
+    $this->assertEquals($composite3_rev_id, $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($composite->id()));
+    $composite3_revision = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($composite3_rev_id);
+    $this->assertTrue($composite3_revision->isDefaultRevision());
+    $this->assertEquals($first_composite_new_name, $composite3_revision->label());
+    // The second composite stayed the default revision.
+    $this->assertEquals($second_composite_rev_id, $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($second_composite->id()));
+    $second_composite = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($second_composite_rev_id);
+    $this->assertTrue($second_composite->isDefaultRevision());
+    $this->assertEquals($second_composite_new_name, $second_composite->label());
+
   }
 
   /**
-- 
GitLab


From b7746d24dd4c81b4dac70ccefb4829d2c6970711 Mon Sep 17 00:00:00 2001
From: Henrik Danielsson <h.danielsson@gmail.com>
Date: Sun, 17 Dec 2023 07:40:10 +0100
Subject: [PATCH 2/2] Fix tests by switching to a field with dedicated table
 storage

---
 .../EntityReferenceRevisionsCompositeTest.php | 48 ++++++++++++-------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php b/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php
index 93f80f1..bb3f274 100644
--- a/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php
+++ b/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\entity_reference_revisions\Kernel;
 
+use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\entity_composite_relationship_test\Entity\EntityTestCompositeRelationship;
 use Drupal\field\Entity\FieldConfig;
@@ -64,6 +65,10 @@ class EntityReferenceRevisionsCompositeTest extends EntityKernelTestBase {
   protected function setUp(): void {
     parent::setUp();
 
+    $definitions['dedicated_table_field'] = BaseFieldDefinition::create('string')
+      ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
+      ->setRevisionable(TRUE);
+    $this->container->get('state')->set('entity_test_composite.additional_base_field_definitions', $definitions);
     $this->installEntitySchema('entity_test_composite');
     $this->installSchema('node', ['node_access']);
 
@@ -459,11 +464,12 @@ class EntityReferenceRevisionsCompositeTest extends EntityKernelTestBase {
     // as well, but it should not be the default.
     $node->setNewRevision(TRUE);
     $node->isDefaultRevision(FALSE);
-    $second_composite_name = $this->randomMachineName();
+    $second_composite_value = $this->randomMachineName();
     // Add another composite entity, which will be a default revision.
     $second_composite = EntityTestCompositeRelationship::create([
       'uuid' => $this->randomMachineName(),
-      'name' => $second_composite_name,
+      'name' => $this->randomMachineName(),
+      'dedicated_table_field' => $second_composite_value
     ]);
     $node->composite_reference[1] = $second_composite;
     $node->save();
@@ -475,38 +481,45 @@ class EntityReferenceRevisionsCompositeTest extends EntityKernelTestBase {
     $this->assertNotEquals($composite3_rev_id, $composite2_rev_id);
     $composite3_revision = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($composite3_rev_id);
     $this->assertFalse($composite3_revision->isDefaultRevision());
-    $this->assertSame($second_composite_name, $second_composite->label());
+    $second_composite_rev_id = $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($second_composite->id());
+    $second_composite = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($second_composite_rev_id);
+    $this->assertSame($second_composite_value, $second_composite->dedicated_table_field->value);
+    $this->assertTrue($second_composite->isDefaultRevision());
+
+    $node = $this->entityTypeManager->getStorage('node')->loadRevision($node_latest_revision_id);
 
     // Update the pending revision, ensuring updates persist.
-    $second_composite_rev_id = $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($second_composite->id());
-    $first_composite_new_name = $this->randomMachineName();
-    $second_composite_new_name = $this->randomMachineName();
-    $node->composite_reference[0]->entity->name->value = $first_composite_new_name;
+    $first_composite_new_value = $this->randomMachineName();
+    $second_composite_new_value = $this->randomMachineName();
+    $node->composite_reference[0]->entity->dedicated_table_field->value = $first_composite_new_value;
     $node->composite_reference[0]->entity->setNeedsSave(TRUE);
-    $node->composite_reference[1]->entity->name->value = $second_composite_new_name;
+    $node->composite_reference[1]->entity->dedicated_table_field->value = $second_composite_new_value;
     $node->composite_reference[1]->entity->setNeedsSave(TRUE);
     $node->save();
-
     $this->assertEquals($node_latest_revision_id, $node->getRevisionId());
     // The first composite was updated, and not made a default revision.
     $this->assertEquals($composite3_rev_id, $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($composite->id()));
     $this->assertEquals($second_composite_rev_id, $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($second_composite->id()));
     $composite3_revision = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($composite3_rev_id);
     $this->assertFalse($composite3_revision->isDefaultRevision());
-    $this->assertEquals($first_composite_new_name, $composite3_revision->label());
+    $this->assertEquals($first_composite_new_value, $composite3_revision->dedicated_table_field->value);
     // The second composite was updated, and stayed the default revision.
+    $this->entityTypeManager->getStorage('entity_test_composite')->resetCache([$second_composite->id()]);
     $second_composite = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($second_composite_rev_id);
     $this->assertTrue($second_composite->isDefaultRevision());
-    $this->assertEquals($second_composite_new_name, $second_composite->label());
+    $this->assertEquals($second_composite_new_value, $second_composite->dedicated_table_field->value);
+    // Actually loading the default revision produces the same result.
+    $second_composite_default = $this->entityTypeManager->getStorage('entity_test_composite')->load($second_composite->id());
+    $this->assertEquals($second_composite_rev_id, $second_composite_default->getRevisionId());
+    $this->assertEquals($second_composite_new_value, $second_composite_default->dedicated_table_field->value);
 
     // Make the pending revision default, ensuring updates persist.
-    // Change the name of the first composite, it should be saved automatically
+    // Change the value of the first composite, it should be saved automatically
     // because it must become the default revision.
-    $first_composite_new_name = $this->randomMachineName();
-    $node->composite_reference[0]->entity->name->value = $first_composite_new_name;
+    $first_composite_new_value = $this->randomMachineName();
+    $node->composite_reference[0]->entity->dedicated_table_field->value = $first_composite_new_value;
     $node->isDefaultRevision(TRUE);
     $node->save();
-
     // The node did not get a new revision.
     $this->assertEquals($node_latest_revision_id, $node->getRevisionId());
     $this->assertTrue($node->isDefaultRevision());
@@ -514,13 +527,12 @@ class EntityReferenceRevisionsCompositeTest extends EntityKernelTestBase {
     $this->assertEquals($composite3_rev_id, $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($composite->id()));
     $composite3_revision = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($composite3_rev_id);
     $this->assertTrue($composite3_revision->isDefaultRevision());
-    $this->assertEquals($first_composite_new_name, $composite3_revision->label());
+    $this->assertEquals($first_composite_new_value, $composite3_revision->dedicated_table_field->value);
     // The second composite stayed the default revision.
     $this->assertEquals($second_composite_rev_id, $this->entityTypeManager->getStorage('entity_test_composite')->getLatestRevisionId($second_composite->id()));
     $second_composite = $this->entityTypeManager->getStorage('entity_test_composite')->loadRevision($second_composite_rev_id);
     $this->assertTrue($second_composite->isDefaultRevision());
-    $this->assertEquals($second_composite_new_name, $second_composite->label());
-
+    $this->assertEquals($second_composite_new_value, $second_composite->dedicated_table_field->value);
   }
 
   /**
-- 
GitLab

