Commit b43bf88c authored by alexpott's avatar alexpott
Browse files

Issue #2340993 by Berdir:...

Issue #2340993 by Berdir: SqlContentEntityStorageSchema::requiresEntityDataMigration() returns TRUE for cases where it should return FALSE
parent 6a002ab5
......@@ -128,13 +128,30 @@ protected function installedStorageSchema() {
*/
public function requiresEntityStorageSchemaChanges(EntityTypeInterface $entity_type, EntityTypeInterface $original) {
return
$entity_type->isRevisionable() != $original->isRevisionable() ||
$entity_type->isTranslatable() != $original->isTranslatable() ||
$this->hasSharedTableNameChanges($entity_type, $original) ||
$this->hasSharedTableStructureChange($entity_type, $original) ||
// Detect changes in key or index definitions.
$this->getEntitySchemaData($entity_type, $this->getEntitySchema($entity_type, TRUE)) != $this->loadEntitySchemaData($original);
}
/**
* Detects whether there is a change in the shared table structure.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The new entity type.
* @param \Drupal\Core\Entity\EntityTypeInterface $original
* The origin entity type.
*
* @return bool
* Returns TRUE if either the revisionable or translatable flag changes or
* a table has been renamed.
*/
protected function hasSharedTableStructureChange(EntityTypeInterface $entity_type, EntityTypeInterface $original) {
return
$entity_type->isRevisionable() != $original->isRevisionable() ||
$entity_type->isTranslatable() != $original->isTranslatable() ||
$this->hasSharedTableNameChanges($entity_type, $original);
}
/**
* Detects whether any table name got renamed in an entity type update.
*
......@@ -203,6 +220,13 @@ public function requiresEntityDataMigration(EntityTypeInterface $entity_type, En
if (!class_exists($original_storage_class)) {
return TRUE;
}
// Data migration is not needed when only indexes changed, as they can be
// applied if there is data.
if (!$this->hasSharedTableStructureChange($entity_type, $original)) {
return FALSE;
}
// Use the original entity type since the storage has not been updated.
$original_storage = $this->entityManager->createHandlerInstance($original_storage_class, $original);
return $original_storage->hasData();
......
......@@ -518,19 +518,11 @@ public function testEntityIndexCreateWithData() {
$entity = $this->entityManager->getStorage('entity_test_update')->create(array('name' => $name));
$entity->save();
// Add an entity index, run the update. For now, it's expected to throw an
// exception.
// @todo Improve SqlContentEntityStorageSchema::requiresEntityDataMigration()
// to return FALSE when only index changes are required, so that it can be
// applied on top of existing data: https://www.drupal.org/node/2340993.
// Add an entity index, run the update. Ensure that the index is created
// despite having data.
$this->addEntityIndex();
try {
$this->entityDefinitionUpdateManager->applyUpdates();
$this->fail('EntityStorageException thrown when trying to apply an update that requires data migration.');
}
catch (EntityStorageException $e) {
$this->pass('EntityStorageException thrown when trying to apply an update that requires data migration.');
}
$this->entityDefinitionUpdateManager->applyUpdates();
$this->assertTrue($this->database->schema()->indexExists('entity_test_update', 'entity_test_update__new_index'), 'Index added.');
}
/**
......
......@@ -1054,15 +1054,22 @@ public function providerTestRequiresEntityDataMigration() {
return [
// Case 1: same storage class, ::hasData() === TRUE.
[$updated_entity_type_definition, $original_entity_type_definition, TRUE, TRUE],
[$updated_entity_type_definition, $original_entity_type_definition, TRUE, TRUE, TRUE],
// Case 2: same storage class, ::hasData() === FALSE.
[$updated_entity_type_definition, $original_entity_type_definition, FALSE, FALSE],
[$updated_entity_type_definition, $original_entity_type_definition, FALSE, TRUE, FALSE],
// Case 3: different storage class, original storage class does not exist.
[$updated_entity_type_definition, $original_entity_type_definition_other_nonexisting, NULL, TRUE],
// Case 4: different storage class, original storage class exists, ::hasData() === TRUE.
[$updated_entity_type_definition, $original_entity_type_definition_other_existing, TRUE, TRUE],
// Case 5: different storage class, original storage class exists, ::hasData() === FALSE.
[$updated_entity_type_definition, $original_entity_type_definition_other_existing, FALSE, FALSE],
[$updated_entity_type_definition, $original_entity_type_definition_other_nonexisting, NULL, TRUE, TRUE],
// Case 4: different storage class, original storage class exists,
// ::hasData() === TRUE.
[$updated_entity_type_definition, $original_entity_type_definition_other_existing, TRUE, TRUE, TRUE],
// Case 5: different storage class, original storage class exists,
// ::hasData() === FALSE.
[$updated_entity_type_definition, $original_entity_type_definition_other_existing, FALSE, TRUE, FALSE],
// Case 6: same storage class, ::hasData() === TRUE, no structure changes.
[$updated_entity_type_definition, $original_entity_type_definition, TRUE, FALSE, FALSE],
// Case 7: different storage class, original storage class exists,
//::hasData() === TRUE, no structure changes.
[$updated_entity_type_definition, $original_entity_type_definition_other_existing, TRUE, FALSE, FALSE],
];
}
......@@ -1071,7 +1078,7 @@ public function providerTestRequiresEntityDataMigration() {
*
* @dataProvider providerTestRequiresEntityDataMigration
*/
public function testRequiresEntityDataMigration($updated_entity_type_definition, $original_entity_type_definition, $original_storage_has_data, $migration_required) {
public function testRequiresEntityDataMigration($updated_entity_type_definition, $original_entity_type_definition, $original_storage_has_data, $shared_table_structure_changed, $migration_required) {
$this->entityType = new ContentEntityType(array(
'id' => 'entity_test',
'entity_keys' => array('id' => 'id'),
......@@ -1081,7 +1088,7 @@ public function testRequiresEntityDataMigration($updated_entity_type_definition,
->disableOriginalConstructor()
->getMock();
$original_storage->expects($this->exactly(is_null($original_storage_has_data) ? 0 : 1))
$original_storage->expects($this->exactly(is_null($original_storage_has_data) || !$shared_table_structure_changed ? 0 : 1))
->method('hasData')
->willReturn($original_storage_has_data);
......@@ -1099,9 +1106,14 @@ public function testRequiresEntityDataMigration($updated_entity_type_definition,
$this->storageSchema = $this->getMockBuilder('Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema')
->setConstructorArgs(array($this->entityManager, $this->entityType, $this->storage, $connection))
->setMethods(array('installedStorageSchema'))
->setMethods(array('installedStorageSchema', 'hasSharedTableStructureChange'))
->getMock();
$this->storageSchema->expects($this->any())
->method('hasSharedTableStructureChange')
->with($updated_entity_type_definition, $original_entity_type_definition)
->willReturn($shared_table_structure_changed);
$this->assertEquals($migration_required, $this->storageSchema->requiresEntityDataMigration($updated_entity_type_definition, $original_entity_type_definition));
}
......
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