diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php index a573a590f9..ecfa56409a 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Entity\Sql; +use Drupal\Component\Utility\NestedArray; use Drupal\Core\Database\Connection; use Drupal\Core\Database\DatabaseExceptionWrapper; use Drupal\Core\DependencyInjection\DependencySerializationTrait; @@ -717,7 +718,9 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res elseif ($table_mapping->allowsSharedTableStorage($this->fieldStorageDefinitions[$field_name])) { $column_names = $table_mapping->getColumnNames($field_name); $storage_definition = $this->fieldStorageDefinitions[$field_name]; - $schema[$table_name] = array_merge_recursive($schema[$table_name], $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names)); + // Preserve integer keys when merging the schema so that composite + // primary keys are not merged. + $schema[$table_name] = NestedArray::mergeDeepArray([$schema[$table_name], $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names)], TRUE); } } } @@ -1050,15 +1053,12 @@ protected function initializeBaseTable(ContentEntityTypeInterface $entity_type) $schema = [ 'description' => "The base table for $entity_type_id entities.", - 'primary key' => [$entity_type->getKey('id')], 'indexes' => [], 'foreign keys' => [], ]; if ($entity_type->hasKey('revision')) { $revision_key = $entity_type->getKey('revision'); - $key_name = $this->getEntityIndexName($entity_type, $revision_key); - $schema['unique keys'][$key_name] = [$revision_key]; $schema['foreign keys'][$entity_type_id . '__revision'] = [ 'table' => $this->storage->getRevisionTable(), 'columns' => [$revision_key => $revision_key], @@ -1082,11 +1082,9 @@ protected function initializeBaseTable(ContentEntityTypeInterface $entity_type) protected function initializeRevisionTable(ContentEntityTypeInterface $entity_type) { $entity_type_id = $entity_type->id(); $id_key = $entity_type->getKey('id'); - $revision_key = $entity_type->getKey('revision'); $schema = [ 'description' => "The revision table for $entity_type_id entities.", - 'primary key' => [$revision_key], 'indexes' => [], 'foreign keys' => [ $entity_type_id . '__revisioned' => [ @@ -1096,8 +1094,6 @@ protected function initializeRevisionTable(ContentEntityTypeInterface $entity_ty ], ]; - $schema['indexes'][$this->getEntityIndexName($entity_type, $id_key)] = [$id_key]; - $this->addTableDefaults($schema); return $schema; @@ -1118,10 +1114,6 @@ protected function initializeDataTable(ContentEntityTypeInterface $entity_type) $schema = [ 'description' => "The data table for $entity_type_id entities.", - 'primary key' => [$id_key, $entity_type->getKey('langcode')], - 'indexes' => [ - $entity_type_id . '__id__default_langcode__langcode' => [$id_key, $entity_type->getKey('default_langcode'), $entity_type->getKey('langcode')], - ], 'foreign keys' => [ $entity_type_id => [ 'table' => $this->storage->getBaseTable(), @@ -1130,11 +1122,6 @@ protected function initializeDataTable(ContentEntityTypeInterface $entity_type) ], ]; - if ($entity_type->hasKey('revision')) { - $key = $entity_type->getKey('revision'); - $schema['indexes'][$this->getEntityIndexName($entity_type, $key)] = [$key]; - } - $this->addTableDefaults($schema); return $schema; @@ -1156,10 +1143,6 @@ protected function initializeRevisionDataTable(ContentEntityTypeInterface $entit $schema = [ 'description' => "The revision data table for $entity_type_id entities.", - 'primary key' => [$revision_key, $entity_type->getKey('langcode')], - 'indexes' => [ - $entity_type_id . '__id__default_langcode__langcode' => [$id_key, $entity_type->getKey('default_langcode'), $entity_type->getKey('langcode')], - ], 'foreign keys' => [ $entity_type_id => [ 'table' => $this->storage->getBaseTable(), @@ -1302,6 +1285,8 @@ protected function processFieldStorageSchema(array &$field_storage_schema) { unset($field_storage_schema[$table_name]['fields'][$key]['initial']); unset($field_storage_schema[$table_name]['fields'][$key]['initial_from_field']); } + + $this->addTableDefaults($field_storage_schema[$table_name]); } } @@ -1376,16 +1361,24 @@ protected function createSharedTableSchema(FieldStorageDefinitionInterface $stor if (!$only_save) { // The entity schema needs to be checked because the field schema is // potentially incomplete. - // @todo Remove this in - // https://www.drupal.org/project/drupal/issues/2929120 - $entity_schema = $this->getEntitySchema($this->entityType); foreach ($schema[$table_name]['fields'] as $name => $specifier) { // Check if the field is part of the primary keys and pass along // this information when adding the field. // @see \Drupal\Core\Database\Schema::addField() $new_keys = []; - if (isset($entity_schema[$table_name]['primary key']) && array_intersect($column_names, $entity_schema[$table_name]['primary key'])) { - $new_keys = ['primary key' => $entity_schema[$table_name]['primary key']]; + if (!empty($schema[$table_name]['primary key']) && in_array($name, $schema[$table_name]['primary key'], TRUE)) { + $new_keys = ['primary key' => $schema[$table_name]['primary key']]; + + // If the field is part of a primary key, it might be a serial + // field. Serial fields are incorrectly stored as integer fields + // in the field schema, so we adapt the schema here manually. + // @todo Remove this in + // https://www.drupal.org/project/drupal/issues/2928906 + $base_table_serial = ($created_field_name === $this->entityType->getKey('id')) && ($table_name === $this->storage->getBaseTable()); + $revision_table_serial = ($created_field_name === $this->entityType->getKey('revision')) && ($table_name === $this->storage->getRevisionTable()); + if (($specifier['type'] === 'int') && ($base_table_serial || $revision_table_serial)) { + $specifier['type'] = 'serial'; + } } // Check if the field exists because it might already have been @@ -1396,14 +1389,24 @@ protected function createSharedTableSchema(FieldStorageDefinitionInterface $stor } if (!empty($schema[$table_name]['indexes'])) { foreach ($schema[$table_name]['indexes'] as $name => $specifier) { + // When creating a composite index, the field schema of all + // participating fields must be passed to the schema handler. + $index_schema = $schema[$table_name]; + foreach ($specifier as $index_key => $index_field) { + // Get the name of the field from the index specification. + $other_column_name = is_array($index_field) ? $index_field[0] : $index_field; + if (!isset($index_schema['fields'][$other_column_name])) { + $this->mergeFieldSchema($index_schema, $table_mapping, $table_name, $other_column_name); + } + } // Check if the index exists because it might already have been // created as part of the earlier entity type update event. - $this->addIndex($table_name, $name, $specifier, $schema[$table_name]); + $this->addIndex($table_name, $name, $specifier, $index_schema); } } if (!empty($schema[$table_name]['unique keys'])) { foreach ($schema[$table_name]['unique keys'] as $name => $specifier) { - $schema_handler->addUniqueKey($table_name, $name, $specifier); + $this->addUniqueKey($table_name, $name, $specifier); } } } @@ -1469,7 +1472,7 @@ protected function deleteSharedTableSchema(FieldStorageDefinitionInterface $stor $schema = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names); // Drop the primary key, indexes and unique keys first. - $this->dropPrimaryKey($table_name, $column_names); + $this->dropPrimaryKey($storage_definition, $table_name, $schema, $column_names); if (!empty($schema['indexes'])) { foreach ($schema['indexes'] as $name => $specifier) { @@ -1657,7 +1660,7 @@ protected function updateSharedTableSchema(FieldStorageDefinitionInterface $stor } // Drop the original primary key, indexes and unique keys first. - $this->dropPrimaryKey($table_name, $column_names); + $this->dropPrimaryKey($storage_definition, $table_name, $schema[$table_name], $column_names); if (!empty($original_schema[$table_name]['indexes'])) { foreach ($original_schema[$table_name]['indexes'] as $name => $specifier) { @@ -1684,15 +1687,25 @@ protected function updateSharedTableSchema(FieldStorageDefinitionInterface $stor } if (!empty($schema[$table_name]['indexes'])) { foreach ($schema[$table_name]['indexes'] as $name => $specifier) { + // When creating a composite index, the field schema of all + // participating fields must be passed to the schema handler. + $index_schema = $schema[$table_name]; + foreach ($specifier as $index_key => $index_field) { + // Get the name of the field from the index specification. + $other_column_name = is_array($index_field) ? $index_field[0] : $index_field; + if (!isset($index_schema['fields'][$other_column_name])) { + $this->mergeFieldSchema($index_schema, $table_mapping, $table_name, $other_column_name); + } + } // Check if the index exists because it might already have been // created as part of the earlier entity type update event. - $this->addIndex($table_name, $name, $specifier, $schema[$table_name]); + $this->addIndex($table_name, $name, $specifier, $index_schema); } } if (!empty($schema[$table_name]['unique keys'])) { foreach ($schema[$table_name]['unique keys'] as $name => $specifier) { - $schema_handler->addUniqueKey($table_name, $name, $specifier); + $this->addUniqueKey($table_name, $name, $specifier); } } // After deleting the field schema skip to the next table. @@ -1943,6 +1956,53 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st $schema['foreign keys'] = $this->getFieldForeignKeys($field_name, $field_schema, $column_mapping); } + // Add primary keys and indexes for key fields. + if ($table_name === $this->storage->getBaseTable()) { + if ($field_name === $this->entityType->getKey('id')) { + $schema['primary key'] = [$this->entityType->getKey('id')]; + } + elseif ($field_name === $this->entityType->getKey('revision')) { + $key_name = $this->getEntityIndexName($this->entityType, $this->entityType->getKey('revision')); + $schema['unique keys'][$key_name] = [$this->entityType->getKey('revision')]; + } + } + elseif ($table_name === $this->storage->getRevisionTable()) { + if ($field_name === $this->entityType->getKey('id')) { + $schema['indexes'][$this->getEntityIndexName($this->entityType, $this->entityType->getKey('id'))] = [$field_name]; + } + elseif ($field_name === $this->entityType->getKey('revision')) { + $schema['primary key'] = [$this->entityType->getKey('revision')]; + } + } + elseif ($table_name === $this->storage->getDataTable()) { + if (in_array($field_name, [$this->entityType->getKey('id'), $this->entityType->getKey('langcode')], TRUE)) { + $schema['primary key'] = [ + $this->entityType->getKey('id'), + $this->entityType->getKey('langcode'), + ]; + } + elseif ($field_name === $this->entityType->getKey('revision')) { + $key_name = $this->getEntityIndexName($this->entityType, $this->entityType->getKey('revision')); + $schema['indexes'][$key_name] = [$this->entityType->getKey('revision')]; + } + } + elseif ($table_name === $this->storage->getRevisionDataTable()) { + if (in_array($field_name, [$this->entityType->getKey('revision'), $this->entityType->getKey('langcode')], TRUE)) { + $schema['primary key'] = [$this->entityType->getKey('revision'), $this->entityType->getKey('langcode')]; + } + } + if (in_array($table_name, [$this->storage->getDataTable(), $this->storage->getRevisionDataTable()], TRUE)) { + if (in_array($field_name, [$this->entityType->getKey('id'), $this->entityType->getKey('default_langcode'), $this->entityType->getKey('langcode')], TRUE)) { + $schema['indexes'][$this->entityType->id() . '__id__default_langcode__langcode'] = [ + $this->entityType->getKey('id'), + $this->entityType->getKey('default_langcode'), + $this->entityType->getKey('langcode'), + ]; + } + } + + $this->addTableDefaults($schema); + return $schema; } @@ -2193,6 +2253,34 @@ protected function getDedicatedTableSchema(FieldStorageDefinitionInterface $stor return $dedicated_table_schema; } + /** + * Merges schema with the field schema for a given column. + * + * This looks up the field that the column belongs to and merges the field + * schema of that field into the passed-in schema. + * + * @param array $schema + * The schema to merge the other field schema to. + * @param \Drupal\Core\Entity\Sql\TableMappingInterface $table_mapping + * The table mapping. + * @param string $table_name + * The table name. + * @param string $column_name + * The column name to merge the field schema for. + */ + protected function mergeFieldSchema(&$schema, TableMappingInterface $table_mapping, $table_name, $column_name) { + foreach ($table_mapping->getFieldNames($table_name) as $search_field_name) { + $search_column_names = $table_mapping->getColumnNames($search_field_name); + foreach ($search_column_names as $search_column_name) { + if ($search_column_name === $column_name) { + $other_storage_definition = $this->fieldStorageDefinitions[$search_field_name]; + $other_schema = $this->getSharedTableFieldSchema($other_storage_definition, $table_name, $search_column_names); + $schema = NestedArray::mergeDeepArray([$schema, $other_schema], TRUE); + } + } + } + } + /** * Gets the name to be used for the given entity index. * @@ -2334,28 +2422,34 @@ protected function addUniqueKey($table, $name, array $specifier) { /** * Removes the primary key of a table if the passed columns are part of it. * + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition + * The storage definition the primary key belongs to. * @param string $table_name * The name of the table whose primary key is to be deleted. + * @param array $schema + * The field schema for this table. * @param string[] $column_names * The list of columns to check whether they are part of the primary key. * * @internal */ - private function dropPrimaryKey($table_name, $column_names) { + private function dropPrimaryKey(FieldStorageDefinitionInterface $storage_definition, $table_name, array $schema, $column_names) { $schema_handler = $this->database->schema(); - // The entity schema needs to be checked because the field schema is - // potentially incomplete. - // @todo Remove this in - // https://www.drupal.org/project/drupal/issues/2929120 - $entity_schema = $this->getEntitySchema($this->entityType); - if (array_intersect($column_names, $entity_schema[$table_name]['primary key'])) { + if (!empty($schema['primary key']) && array_intersect($column_names, $schema['primary key'])) { // Dropping a primary key must not leave a serial key, so we need to // change any serial field to integer first. - foreach ($entity_schema[$table_name]['primary key'] as $column_name) { - if ($entity_schema[$table_name]['fields'][$column_name]['type'] === 'serial') { - $field_schema = $entity_schema[$table_name]['fields'][$column_name]; - $field_schema['type'] = 'int'; - $schema_handler->changeField($table_name, $column_name, $column_name, $field_schema); + $field_name = $storage_definition->getName(); + // Serial fields are incorrectly stored as integer fields in the field + // schema, so we explicitly check the conditions for marking it serial. + // @todo Remove this in + // https://www.drupal.org/project/drupal/issues/2928906 + $base_table_serial = ($field_name === $this->entityType->getKey('id')) && ($table_name === $this->storage->getBaseTable()); + $revision_table_serial = ($field_name === $this->entityType->getKey('revision')) && ($table_name === $this->storage->getRevisionTable()); + if ($base_table_serial || $revision_table_serial) { + foreach ($schema['primary key'] as $column_name) { + if ($schema['fields'][$column_name]['type'] === 'int') { + $schema_handler->changeField($table_name, $column_name, $column_name, $schema['fields'][$column_name]); + } } } $schema_handler->dropPrimaryKey($table_name); diff --git a/core/modules/node/node.install b/core/modules/node/node.install index 6469245c49..651928462d 100644 --- a/core/modules/node/node.install +++ b/core/modules/node/node.install @@ -255,3 +255,24 @@ function node_update_8400() { $schema['fields']['realm']['description'] = 'The realm in which the user must possess the grant ID. Modules can define one or more realms by implementing hook_node_grants().'; Database::getConnection()->schema()->changeField('node_access', 'realm', 'realm', $schema['fields']['realm']); } + +/** + * Update the stored schema data of various node fields. + */ +function node_update_8601() { + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + + $field_names = [ + 'changed', + 'created', + 'promote', + 'status', + 'sticky', + 'title', + 'type', + ]; + foreach ($field_names as $field_name) { + $field_storage_definition = $definition_update_manager->getFieldStorageDefinition($field_name, 'node'); + $definition_update_manager->updateFieldStorageDefinition($field_storage_definition); + } +} diff --git a/core/modules/node/src/NodeStorageSchema.php b/core/modules/node/src/NodeStorageSchema.php index ac45bb5d1e..b0c4f17b14 100644 --- a/core/modules/node/src/NodeStorageSchema.php +++ b/core/modules/node/src/NodeStorageSchema.php @@ -2,7 +2,6 @@ namespace Drupal\node; -use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; use Drupal\Core\Field\FieldStorageDefinitionInterface; @@ -11,20 +10,6 @@ */ class NodeStorageSchema extends SqlContentEntityStorageSchema { - /** - * {@inheritdoc} - */ - protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { - $schema = parent::getEntitySchema($entity_type, $reset); - - $schema['node_field_data']['indexes'] += [ - 'node__frontpage' => ['promote', 'status', 'sticky', 'created'], - 'node__title_type' => ['title', ['type', 4]], - ]; - - return $schema; - } - /** * {@inheritdoc} */ @@ -45,22 +30,17 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st } if ($table_name == 'node_field_data') { - switch ($field_name) { - case 'promote': - case 'status': - case 'sticky': - case 'title': - // Improves the performance of the indexes defined - // in getEntitySchema(). - $schema['fields'][$field_name]['not null'] = TRUE; - break; - - case 'changed': - case 'created': - // @todo Revisit index definitions: - // https://www.drupal.org/node/2015277. - $this->addSharedTableFieldIndex($storage_definition, $schema, TRUE); - break; + if (in_array($field_name, ['changed', 'created'], TRUE)) { + $this->addSharedTableFieldIndex($storage_definition, $schema, TRUE); + } + if (in_array($field_name, ['promote', 'status', 'sticky', 'title'], TRUE)) { + $schema['fields'][$field_name]['not null'] = TRUE; + } + if (in_array($field_name, ['promote', 'status', 'sticky', 'created'], TRUE)) { + $schema['node_field_data']['indexes']['node__frontpage'] = ['promote', 'status', 'sticky', 'created']; + } + if (in_array($field_name, ['title', 'type'], TRUE)) { + $schema['node_field_data']['indexes']['node__title_type'] = ['title', ['type', 4]]; } } diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 1838326451..b38c2437c8 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -2135,3 +2135,33 @@ function system_update_8501() { } } } + +/** + * Update the stored schema data of ID and language fields. + */ +function system_update_8601() { + $entity_type_manager = \Drupal::entityTypeManager(); + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_respository */ + $entity_last_installed_schema_respository = \Drupal::service('entity.last_installed_schema.repository'); + + foreach ($entity_type_manager->getDefinitions() as $entity_type_id => $entity_type) { + $original_entity_type = $entity_last_installed_schema_respository->getLastInstalledDefinition($entity_type_id); + if (!$original_entity_type) { + continue; + } + $field_storage_definitions = $entity_last_installed_schema_respository->getLastInstalledFieldStorageDefinitions($entity_type_id); + + $field_names = array_filter([ + $original_entity_type->getKey('id'), + $original_entity_type->getKey('revision'), + $original_entity_type->getKey('langcode'), + $original_entity_type->getKey('default_langcode'), + ]); + foreach ($field_names as $field_name) { + if (isset($field_storage_definitions[$field_name])) { + $definition_update_manager->updateFieldStorageDefinition($field_storage_definitions[$field_name]); + } + } + } +} diff --git a/core/modules/system/tests/src/Functional/Entity/Update/SqlContentEntityStorageSchemaConverterTest.php b/core/modules/system/tests/src/Functional/Entity/Update/SqlContentEntityStorageSchemaConverterTest.php index 625ee190ed..639be89565 100644 --- a/core/modules/system/tests/src/Functional/Entity/Update/SqlContentEntityStorageSchemaConverterTest.php +++ b/core/modules/system/tests/src/Functional/Entity/Update/SqlContentEntityStorageSchemaConverterTest.php @@ -220,6 +220,47 @@ public function testMakeRevisionableErrorHandling() { foreach ($new_storage_definitions as $storage_definition) { $new_field_schema_data[$storage_definition->getName()] = $this->installedStorageSchema->get('entity_test_update.field_schema_data.' . $storage_definition->getName(), []); } + // Before https://www.drupal.org/project/drupal/issues/2929120 various keys + // were missing from the field schema, so we explicitly add those before + // checking equality. + $this->assertFalse(isset($original_field_schema_data['id']['entity_test_update']['primary key'])); + $original_field_schema_data['id']['entity_test_update']['primary key'] = ['id']; + $this->assertFalse(isset($original_field_schema_data['id']['entity_test_update_data']['primary key'])); + $original_field_schema_data['id']['entity_test_update_data']['primary key'] = ['id', 'langcode']; + $this->assertFalse(isset($original_field_schema_data['id']['entity_test_update_data']['indexes']['entity_test_update__id__default_langcode__langcode'])); + $original_field_schema_data['id']['entity_test_update_data']['indexes']['entity_test_update__id__default_langcode__langcode'] = ['id', 'default_langcode', 'langcode']; + $this->assertFalse(isset($original_field_schema_data['langcode']['entity_test_update_data']['primary key'])); + $original_field_schema_data['langcode']['entity_test_update_data']['primary key'] = ['id', 'langcode']; + $this->assertFalse(isset($original_field_schema_data['langcode']['entity_test_update_data']['indexes']['entity_test_update__id__default_langcode__langcode'])); + $original_field_schema_data['langcode']['entity_test_update_data']['indexes']['entity_test_update__id__default_langcode__langcode'] = ['id', 'default_langcode', 'langcode']; + $this->assertFalse(isset($original_field_schema_data['default_langcode']['entity_test_update_data']['indexes']['entity_test_update__id__default_langcode__langcode'])); + $original_field_schema_data['default_langcode']['entity_test_update_data']['indexes']['entity_test_update__id__default_langcode__langcode'] = ['id', 'default_langcode', 'langcode']; + // Also account for the fact that the field schema now contains default + // values for DX. + $this->assertFalse(isset($original_field_schema_data['id']['entity_test_update']['unique keys'])); + $original_field_schema_data['id']['entity_test_update']['unique keys'] = []; + $this->assertFalse(isset($original_field_schema_data['id']['entity_test_update']['indexes'])); + $original_field_schema_data['id']['entity_test_update']['indexes'] = []; + $this->assertFalse(isset($original_field_schema_data['id']['entity_test_update']['foreign keys'])); + $original_field_schema_data['id']['entity_test_update']['foreign keys'] = []; + $this->assertFalse(isset($original_field_schema_data['id']['entity_test_update_data']['unique keys'])); + $original_field_schema_data['id']['entity_test_update_data']['unique keys'] = []; + $this->assertFalse(isset($original_field_schema_data['id']['entity_test_update_data']['foreign keys'])); + $original_field_schema_data['id']['entity_test_update_data']['foreign keys'] = []; + $this->assertFalse(isset($original_field_schema_data['langcode']['entity_test_update']['unique keys'])); + $original_field_schema_data['langcode']['entity_test_update']['unique keys'] = []; + $this->assertFalse(isset($original_field_schema_data['langcode']['entity_test_update']['indexes'])); + $original_field_schema_data['langcode']['entity_test_update']['indexes'] = []; + $this->assertFalse(isset($original_field_schema_data['langcode']['entity_test_update']['foreign keys'])); + $original_field_schema_data['langcode']['entity_test_update']['foreign keys'] = []; + $this->assertFalse(isset($original_field_schema_data['langcode']['entity_test_update_data']['unique keys'])); + $original_field_schema_data['langcode']['entity_test_update_data']['unique keys'] = []; + $this->assertFalse(isset($original_field_schema_data['langcode']['entity_test_update_data']['foreign keys'])); + $original_field_schema_data['langcode']['entity_test_update_data']['foreign keys'] = []; + $this->assertFalse(isset($original_field_schema_data['default_langcode']['entity_test_update_data']['unique keys'])); + $original_field_schema_data['default_langcode']['entity_test_update_data']['unique keys'] = []; + $this->assertFalse(isset($original_field_schema_data['default_langcode']['entity_test_update_data']['foreign keys'])); + $original_field_schema_data['default_langcode']['entity_test_update_data']['foreign keys'] = []; $this->assertEqual($original_field_schema_data, $new_field_schema_data); // Check that temporary tables have been removed. diff --git a/core/modules/user/src/UserStorageSchema.php b/core/modules/user/src/UserStorageSchema.php index 5e590b8958..fae75fbb79 100644 --- a/core/modules/user/src/UserStorageSchema.php +++ b/core/modules/user/src/UserStorageSchema.php @@ -2,7 +2,6 @@ namespace Drupal\user; -use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; use Drupal\Core\Field\FieldStorageDefinitionInterface; @@ -11,19 +10,6 @@ */ class UserStorageSchema extends SqlContentEntityStorageSchema { - /** - * {@inheritdoc} - */ - protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { - $schema = parent::getEntitySchema($entity_type, $reset); - - $schema['users_field_data']['unique keys'] += [ - 'user__name' => ['name', 'langcode'], - ]; - - return $schema; - } - /** * {@inheritdoc} */ @@ -42,24 +28,22 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st $field_name = $storage_definition->getName(); if ($table_name == 'users_field_data') { - switch ($field_name) { - case 'name': - // Improves the performance of the user__name index defined - // in getEntitySchema(). - $schema['fields'][$field_name]['not null'] = TRUE; - // Make sure the field is no longer than 191 characters so we can - // add a unique constraint in MySQL. - $schema['fields'][$field_name]['length'] = USERNAME_MAX_LENGTH; - break; - - case 'mail': - $this->addSharedTableFieldIndex($storage_definition, $schema); - break; - - case 'access': - case 'created': - $this->addSharedTableFieldIndex($storage_definition, $schema, TRUE); - break; + if ($field_name === 'name') { + // Improves the performance of the user__name index defined + // in getEntitySchema(). + $schema['fields'][$field_name]['not null'] = TRUE; + // Make sure the field is no longer than 191 characters so we can + // add a unique constraint in MySQL. + $schema['fields'][$field_name]['length'] = UserInterface::USERNAME_MAX_LENGTH; + } + if ($field_name === 'mail') { + $this->addSharedTableFieldIndex($storage_definition, $schema); + } + if (in_array($field_name, ['access', 'created'], TRUE)) { + $this->addSharedTableFieldIndex($storage_definition, $schema, TRUE); + } + if (in_array($field_name, ['name', 'langcode'], TRUE)) { + $schema['users_field_data']['unique keys']['user__name'] = ['name', 'langcode']; } } diff --git a/core/modules/user/user.install b/core/modules/user/user.install index 0af797a43f..aa0a2a4be6 100644 --- a/core/modules/user/user.install +++ b/core/modules/user/user.install @@ -98,3 +98,16 @@ function user_update_8100() { $config->set('status_blocked', $mail)->save(TRUE); } } + +/** + * Update the stored schema data of various node fields. + */ +function user_update_8601() { + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + + $field_storage_definition = $definition_update_manager->getFieldStorageDefinition('name', 'user'); + $definition_update_manager->updateFieldStorageDefinition($field_storage_definition); + + $entity_type = $definition_update_manager->getEntityType('user'); + $definition_update_manager->updateEntityType($entity_type); +} diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php index d16ece2097..56852869e5 100644 --- a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php @@ -397,7 +397,7 @@ public function testGetSchemaRevisionable() { ], ]); - $this->storage->expects($this->exactly(2)) + $this->storage->expects($this->exactly(6)) ->method('getRevisionTable') ->will($this->returnValue('entity_test_revision')); @@ -604,13 +604,13 @@ public function testGetSchemaRevisionableTranslatable() { ], ]); - $this->storage->expects($this->exactly(3)) + $this->storage->expects($this->exactly(25)) ->method('getRevisionTable') ->will($this->returnValue('entity_test_revision')); - $this->storage->expects($this->once()) + $this->storage->expects($this->exactly(45)) ->method('getDataTable') ->will($this->returnValue('entity_test_field_data')); - $this->storage->expects($this->once()) + $this->storage->expects($this->exactly(37)) ->method('getRevisionDataTable') ->will($this->returnValue('entity_test_revision_field_data'));