diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php index cdb9ae43a6..694c171fde 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php @@ -1204,7 +1204,22 @@ protected function addTableDefaults(&$schema) { * A partial schema array for the base table. */ protected function processBaseTable(ContentEntityTypeInterface $entity_type, array &$schema) { - $this->processIdentifierSchema($schema, $entity_type->getKey('id')); + // Account for a missing ID key. In theory this should not be necessary, but + // we support this for backwards-compatibility. Entity types can be declared + // without an ID field (and, thus, also without an ID key) if they are not + // stored (for example if they use ContentEntityNullStorage as the storage + // handler). Contact messages are an example of this. We then support other + // modules adding an ID field, for example via + // hook_entity_base_field_info(). Such a module is responsible for adding + // ID key to the entity type in its hook_install() implementation. (See + // Contact Storage Test for an example of this.) The ID field, however, will + // already have been installed at this point by the module installer itself. + // And because the last installed entity type is used when building the + // entity schema during field installation the entity type will not (yet) + // have an ID key when the ID field is being installed. + if ($entity_type->hasKey('id')) { + $this->processIdentifierSchema($schema, $entity_type->getKey('id')); + } } /** diff --git a/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.install b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.install index a165267b8a..c56d5b5669 100644 --- a/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.install +++ b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.install @@ -6,24 +6,18 @@ */ /** - * Implements hook_module_preinstall(). + * Implements hook_install(). */ -function contact_storage_test_module_preinstall($module) { - // This test module alters the definition of the 'contact_message' entity type - // so we need to inform the system about our changes before additional field - // storage definitions are added by the module installer. - // @see contact_storage_test_entity_type_alter() - // @see contact_storage_test_entity_base_field_info - if ($module === 'contact_storage_test') { - $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); - $entity_type = $definition_update_manager->getEntityType('contact_message'); +function contact_storage_test_install() { + $entity_manager = \Drupal::entityManager(); + $entity_type = $entity_manager->getDefinition('contact_message'); - $entity_type->setStorageClass('\Drupal\Core\Entity\Sql\SqlContentEntityStorage'); - $keys = $entity_type->getKeys(); - $keys['id'] = 'id'; - $entity_type->set('entity_keys', $keys); - $entity_type->set('base_table', 'contact_message'); + // Recreate the original entity type definition, in order to notify the + // manager of what changed. The change of storage backend will trigger + // schema installation. + // @see contact_storage_test_entity_type_alter() + $original = clone $entity_type; + $original->setStorageClass('Drupal\Core\Entity\ContentEntityNullStorage'); - $definition_update_manager->updateEntityType($entity_type); - } + $entity_manager->onEntityTypeUpdate($entity_type, $original); } diff --git a/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.module b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.module index fbcd362572..cef976c6ff 100644 --- a/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.module +++ b/core/modules/contact/tests/modules/contact_storage_test/contact_storage_test.module @@ -33,8 +33,8 @@ function contact_storage_test_entity_base_field_info(EntityTypeInterface $entity */ function contact_storage_test_entity_type_alter(array &$entity_types) { /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */ - // Set the controller class for contact messages to an alternate - // implementation of the \Drupal\Core\Entity\EntityStorageInterface interface. + // Set the controller class for nodes to an alternate implementation of the + // Drupal\Core\Entity\EntityStorageInterface interface. $entity_types['contact_message']->setStorageClass('\Drupal\Core\Entity\Sql\SqlContentEntityStorage'); $keys = $entity_types['contact_message']->getKeys(); $keys['id'] = 'id';