diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index 3effe8b3c2..12b9324402 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -331,6 +331,20 @@ public function isDefaultRevision($new_value = NULL) { return $this->isNew() || $return; } + /** + * {@inheritdoc} + */ + public function wasDefaultRevision() { + if (!$this->getEntityType()->isRevisionable()) { + throw new \LogicException("Entity type {$this->getEntityTypeId()} does not support revisions."); + } + $value = $this->get('default_revision')->value; + if (isset($value)) { + return (bool) $value; + } + throw new \LogicException("Missing data for the \"default_revision\" field on the entity {$this->getEntityTypeId()}:{$this->id()}."); + } + /** * {@inheritdoc} */ @@ -1269,23 +1283,33 @@ protected function getEntityKey($key) { */ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields = []; + if ($entity_type->hasKey('id')) { $fields[$entity_type->getKey('id')] = BaseFieldDefinition::create('integer') ->setLabel(new TranslatableMarkup('ID')) ->setReadOnly(TRUE) ->setSetting('unsigned', TRUE); } + if ($entity_type->hasKey('uuid')) { $fields[$entity_type->getKey('uuid')] = BaseFieldDefinition::create('uuid') ->setLabel(new TranslatableMarkup('UUID')) ->setReadOnly(TRUE); } - if ($entity_type->hasKey('revision')) { + + if ($entity_type->isRevisionable()) { $fields[$entity_type->getKey('revision')] = BaseFieldDefinition::create('integer') ->setLabel(new TranslatableMarkup('Revision ID')) ->setReadOnly(TRUE) ->setSetting('unsigned', TRUE); + + $fields['default_revision'] = BaseFieldDefinition::create('boolean') + ->setLabel(new TranslatableMarkup('Default revision')) + ->setDescription(new TranslatableMarkup('A flag indicating whether this was a default revision when it was saved.')) + ->setTranslatable(FALSE) + ->setRevisionable(TRUE); } + if ($entity_type->hasKey('langcode')) { $fields[$entity_type->getKey('langcode')] = BaseFieldDefinition::create('language') ->setLabel(new TranslatableMarkup('Language')) @@ -1303,6 +1327,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields[$entity_type->getKey('langcode')]->setTranslatable(TRUE); } } + if ($entity_type->hasKey('bundle')) { if ($bundle_entity_type_id = $entity_type->getBundleEntityType()) { $fields[$entity_type->getKey('bundle')] = BaseFieldDefinition::create('entity_reference') diff --git a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php index 3053d23694..e85a299312 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityInterface.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityInterface.php @@ -106,4 +106,16 @@ public function getLoadedRevisionId(); */ public function updateLoadedRevisionId(); + /** + * Checks whether the entity object was a default revision when it was saved. + * + * @return bool + * TRUE if the entity object was a revision, FALSE otherwise. + * + * @throws \LogicException + * If the entity type is not revisionable or the default revision data is + * missing. + */ + public function wasDefaultRevision(); + } diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php index a3bb20508f..8803d36802 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php @@ -334,6 +334,9 @@ protected function doSave($id, EntityInterface $entity) { } $this->populateAffectedRevisionTranslations($entity); + if ($this->entityType->isRevisionable()) { + $entity->set('default_revision', $entity->isDefaultRevision()); + } $this->doSaveFieldItems($entity); return $return; diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php index 60712eeb21..3b15161380 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchemaConverter.php @@ -293,6 +293,10 @@ protected function copyData(array &$sandbox) { // returned was always TRUE. $entity->set($revision_translation_affected_key, TRUE); + // We cannot know what type the revision was so we assume the core + // default behavior of always creating a default revision. + $entity->set('default_revision', TRUE); + // Treat the entity as new in order to make the storage do an INSERT // rather than an UPDATE. $entity->enforceIsNew(TRUE); @@ -380,6 +384,20 @@ protected function updateFieldStorageDefinitionsToRevisionable(ContentEntityType } $updated_storage_definitions[$entity_type->getKey('revision')] = $revision_field; + // Add the default revision flag. + $field_name = 'default_revision'; + $default_revision_field = BaseFieldDefinition::create('boolean') + ->setName($field_name) + ->setLabel(new TranslatableMarkup('Default revision')) + ->setDescription(new TranslatableMarkup('A flag indicating whether this was a default revision when it was saved.')) + ->setTranslatable(FALSE) + ->setRevisionable(TRUE); + + if ($update_cached_definitions) { + $this->entityDefinitionUpdateManager->installFieldStorageDefinition($default_revision_field->getName(), $entity_type->id(), $entity_type->getProvider(), $default_revision_field); + } + $updated_storage_definitions[$default_revision_field->getName()] = $default_revision_field; + // Add the 'revision_translation_affected' field if needed. if ($entity_type->isTranslatable()) { $revision_translation_affected_field = BaseFieldDefinition::create('boolean') diff --git a/core/modules/rest/tests/src/Functional/EntityResource/BlockContent/BlockContentResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/BlockContent/BlockContentResourceTestBase.php index 5d7329feb9..c652a2c4be 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/BlockContent/BlockContentResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/BlockContent/BlockContentResourceTestBase.php @@ -121,6 +121,11 @@ protected function getExpectedNormalizedEntity() { 'value' => TRUE, ], ], + 'default_revision' => [ + [ + 'value' => TRUE, + ], + ], 'default_langcode' => [ [ 'value' => TRUE, diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Media/MediaResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/Media/MediaResourceTestBase.php index 1875d004a4..b84c96632e 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/Media/MediaResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/Media/MediaResourceTestBase.php @@ -212,6 +212,11 @@ protected function getExpectedNormalizedEntity() { 'value' => TRUE, ], ], + 'default_revision' => [ + [ + 'value' => TRUE, + ], + ], ]; } 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 492ff642e4..fa972eaa6a 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/Node/NodeResourceTestBase.php @@ -152,6 +152,11 @@ protected function getExpectedNormalizedEntity() { 'value' => TRUE, ], ], + 'default_revision' => [ + [ + 'value' => TRUE, + ], + ], 'default_langcode' => [ [ 'value' => TRUE, diff --git a/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php b/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php index 5b71b93b7a..88039ba799 100644 --- a/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php +++ b/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php @@ -129,6 +129,9 @@ public function testNormalize() { 'revision_translation_affected' => [ ['value' => TRUE], ], + 'default_revision' => [ + ['value' => TRUE], + ], 'non_rev_field' => [], 'field_test_text' => [ [ @@ -201,6 +204,7 @@ public function testSerialize() { 'revision_id' => '' . $this->entity->getRevisionId() . '', 'default_langcode' => '1', 'revision_translation_affected' => '1', + 'default_revision' => '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/system.install b/core/modules/system/system.install index ef6f124f51..38c63517f7 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -2056,3 +2056,39 @@ function system_update_8403() { } } } + +/** + * Add the 'revision_type' field to all entity types. + */ +function system_update_8501() { + /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */ + $field_manager = \Drupal::service('entity_field.manager'); + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + + // Get a list of entity types to process. + /** @var \Drupal\Core\Entity\ContentEntityTypeInterface[] $definitions */ + $definitions = array_filter(\Drupal::entityTypeManager()->getDefinitions(), function (EntityTypeInterface $entity_type) use ($field_manager, $definition_update_manager) { + $entity_type_id = $entity_type->id(); + if ($entity_type = $definition_update_manager->getEntityType($entity_type_id)) { + $field_name = 'default_revision'; + return $entity_type->isRevisionable() + && isset($field_manager->getFieldStorageDefinitions($entity_type_id)[$field_name]) + && !$definition_update_manager->getFieldStorageDefinition($field_name, $entity_type_id); + } + return FALSE; + }); + + $storage_definition = BaseFieldDefinition::create('boolean') + ->setLabel(t('Default revision')) + ->setDescription(t('A flag indicating whether this was a default revision when it was saved.')) + ->setTranslatable(FALSE) + ->setRevisionable(TRUE) + ->setInitialValue(TRUE); + + // Install the 'default_revision' field. + foreach ($definitions as $entity_type_id => $entity_type) { + $field_name = 'default_revision'; + $definition_update_manager + ->installFieldStorageDefinition($field_name, $entity_type_id, $entity_type_id, $storage_definition); + } +} diff --git a/core/modules/system/tests/modules/entity_test_update/src/Entity/EntityTestUpdate.php b/core/modules/system/tests/modules/entity_test_update/src/Entity/EntityTestUpdate.php index 286e8e62bd..175bc7ad80 100644 --- a/core/modules/system/tests/modules/entity_test_update/src/Entity/EntityTestUpdate.php +++ b/core/modules/system/tests/modules/entity_test_update/src/Entity/EntityTestUpdate.php @@ -69,11 +69,17 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setDescription(new TranslatableMarkup('The bundle of the test entity.')) ->setRequired(TRUE); - if ($entity_type->hasKey('revision')) { + if ($entity_type->isRevisionable()) { $fields[$entity_type->getKey('revision')] = BaseFieldDefinition::create('integer') ->setLabel(new TranslatableMarkup('Revision ID')) ->setReadOnly(TRUE) ->setSetting('unsigned', TRUE); + + $fields['default_revision'] = BaseFieldDefinition::create('boolean') + ->setLabel(new TranslatableMarkup('Default revision')) + ->setDescription(new TranslatableMarkup('A flag indicating whether this was a default revision when it was saved.')) + ->setTranslatable(FALSE) + ->setRevisionable(TRUE); } $fields[$entity_type->getKey('langcode')] = BaseFieldDefinition::create('language')