Issue #3120731 by alexpott, japerry, daffie, codersukanta, rfay, xjm, tim.plunkett, catch, andypost: Incorrect "Drupal already installed" if any database settings are wrong or unsatisfactory

merge-requests/64/head
catch 2020-05-19 10:46:05 +01:00
parent dd18da9a8f
commit 03b7cf2b1b
3 changed files with 136 additions and 23 deletions

View File

@ -20,6 +20,7 @@ use Drupal\Core\Form\FormState;
use Drupal\Core\Installer\Exception\AlreadyInstalledException;
use Drupal\Core\Installer\Exception\InstallerException;
use Drupal\Core\Installer\Exception\NoProfilesException;
use Drupal\Core\Installer\Form\SiteSettingsForm;
use Drupal\Core\Installer\InstallerKernel;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageManager;
@ -522,18 +523,14 @@ function install_begin_request($class_loader, &$install_state) {
// accessing the database before it is set up yet.)
drupal_maintenance_theme();
if ($install_state['database_verified']) {
if (!$install_state['database_verified']) {
// Do not install over an existing installation. The call to
// install_verify_database_ready() will throw an AlreadyInstalledException
// if this is the case.
install_verify_database_ready();
}
// Verify the last completed task in the database, if there is one.
$task = install_verify_completed_task();
}
else {
$task = NULL;
// Do not install over a configured settings.php.
if (Database::getConnectionInfo()) {
throw new AlreadyInstalledException($container->get('string_translation'));
}
}
// Ensure that the active configuration is empty before installation starts.
if ($install_state['config_verified'] && empty($task)) {
@ -1176,16 +1173,28 @@ function install_verify_database_settings($site_path) {
/**
* Verify that the database is ready (no existing Drupal installation).
*
* @throws \Drupal\Core\Installer\Exception\AlreadyInstalledException
* Thrown when the database already has a table that would be created by
* installing the System module.
*/
function install_verify_database_ready() {
$system_schema = system_schema();
end($system_schema);
$table = key($system_schema);
$existing_install = FALSE;
if ($database = Database::getConnectionInfo()) {
if (Database::getConnection()->schema()->tableExists($table)) {
throw new AlreadyInstalledException(\Drupal::service('string_translation'));
try {
$existing_install = Database::getConnection()->schema()->tableExists($table);
}
// Do not trigger an error if the database query fails, since the database
// might not be set up yet.
catch (\Exception $e) {
}
}
if ($existing_install) {
throw new AlreadyInstalledException(\Drupal::service('string_translation'));
}
}
@ -2223,6 +2232,25 @@ function install_check_requirements($install_state) {
];
}
}
// Check the database settings if they have been configured in settings.php
// before running the Drupal installer.
if ($database = Database::getConnectionInfo()) {
$request = Request::createFromGlobals();
$site_path = empty($install_state['site_path']) ? DrupalKernel::findSitePath($request, FALSE) : $install_state['site_path'];
$database = $database['default'];
$settings_file = './' . $site_path . '/settings.php';
$errors = install_database_errors($database, $settings_file);
if (count($errors)) {
$error_message = SiteSettingsForm::getDatabaseErrorsTemplate($errors);
$requirements['database_install_errors'] = [
'title' => t('Database settings'),
'description' => $error_message,
'severity' => REQUIREMENT_ERROR,
];
}
}
}
return $requirements;
}

View File

@ -194,7 +194,28 @@ class SiteSettingsForm extends FormBase {
$errors = array_diff_key($errors, $form_errors);
if (count($errors)) {
$error_message = [
$error_message = static::getDatabaseErrorsTemplate($errors);
// These are generic errors, so we do not have any specific key of the
// database connection array to attach them to; therefore, we just put
// them in the error array with standard numeric keys.
$form_errors[$database['driver'] . '][0'] = $this->renderer->renderPlain($error_message);
}
return $form_errors;
}
/**
* Gets the inline template render array to display the database errors.
*
* @param \Drupal\Core\StringTranslation\TranslatableMarkup[] $errors
* The database errors to list.
*
* @return mixed[]
* The inline template render array to display the database errors.
*/
public static function getDatabaseErrorsTemplate(array $errors) {
return [
'#type' => 'inline_template',
'#template' => '{% trans %}Resolve all issues below to continue the installation. For help configuring your database server, see the <a href="https://www.drupal.org/docs/8/install">installation handbook</a>, or contact your hosting provider.{% endtrans %}{{ errors }}',
'#context' => [
@ -204,14 +225,6 @@ class SiteSettingsForm extends FormBase {
],
],
];
// These are generic errors, so we do not have any specific key of the
// database connection array to attach them to; therefore, we just put
// them in the error array with standard numeric keys.
$form_errors[$database['driver'] . '][0'] = $this->renderer->renderPlain($error_message);
}
return $form_errors;
}
/**

View File

@ -0,0 +1,72 @@
<?php
namespace Drupal\FunctionalTests\Installer;
use Drupal\Core\Database\Database;
/**
* Tests the installer with broken database connection info in settings.php.
*
* @group Installer
*/
class InstallerExistingBrokenDatabaseSettingsTest extends InstallerTestBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function prepareEnvironment() {
parent::prepareEnvironment();
// Pre-configure database credentials in settings.php.
$connection_info = Database::getConnectionInfo();
if ($connection_info['default']['driver'] !== 'mysql') {
$this->markTestSkipped('This test relies on overriding the mysql driver');
}
// Use a database driver that reports a fake database version that does
// not meet requirements.
unset($connection_info['default']['pdo']);
unset($connection_info['default']['init_commands']);
$connection_info['default']['driver'] = 'DrivertestMysqlDeprecatedVersion';
$namespace = 'Drupal\\driver_test\\Driver\\Database\\DrivertestMysqlDeprecatedVersion';
$connection_info['default']['namespace'] = $namespace;
$connection_info['default']['autoload'] = Database::findDriverAutoloadDirectory($namespace, \Drupal::root());
$this->settings['databases']['default'] = (object) [
'value' => $connection_info,
'required' => TRUE,
];
}
/**
* {@inheritdoc}
*/
protected function setUpSettings() {
// This form will never be reached.
return;
}
/**
* {@inheritdoc}
*/
protected function setUpSite() {
// This form will never be reached.
return;
}
/**
* Tests the expected requirements problem.
*/
public function testRequirementsProblem() {
$this->assertSession()->titleEquals('Requirements problem | Drupal');
$this->assertSession()->pageTextContains('Database settings');
$this->assertSession()->pageTextContains('Resolve all issues below to continue the installation. For help configuring your database server,');
$this->assertSession()->pageTextContains('The database server version 5.5.2 is less than the minimum required version');
}
}