diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 9f21344..47da72c 100644
--- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -308,6 +308,13 @@ public function getLatestRevisionId() {
/**
* {@inheritdoc}
*/
+ public function getLatestTranslationAffectedRevisionId() {
+ return $this->getEntityKey('latest_revision_translation_affected');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function isNewRevision() {
return $this->newRevision || ($this->getEntityType()->hasKey('revision') && !$this->getRevisionId());
}
@@ -1242,6 +1249,13 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
->setReadOnly(TRUE)
->setSetting('unsigned', TRUE);
}
+ if ($entity_type->hasKey('langcode') && $entity_type->hasKey('revision')) {
+ $fields[$entity_type->getKey('latest_revision_translation_affected')] = BaseFieldDefinition::create('integer')
+ ->setLabel(new TranslatableMarkup('Latest Revision Translation Affected'))
+ ->setReadOnly(TRUE)
+ ->setTranslatable(TRUE)
+ ->setSetting('unsigned', TRUE);
+ }
if ($entity_type->hasKey('langcode')) {
$fields[$entity_type->getKey('langcode')] = BaseFieldDefinition::create('language')
->setLabel(new TranslatableMarkup('Language'))
@@ -1299,6 +1313,7 @@ protected function getFieldsToSkipFromTranslationChangesCheck() {
$fields = [
$entity_type->getKey('revision'),
$entity_type->getKey('latest_revision'),
+ $entity_type->getKey('latest_revision_translation_affected'),
'revision_translation_affected',
];
$fields = array_merge($fields, array_values($entity_type->getRevisionMetadataKeys()));
diff --git a/core/lib/Drupal/Core/Entity/EntityType.php b/core/lib/Drupal/Core/Entity/EntityType.php
index e25b24c..f146c8e 100644
--- a/core/lib/Drupal/Core/Entity/EntityType.php
+++ b/core/lib/Drupal/Core/Entity/EntityType.php
@@ -303,6 +303,7 @@ public function __construct($definition) {
'langcode' => '',
'default_langcode' => 'default_langcode',
'latest_revision' => 'latest_revision',
+ 'latest_revision_translation_affected' => 'latest_revision_translation_affected',
];
$this->handlers += [
'access' => 'Drupal\Core\Entity\EntityAccessControlHandler',
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
index 04f6e94..566126a 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -62,6 +62,13 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
protected $latestRevisionKey;
/**
+ * Name of the entity's latest translation affected revision key if supported.
+ *
+ * @var string
+ */
+ protected $latestRevisionTranslationAffectedKey;
+
+ /**
* The entity langcode key.
*
* @var string|bool
@@ -178,6 +185,7 @@ protected function initTableLayout() {
$this->tableMapping = NULL;
$this->revisionKey = NULL;
$this->latestRevisionKey = NULL;
+ $this->latestRevisionTranslationAffectedKey = NULL;
$this->revisionTable = NULL;
$this->dataTable = NULL;
$this->revisionDataTable = NULL;
@@ -199,6 +207,7 @@ protected function initTableLayout() {
}
if ($revisionable && $translatable) {
$this->revisionDataTable = $this->entityType->getRevisionDataTable() ?: $this->entityTypeId . '_field_revision';
+ $this->latestRevisionTranslationAffectedKey = $this->entityType->getKey('latest_revision_translation_affected');
}
}
@@ -834,7 +843,7 @@ protected function doSaveFieldItems(ContentEntityInterface $entity, array $names
if ($default_revision && $this->dataTable) {
$this->saveToSharedTables($entity);
}
- if ($this->revisionTable && $this->latestRevisionKey && $entity->isNewRevision()) {
+ if ($this->latestRevisionKey && $entity->isNewRevision()) {
$this->database
->update($this->dataTable ? $this->dataTable : $this->baseTable)
->fields([$this->latestRevisionKey => $entity->{$this->revisionKey}->value])
@@ -842,6 +851,15 @@ protected function doSaveFieldItems(ContentEntityInterface $entity, array $names
->execute();
$entity->{$this->latestRevisionKey} = $entity->{$this->revisionKey}->value;
}
+ if ($this->latestRevisionTranslationAffectedKey && $entity->isNewRevision() && $entity->isRevisionTranslationAffected()) {
+ $this->database
+ ->update($this->dataTable ? $this->dataTable : $this->baseTable)
+ ->fields([$this->latestRevisionTranslationAffectedKey => $entity->{$this->revisionKey}->value])
+ ->condition($this->idKey, $record->{$this->idKey})
+ ->condition($this->langcodeKey, $entity->language()->getId())
+ ->execute();
+ $entity->{$this->latestRevisionTranslationAffectedKey} = $entity->{$this->revisionKey}->value;
+ }
if ($this->revisionDataTable) {
$new_revision = $full_save && $entity->isNewRevision();
$this->saveToSharedTables($entity, $this->revisionDataTable, $new_revision);
@@ -862,6 +880,7 @@ protected function doSaveFieldItems(ContentEntityInterface $entity, array $names
if ($this->revisionTable) {
$record->{$this->revisionKey} = $this->saveRevision($entity);
$entity->{$this->latestRevisionKey} = $record->{$this->revisionKey};
+ $entity->{$this->latestRevisionTranslationAffectedKey} = $record->{$this->revisionKey};
}
if ($this->dataTable) {
$this->saveToSharedTables($entity);
diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
index 78e1678..cc915c4 100644
--- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
@@ -1641,6 +1641,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st
// The latest revision key is stored in the data table and is also updated
// after a revision has been created.
unset($not_null_keys['latest_revision']);
+ unset($not_null_keys['latest_revision_translation_affected']);
foreach ($column_mapping as $field_column_name => $schema_field_name) {
$column_schema = $field_schema['columns'][$field_column_name];
diff --git a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
index 5b57a87..a9ff612 100644
--- a/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
+++ b/core/lib/Drupal/Core/TypedData/TranslatableInterface.php
@@ -113,4 +113,13 @@ public function removeTranslation($langcode);
*/
public function isTranslatable();
+ /**
+ * Get the latest translation affected revision for the loaded entity.
+ *
+ * @return int|null
+ * The latest revision that has been affected by translation or null if none
+ * exists.
+ */
+ public function getLatestTranslationAffectedRevisionId();
+
}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeResourceTestBase.php
index 55fe89d..d329b32 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeResourceTestBase.php
@@ -100,6 +100,9 @@ protected function getExpectedNormalizedEntity() {
'latest_revision' => [
['value' => 1],
],
+ 'latest_revision_translation_affected' => [
+ ['value' => 1],
+ ],
'langcode' => [
[
'value' => 'en',
diff --git a/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php b/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php
index e1070b0..89cfcc9 100644
--- a/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php
+++ b/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php
@@ -123,6 +123,12 @@ public function testNormalize() {
'latest_revision' => [
['value' => 1],
],
+ 'latest_revision_translation_affected' => [
+ ['value' => 1],
+ ],
+ 'revision_translation_affected' => [
+ ['value' => TRUE],
+ ],
'default_langcode' => [
['value' => TRUE],
],
@@ -195,6 +201,8 @@ public function testSerialize() {
'user_id' => '' . $this->user->id() . '' . $this->user->getEntityTypeId() . '' . $this->user->uuid() . '' . $this->user->url() . '',
'revision_id' => '' . $this->entity->getRevisionId() . '',
'latest_revision' => '' . $this->entity->getLatestRevisionId() . '',
+ 'revision_translation_affected' => '' . $this->entity->isRevisionTranslationAffected() . '',
+ 'latest_revision_translation_affected' => '' . $this->entity->getLatestTranslationAffectedRevisionId() . '',
'default_langcode' => '1',
'non_rev_field' => '',
'field_test_text' => '' . $this->values['field_test_text']['value'] . '' . $this->values['field_test_text']['format'] . '',
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php
index f01675f..a16a3f2 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php
@@ -1,6 +1,8 @@
setLabel(t('Revision translation affected'))
+ ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
+ ->setReadOnly(TRUE)
+ ->setRevisionable(TRUE)
+ ->setTranslatable(TRUE);
+ return $fields;
+ }
+
}
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityLatestRevisionTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityLatestRevisionTest.php
index c213911..49b6ab6 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityLatestRevisionTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityLatestRevisionTest.php
@@ -87,7 +87,7 @@ public function latestRevisionTestCases() {
/**
* Test the latest revision tracking with translations.
*/
- public function testWithTranslations() {
+ public function testLatestRevisionTranslations() {
$entity = EntityTestMulRev::create([]);
$entity->save();
$this->assertEquals(1, $entity->getLatestRevisionId());
@@ -110,4 +110,49 @@ public function testWithTranslations() {
$this->assertEquals(2, EntityTestMulRev::load(1)->getLatestRevisionId());
}
+ /**
+ * Test the latest_revision_translation_affected column.
+ */
+ public function testLatestRevisionTranslationAffected() {
+ $storage = $this->entityTypeManager->getStorage('entity_test_mulrev');
+
+ // Creating a new entity is translation affected.
+ $entity = EntityTestMulRev::create([
+ 'name' => 'Original Entity',
+ ]);
+ $entity->save();
+ $this->assertEquals(1, $entity->getLatestTranslationAffectedRevisionId());
+
+ // The first revision of a new entity is also translation affected.
+ $translated_entity = $entity->addTranslation('de', ['name' => 'Added Translation']);
+ $translated_entity->save();
+ $this->assertEquals(1, $entity->getLatestTranslationAffectedRevisionId());
+
+ // Create a forward revision of the translated entity.
+ $translated_entity->setNewRevision(TRUE);
+ $translated_entity->isDefaultRevision(FALSE);
+ $translated_entity->name = 'Translated Forward Revision';
+ $translated_entity->save();
+
+ // The latest translation affected entity will update for the translated
+ // version, but not the original.
+ $this->assertEquals(2, $translated_entity->getLatestTranslationAffectedRevisionId());
+ $reloaded_entity = $storage->load($entity->id());
+ $this->assertEquals(1, $reloaded_entity->getLatestTranslationAffectedRevisionId());
+ $this->assertEquals(2, $reloaded_entity->getLatestRevisionId());
+
+ // After reloading create a forward revision of the original entity.
+ $reloaded_entity->setNewRevision(TRUE);
+ $reloaded_entity->isDefaultRevision(FALSE);
+ $reloaded_entity->name = 'Updated Original Entity';
+ $reloaded_entity->save();
+
+ // Creating a forward revision of the original entity should not alter
+ // the latest translation affected revision of the translated entity.
+ $reloaded_translated_entity = $reloaded_entity->getTranslation('de');
+ $this->assertEquals(2, $reloaded_translated_entity->getLatestTranslationAffectedRevisionId());
+ $this->assertEquals(3, $reloaded_translated_entity->getLatestRevisionId());
+ $this->assertEquals(3, $reloaded_entity->getLatestRevisionId());
+ }
+
}
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityTypeTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityTypeTest.php
index 0e17181..6cc609f 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityTypeTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityTypeTest.php
@@ -58,7 +58,7 @@ public function testSet($key, $value) {
*/
public function testGetKeys($entity_keys, $expected) {
$entity_type = $this->setUpEntityType(['entity_keys' => $entity_keys]);
- $this->assertSame($expected + ['default_langcode' => 'default_langcode', 'latest_revision' => 'latest_revision'], $entity_type->getKeys());
+ $this->assertSame($expected + ['default_langcode' => 'default_langcode', 'latest_revision' => 'latest_revision', 'latest_revision_translation_affected' => 'latest_revision_translation_affected'], $entity_type->getKeys());
}
/**