diff --git a/core/includes/install.inc b/core/includes/install.inc index e806a09a41..3bb7241bcc 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -8,6 +8,7 @@ use Drupal\Component\Utility\OpCodeCache; use Drupal\Component\Utility\Unicode; use Drupal\Component\Utility\UrlHelper; +use Drupal\Core\Database\Database; use Drupal\Core\Extension\Dependency; use Drupal\Core\Extension\ExtensionDiscovery; use Drupal\Core\Installer\InstallerKernel; @@ -611,6 +612,20 @@ function drupal_install_system($install_state) { ->set('profile', $install_state['parameters']['profile']) ->save(); + // When the database driver is provided by a module, then install that module. + if ($connection = Database::getConnection()) { + if ($module = $connection->getModuleName()) { + $autoload = $connection->getConnectionOptions()['autoload'] ?? ''; + if (($pos = strpos($autoload, 'src/Driver/Database/')) !== FALSE) { + $module_info_yml = substr($autoload, 0, $pos) . $module . '.info.yml'; + if (file_exists($module_info_yml)) { + \Drupal::service('extension.list.module')->setPathname($module, $module_info_yml); + $kernel->getContainer()->get('module_installer')->install([$module], FALSE); + } + } + } + } + // Install System module and rebuild the newly available routes. $kernel->getContainer()->get('module_installer')->install(['system'], FALSE); \Drupal::service('router.builder')->rebuild(); diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php index c6ce48e523..0bb0e6e7f1 100644 --- a/core/lib/Drupal/Core/Database/Connection.php +++ b/core/lib/Drupal/Core/Database/Connection.php @@ -1820,4 +1820,22 @@ public static function createUrlFromConnectionOptions(array $connection_options) return $db_url; } + /** + * Get the module name of the module that is providing the database driver. + * + * @return string|false + * The module name of the module that is providing the database driver, or + * false when there is no providing module. + */ + public function getModuleName() { + [$first, $second] = explode('\\', $this->connectionOptions['namespace'], 3); + + // The namespace for Drupal modules is Drupal\MODULE_NAME, and the module + // name must be all lowercase. Second-level namespaces containing uppercase + // letters (e.g., "Core", "Component", "Driver") are not modules. + // @see \Drupal\Core\DrupalKernel::getModuleNamespacesPsr4() + // @see https://www.drupal.org/docs/8/creating-custom-modules/naming-and-placing-your-drupal-8-module#s-name-your-module + return ($first === 'Drupal' && strtolower($second) === $second) ? $second : FALSE; + } + } diff --git a/core/tests/Drupal/FunctionalTests/Installer/InstallerNonDefaultDatabaseDriverTest.php b/core/tests/Drupal/FunctionalTests/Installer/InstallerNonDefaultDatabaseDriverTest.php index fd2400a6ca..eb70c8983f 100644 --- a/core/tests/Drupal/FunctionalTests/Installer/InstallerNonDefaultDatabaseDriverTest.php +++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerNonDefaultDatabaseDriverTest.php @@ -3,6 +3,7 @@ namespace Drupal\FunctionalTests\Installer; use Drupal\Core\Database\Database; +use Drupal\Core\Extension\Extension; /** * Tests the interactive installer. @@ -60,6 +61,9 @@ public function testInstalled() { $this->assertStringContainsString("'namespace' => 'Drupal\\\\driver_test\\\\Driver\\\\Database\\\\{$this->testDriverName}',", $contents); $this->assertStringContainsString("'driver' => '{$this->testDriverName}',", $contents); $this->assertStringContainsString("'autoload' => 'core/modules/system/tests/modules/driver_test/src/Driver/Database/{$this->testDriverName}/',", $contents); + + // Assert that the module "driver_test" has been installed. + $this->assertEquals(\Drupal::service('module_handler')->getModule('driver_test'), new Extension($this->root, 'module', 'core/modules/system/tests/modules/driver_test/driver_test.info.yml')); } }