diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 46fbcbce4fe99b8e2ab78b856a9f26c7772945d8..6dfc2700e3b004c99f534a781370a09cfd5b0273 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -7,6 +7,7 @@ use Drupal\Core\DrupalKernel; use Drupal\Core\CoreServiceProvider; use Drupal\Core\Database\Database; +use Drupal\Core\Database\DatabaseExceptionWrapper; use Drupal\Core\Database\Install\TaskException; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageManager; @@ -156,14 +157,15 @@ function install_state_defaults() { // The last task that was completed during the previous installation // request. 'completed_task' => NULL, - // This becomes TRUE only when a valid config directory is created or - // detected. + // TRUE when there are valid config directories. 'config_verified' => FALSE, - // This becomes TRUE only when Drupal's system module is installed. - 'database_tables_exist' => FALSE, - // This becomes TRUE only when a valid database connection can be - // established. + // TRUE when there is a valid database connection. 'database_verified' => FALSE, + // TRUE when a valid settings.php exists (containing both database + // connection information and config directory names). + 'settings_verified' => FALSE, + // TRUE when the base system has been installed and is ready to operate. + 'base_system_verified' => FALSE, // Whether a translation file for the selected language will be downloaded // from the translation server. 'download_translation' => FALSE, @@ -209,10 +211,6 @@ function install_state_defaults() { // Tokens in the pattern will be replaced by appropriate values for the // required translation file. 'server_pattern' => 'http://ftp.drupal.org/files/translations/%core/%project/%project-%version.%language.po', - // This becomes TRUE only when a valid settings.php file is written - // (containing both valid database connection information and a valid - // config directory). - 'settings_verified' => FALSE, // Installation tasks can set this to TRUE to force the page request to // end (even if there is no themable output), in the case of an interactive // installation. This is needed only rarely; for example, it would be used @@ -322,48 +320,43 @@ function install_begin_request(&$install_state) { require_once __DIR__ . '/install.inc'; require_once __DIR__ . '/schema.inc'; require_once __DIR__ . '/../../' . settings()->get('path_inc', 'core/includes/path.inc'); + require_once __DIR__ . '/cache.inc'; + require_once __DIR__ . '/database.inc'; + require_once __DIR__ . '/form.inc'; + require_once __DIR__ . '/batch.inc'; + require_once __DIR__ . '/ajax.inc'; // Load module basics (needed for hook invokes). include_once __DIR__ . '/module.inc'; include_once __DIR__ . '/session.inc'; require_once __DIR__ . '/entity.inc'; - // Determine whether the configuration system is ready to operate. - $install_state['config_verified'] = install_verify_config_directory(CONFIG_ACTIVE_DIRECTORY) && install_verify_config_directory(CONFIG_STAGING_DIRECTORY); - // Register the translation services. install_register_translation_service($container); \Drupal::setContainer($container); - // Check existing settings.php. + // Determine whether base system services are ready to operate. + $install_state['config_verified'] = install_verify_config_directory(CONFIG_ACTIVE_DIRECTORY) && install_verify_config_directory(CONFIG_STAGING_DIRECTORY); $install_state['database_verified'] = install_verify_database_settings(); $install_state['settings_verified'] = $install_state['config_verified'] && $install_state['database_verified']; - // If it is not, replace the configuration storage with the InstallStorage - // implementation, for the following reasons: - // - The first call to $kernel->getContainer() will try to set up the regular - // runtime configuration storage, using the CachedStorage by default. It - // calls config_get_config_directory() to retrieve the config directory to - // use, but that throws an exception, since $config_directories is not - // defined since there is no settings.php yet. If there is a prepared - // settings.php already, then the returned directory still cannot be used, - // because it does not necessarily exist. The installer ensures that it - // exists and is writeable in a later step. - // - The installer outputs maintenance theme pages and performs many other - // operations, which try to load configuration. Since there is no active - // configuration yet, and because the configuration system does not have a - // notion of default values at runtime, data is missing in many places. The - // lack of data does not trigger errors, but results in a broken user - // interface (e.g., missing page title, etc). - // - The actual configuration data to read during installation is essentially - // the default configuration provided by the installation profile and - // modules (most notably System module). The InstallStorage therefore reads - // from the default configuration directories of extensions. - // This override is reverted as soon as the config directory and the - // database has been set up successfully. - // @see drupal_install_config_directories() - // @see install_settings_form_submit() if ($install_state['settings_verified']) { + try { + $system_schema = system_schema(); + end($system_schema); + $table = key($system_schema); + $install_state['base_system_verified'] = Database::getConnection()->schema()->tableExists($table); + } + catch (DatabaseExceptionWrapper $e) { + // The last defined table of the base system_schema() does not exist yet. + // $install_state['base_system_verified'] defaults to FALSE, so the code + // following below will use the minimal installer service container. + // As soon as the base system is verified here, the installer operates in + // a full and regular Drupal environment, without any kind of exceptions. + } + } + + if ($install_state['base_system_verified']) { $kernel = new DrupalKernel('install', drupal_classloader(), FALSE); $kernel->boot(); $container = $kernel->getContainer(); @@ -371,6 +364,9 @@ function install_begin_request(&$install_state) { $container->set('string_translator.file_translation', install_file_translation_service()); $container->get('string_translation')->addTranslator($container->get('string_translator.file_translation')); } + // Replace services with in-memory implementations and specialized installer + // implementations. This service container is reverted to a regular + // DrupalKernel in install_bootstrap_full(). else { // @todo Move into a proper Drupal\Core\DependencyInjection\InstallContainerBuilder. $container = new ContainerBuilder(); @@ -494,8 +490,6 @@ function install_begin_request(&$install_state) { \Drupal::translation()->setDefaultLangcode($install_state['parameters']['langcode']); } - require_once __DIR__ . '/ajax.inc'; - $module_handler = \Drupal::moduleHandler(); if (!$module_handler->moduleExists('system')) { // Override the module list with a minimal set of modules. @@ -503,8 +497,6 @@ function install_begin_request(&$install_state) { } $module_handler->load('system'); - require_once __DIR__ . '/cache.inc'; - // Prepare for themed output. We need to run this at the beginning of the // page request to avoid a different theme accidentally getting set. (We also // need to run it even in the case of command-line installations, to prevent @@ -513,10 +505,6 @@ function install_begin_request(&$install_state) { drupal_maintenance_theme(); if ($install_state['database_verified']) { - // Initialize the database system. Note that the connection - // won't be initialized until it is actually requested. - require_once __DIR__ . '/database.inc'; - // Verify the last completed task in the database, if there is one. $task = install_verify_completed_task(); } @@ -541,7 +529,6 @@ function install_begin_request(&$install_state) { // Modify the installation state as appropriate. $install_state['completed_task'] = $task; - $install_state['database_tables_exist'] = !empty($task); // Add the list of available profiles to the installation state. $install_state['profiles'] += drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.profile$/', 'profiles'); @@ -585,7 +572,7 @@ function install_run_tasks(&$install_state) { if (!$install_state['task_not_complete']) { $install_state['tasks_performed'][] = $task_name; $install_state['installation_finished'] = empty($tasks_to_perform); - if ($install_state['database_tables_exist'] && ($task['run'] == INSTALL_TASK_RUN_IF_NOT_COMPLETED || $install_state['installation_finished'])) { + if ($task['run'] == INSTALL_TASK_RUN_IF_NOT_COMPLETED || $install_state['installation_finished']) { \Drupal::state()->set('install_task', $install_state['installation_finished'] ? 'done' : $task_name); } } @@ -614,7 +601,6 @@ function install_run_task($task, &$install_state) { $function = $task['function']; if ($task['type'] == 'form') { - require_once __DIR__ . '/form.inc'; if ($install_state['interactive']) { // For interactive forms, build the form and ensure that it will not // redirect, since the installer handles its own redirection only after @@ -692,7 +678,6 @@ function install_run_task($task, &$install_state) { // If we are in the middle of processing this batch, keep sending back // any output from the batch process, until the task is complete. elseif ($current_batch == $function) { - include_once __DIR__ . '/batch.inc'; $output = _batch_page(\Drupal::request()); // Because Batch API now returns a JSON response for intermediary steps, // but the installer doesn't handle Response objects yet, just send the @@ -813,7 +798,9 @@ function install_tasks($install_state) { 'run' => $install_state['settings_verified'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED, ), 'install_base_system' => array( + 'run' => $install_state['base_system_verified'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED, ), + // All tasks below are executed in a regular, full Drupal environment. 'install_bootstrap_full' => array( 'run' => INSTALL_TASK_RUN_IF_REACHED, ), @@ -1047,7 +1034,7 @@ function install_base_system(&$install_state) { $modules[] = drupal_get_profile(); \Drupal::state()->set('install_profile_modules', array_diff($modules, array('system'))); - $install_state['database_tables_exist'] = TRUE; + $install_state['base_system_verified'] = TRUE; } /**