Commit f6fa46e5 authored by catch's avatar catch

Issue #2721313 by timmillwood, amateescu, dawehner, jeqq, jibran, plach,...

Issue #2721313 by timmillwood, amateescu, dawehner, jeqq, jibran, plach, catch, jhedstrom: Upgrade path between revisionable / non-revisionable entities
parent eef585f6
......@@ -117,6 +117,13 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
*/
protected $languageManager;
/**
* Whether this storage should use the temporary table mapping.
*
* @var bool
*/
protected $temporary = FALSE;
/**
* {@inheritdoc}
*/
......@@ -266,6 +273,31 @@ public function setEntityType(EntityTypeInterface $entity_type) {
}
}
/**
* Sets the wrapped table mapping definition.
*
* @param \Drupal\Core\Entity\Sql\TableMappingInterface $table_mapping
* The table mapping.
*
* @internal Only to be used internally by Entity API. Expected to be removed
* by https://www.drupal.org/node/2554235.
*/
public function setTableMapping(TableMappingInterface $table_mapping) {
$this->tableMapping = $table_mapping;
}
/**
* Changes the temporary state of the storage.
*
* @param bool $temporary
* Whether to use a temporary table mapping or not.
*
* @internal Only to be used internally by Entity API.
*/
public function setTemporary($temporary) {
$this->temporary = $temporary;
}
/**
* {@inheritdoc}
*/
......@@ -279,8 +311,10 @@ public function getTableMapping(array $storage_definitions = NULL) {
// @todo Clean-up this in https://www.drupal.org/node/2274017 so we can
// easily instantiate a new table mapping whenever needed.
if (!isset($this->tableMapping) || $storage_definitions) {
$table_mapping_class = $this->temporary ? TemporaryTableMapping::class : DefaultTableMapping::class;
$definitions = $storage_definitions ?: $this->entityManager->getFieldStorageDefinitions($this->entityTypeId);
$table_mapping = new DefaultTableMapping($this->entityType, $definitions);
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping|\Drupal\Core\Entity\Sql\TemporaryTableMapping $table_mapping */
$table_mapping = new $table_mapping_class($this->entityType, $definitions);
$shared_table_definitions = array_filter($definitions, function (FieldStorageDefinitionInterface $definition) use ($table_mapping) {
return $table_mapping->allowsSharedTableStorage($definition);
......
......@@ -237,6 +237,12 @@ protected function getSchemaFromStorageDefinition(FieldStorageDefinitionInterfac
* {@inheritdoc}
*/
public function requiresEntityDataMigration(EntityTypeInterface $entity_type, EntityTypeInterface $original) {
// Check if the entity type specifies that data migration is being handled
// elsewhere.
if ($entity_type->get('requires_data_migration') === FALSE) {
return FALSE;
}
// If the original storage has existing entities, or it is impossible to
// determine if that is the case, require entity data to be migrated.
$original_storage_class = $original->getStorageClass();
......@@ -1212,10 +1218,14 @@ protected function deleteDedicatedTableSchema(FieldStorageDefinitionInterface $s
$deleted = !$this->originalDefinitions;
$table_mapping = $this->storage->getTableMapping();
$table_name = $table_mapping->getDedicatedDataTableName($storage_definition, $deleted);
$this->database->schema()->dropTable($table_name);
if ($this->database->schema()->tableExists($table_name)) {
$this->database->schema()->dropTable($table_name);
}
if ($this->entityType->isRevisionable()) {
$revision_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, $deleted);
$this->database->schema()->dropTable($revision_name);
$revision_table_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, $deleted);
if ($this->database->schema()->tableExists($revision_table_name)) {
$this->database->schema()->dropTable($revision_table_name);
}
}
$this->deleteFieldSchemaData($storage_definition);
}
......
<?php
namespace Drupal\Core\Entity\Sql;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
/**
* Defines a temporary table mapping class.
*/
class TemporaryTableMapping extends DefaultTableMapping {
/**
* {@inheritdoc}
*/
protected function generateFieldTableName(FieldStorageDefinitionInterface $storage_definition, $revision) {
return static::getTempTableName(parent::generateFieldTableName($storage_definition, $revision));
}
/**
* Generates a temporary table name.
*
* The method accounts for a maximum table name length of 64 characters.
*
* @param string $table_name
* The initial table name.
* @param string $prefix
* (optional) The prefix to use for the new table name. Defaults to 'tmp_'.
*
* @return string
* The final table name.
*/
public static function getTempTableName($table_name, $prefix = 'tmp_') {
$tmp_table_name = $prefix . $table_name;
// Limit the string to 48 characters, keeping a 16 characters margin for db
// prefixes.
if (strlen($table_name) > 48) {
$short_table_name = substr($table_name, 0, 34);
$table_hash = substr(hash('sha256', $table_name), 0, 10);
$tmp_table_name = $prefix . $short_table_name . $table_hash;
}
return $tmp_table_name;
}
}
<?php
// @codingStandardsIgnoreFile
use Drupal\Core\Database\Database;
$connection = Database::getConnection();
// Set the schema version.
$connection->merge('key_value')
->fields([
'value' => 'i:8000;',
'name' => 'entity_test_schema_converter',
'collection' => 'system.schema',
])
->condition('collection', 'system.schema')
->condition('name', 'entity_test_schema_converter')
->execute();
// Update core.extension.
$extensions = $connection->select('config')
->fields('config', ['data'])
->condition('collection', '')
->condition('name', 'core.extension')
->execute()
->fetchField();
$extensions = unserialize($extensions);
$extensions['module']['entity_test_schema_converter'] = 8000;
$connection->update('config')
->fields([
'data' => serialize($extensions),
'collection' => '',
'name' => 'core.extension',
])
->condition('collection', '')
->condition('name', 'core.extension')
->execute();
name: 'Entity Schema Converter Test'
type: module
description: 'Provides testing for the entity schema converter.'
package: Testing
version: VERSION
core: 8.x
dependencies:
- entity_test_update
\ No newline at end of file
<?php
/**
* @file
* Post update functions for entity_test_schema_converter.
*/
use \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchemaConverter;
/**
* @addtogroup updates-8.4.x
* @{
*/
/**
* Update entity_test_update to be revisionable.
*/
function entity_test_schema_converter_post_update_make_revisionable(&$sandbox) {
$revisionableSchemaConverter = new SqlContentEntityStorageSchemaConverter(
'entity_test_update',
\Drupal::entityTypeManager(),
\Drupal::entityDefinitionUpdateManager(),
\Drupal::service('entity.last_installed_schema.repository'),
\Drupal::keyValue('entity.storage_schema.sql'),
\Drupal::database()
);
$revisionableSchemaConverter->convertToRevisionable(
$sandbox,
[
'test_single_property',
'test_multiple_properties',
'test_single_property_multiple_values',
'test_multiple_properties_multiple_values',
'test_entity_base_field_info',
]);
}
/**
* @} End of "addtogroup updates-8.4.x".
*/
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment