diff --git a/core/core.services.yml b/core/core.services.yml index 439b1ef..17cbdaf 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -514,6 +514,9 @@ services: # @todo Remove this tag in https://www.drupal.org/node/2549143. tags: - { name: plugin_manager_cache_clear } + entity.revisionable_schema_converter: + class: Drupal\Core\Entity\RevisionableSchemaConverter + arguments: ['@entity.last_installed_schema.repository', '@entity_type.manager', '@entity.definition_update_manager', '@entity_field.manager', '@database'] entity_type.manager: class: Drupal\Core\Entity\EntityTypeManager arguments: ['@container.namespaces', '@module_handler', '@cache.discovery', '@string_translation', '@class_resolver'] diff --git a/core/lib/Drupal/Core/Entity/RevisionableSchemaConverter.php b/core/lib/Drupal/Core/Entity/RevisionableSchemaConverter.php index e69de29..cf9cb5b 100644 --- a/core/lib/Drupal/Core/Entity/RevisionableSchemaConverter.php +++ b/core/lib/Drupal/Core/Entity/RevisionableSchemaConverter.php @@ -0,0 +1,184 @@ +lastInstalledSchemaRepository = $last_installed_schema_repository; + $this->entityTypeManager = $entity_type_manager; + $this->entityDefinitionUpdateManager = $entity_definition_update_manager; + $this->entityFieldManager = $entity_field_manager; + $this->database = $database; + } + + /** + * {@inheritdoc} + */ + public function updateEntityType(EntityTypeInterface $entity_type) { + $last_entity_type = $this->lastInstalledSchemaRepository->getLastInstalledDefinition($entity_type->id()); + $keys = $last_entity_type->getKeys(); + $keys['revision'] = 'revision_id'; + $last_entity_type->set('entity_keys', $keys); + $last_entity_type->set('revision_table', $entity_type->getRevisionTable()); + $last_entity_type->set('revision_data_table', $entity_type->getRevisionDataTable()); + $this->lastInstalledSchemaRepository->setLastInstalledDefinition($last_entity_type); + } + + /** + * {@inheritdoc} + */ + public function createTables(EntityTypeInterface $entity_type) { + /** @var \Drupal\Core\Entity\EntityTypeListenerInterface $storage */ + $storage = $this->entityTypeManager->getStorage($entity_type->id()); + if ($storage instanceof EntityTypeListenerInterface) { + $storage->onEntityTypeCreate($entity_type); + } + } + + /** + * {@inheritdoc} + */ + public function installFields(EntityTypeInterface $entity_type) { + if ($entity_type->hasKey('revision')) { + $revision_id = BaseFieldDefinition::create('integer') + ->setLabel(new TranslatableMarkup('Revision ID')) + ->setReadOnly(TRUE) + ->setSetting('unsigned', TRUE); + $this->entityDefinitionUpdateManager + ->installFieldStorageDefinition($entity_type->getKey('revision'), $entity_type->id(), $entity_type->id(), $revision_id); + + } + + $revision_created = BaseFieldDefinition::create('created') + ->setLabel(t('Revision create time')) + ->setDescription(t('The time that the current revision was created.')) + ->setRevisionable(TRUE); + $this->entityDefinitionUpdateManager + ->installFieldStorageDefinition("revision_created", $entity_type->id(), $entity_type->id(), $revision_created); + + $revision_user = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Revision user')) + ->setDescription(t('The user ID of the author of the current revision.')) + ->setSetting('target_type', 'user') + ->setRevisionable(TRUE); + $this->entityDefinitionUpdateManager + ->installFieldStorageDefinition("revision_user", $entity_type->id(), $entity_type->id(), $revision_user); + + $revision_log_message = BaseFieldDefinition::create('string_long') + ->setLabel(t('Revision log message')) + ->setDescription(t('Briefly describe the changes you have made.')) + ->setRevisionable(TRUE) + ->setDefaultValue('') + ->setDisplayOptions('form', [ + 'type' => 'string_textarea', + 'weight' => 25, + 'settings' => [ + 'rows' => 4, + ], + ]); + $this->entityDefinitionUpdateManager + ->installFieldStorageDefinition("revision_log_message", $entity_type->id(), $entity_type->id(), $revision_log_message); + + /** @var \Drupal\Core\Field\FieldDefinitionInterface[] $field_definitions */ + $field_definitions = $this->entityFieldManager->getBaseFieldDefinitions($entity_type->id()); + foreach ($field_definitions as $field_definition) { + $this->entityDefinitionUpdateManager->updateFieldStorageDefinition($field_definition); + } + + $revision_data_table = $entity_type->getRevisionDataTable(); + $schema = $this->database->schema(); + $schema->dropPrimaryKey($revision_data_table); + $schema->addPrimaryKey($revision_data_table, [$entity_type->getKey('revision'), $entity_type->getKey('langcode')]); + } + + /** + * {@inheritdoc} + */ + public function copyData(EntityTypeInterface $entity_type) { + /** @var \Drupal\Core\Entity\Sql\TableMappingInterface $table_mapping */ + $table_mapping = $this->entityTypeManager->getStorage($entity_type->id())->getTableMapping(); + $table_names = $table_mapping->getTableNames(); + $data = []; + foreach ($table_names as $table_name) { + $column_names = $table_mapping->getAllColumns($table_name); + $results = $this->database->select($table_name, 't')->fields('t')->execute()->fetchAll(); + foreach ($results as $key => $result) { + foreach ($column_names as $column_name) { + if (!empty($result->{$column_name})) { + $data[$key][$column_name] = $result->{$column_name}; + } + } + } + } + + $id = $entity_type->getKey('id'); + $revision_id = $entity_type->getKey('revision'); + foreach ($data as $record) { + if (!empty($record[$id])) { + $record[$revision_id] = $record[$id]; + } + foreach ($table_names as $table_name) { + $values = []; + $column_names = $table_mapping->getAllColumns($table_name); + foreach ($column_names as $column_name) { + if (!empty($record[$column_name])) { + $values[$column_name] = $record[$column_name]; + } + } + $query = $this->database->select($table_name)->fields($table_name, [$id])->condition($id, $record[$id]); + $exists = $query->execute()->fetchAll(); + if (isset($exists) && isset($exists[0]) && ($exists[0]->{$id} == $record[$id])) { + $this->database + ->update($table_name) + ->fields($values) + ->condition($id, $record[$id]) + ->execute(); + } + else { + $this->database + ->insert($table_name) + ->fields($values) + ->execute(); + } + } + } + } +} diff --git a/core/lib/Drupal/Core/Entity/RevisionableSchemaConverterInterface.php b/core/lib/Drupal/Core/Entity/RevisionableSchemaConverterInterface.php index e69de29..2315bfb 100644 --- a/core/lib/Drupal/Core/Entity/RevisionableSchemaConverterInterface.php +++ b/core/lib/Drupal/Core/Entity/RevisionableSchemaConverterInterface.php @@ -0,0 +1,35 @@ +getStorage('shortcut')->getEntityType(); - \Drupal::service('system.entity_schema_updater')->updateEntityType($entity_type); - \Drupal::service('system.entity_schema_updater')->createTables($entity_type); - \Drupal::service('system.entity_schema_updater')->installFields($entity_type); - \Drupal::service('system.entity_schema_updater')->copyData($entity_type); + \Drupal::service('entity.revisionable_schema_converter')->updateEntityType($entity_type); + \Drupal::service('entity.revisionable_schema_converter')->createTables($entity_type); + \Drupal::service('entity.revisionable_schema_converter')->installFields($entity_type); + \Drupal::service('entity.revisionable_schema_converter')->copyData($entity_type); } diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml index 93ac9a8..c70889d 100644 --- a/core/modules/system/system.services.yml +++ b/core/modules/system/system.services.yml @@ -43,6 +43,3 @@ services: arguments: ['@theme_handler', '@cache_tags.invalidator'] tags: - { name: event_subscriber } - system.entity_schema_updater: - class: Drupal\system\EntitySchemaUpdater - arguments: ['@entity.last_installed_schema.repository', '@entity_type.manager', '@entity.definition_update_manager', '@entity_field.manager', '@database'] diff --git a/core/tests/Drupal/Tests/Core/Entity/RevisionableSchemaConverterTest.php b/core/tests/Drupal/Tests/Core/Entity/RevisionableSchemaConverterTest.php index e69de29..7cfaa9f 100644 --- a/core/tests/Drupal/Tests/Core/Entity/RevisionableSchemaConverterTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/RevisionableSchemaConverterTest.php @@ -0,0 +1,40 @@ +databaseDumpFiles = [__DIR__ . '/../../../../../modules/system/tests/fixtures/update/drupal-8.bare.standard.php.gz']; + } + + public function testMakeRevisionable() { + $entity_type = \Drupal::entityTypeManager()->getStorage('shortcut')->getEntityType(); + + /** @var ContentEntityInterface $last_installed */ + $pre_last_installed = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledDefinition($entity_type->id()); + $this->assertFalse($pre_last_installed->isRevisionable()); + + $this->runUpdates(); + + /** @var ContentEntityInterface $last_installed */ + $post_last_installed = \Drupal::service('entity.last_installed_schema.repository')->getLastInstalledDefinition($entity_type->id()); + $this->assertTrue($post_last_installed->isRevisionable()); + + $storage = \Drupal::entityTypeManager()->getStorage($entity_type->id()); + $entities = $storage->loadMultiple(); + $this->assertEqual(count($entities), 2, "Two Shortcut entities found"); + + } + +}