diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 9d86cb9..7c7ea6f 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -202,6 +202,8 @@ function install_state_defaults() { 'profile_info' => array(), // An array of available installation profiles. 'profiles' => array(), + // The name of a theme to use during installation. + 'theme' => 'seven', // An array of server variables that will be substituted into the global // $_SERVER array via drupal_override_server_variables(). Used by // non-interactive installations only. @@ -499,12 +501,27 @@ function install_begin_request(&$install_state) { \Drupal::translation()->setDefaultLangcode($install_state['parameters']['langcode']); } + // Add the list of available profiles to the installation state. + $install_state['profiles'] += drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.profile$/', 'profiles'); + + if ($profile = _install_select_profile($install_state)) { + $install_state['parameters']['profile'] = $profile; + install_load_profile($install_state); + if (isset($install_state['profile_info']['distribution']['install']['theme'])) { + // @todo Do we need to validate this? + $install_state['theme'] = $install_state['profile_info']['distribution']['install']['theme']; + } + } + $module_handler = \Drupal::moduleHandler(); if (!$module_handler->moduleExists('system')) { // Override the module list with a minimal set of modules. $module_handler->setModuleList(array('system' => 'core/modules/system/system.module')); } - $module_handler->load('system'); + if ($profile && !$module_handler->moduleExists($profile)) { + $module_handler->setModuleList(array($profile => $install_state['profiles'][$profile]->uri)); + } + $module_handler->loadAll(); // 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 @@ -538,9 +555,6 @@ function install_begin_request(&$install_state) { // Modify the installation state as appropriate. $install_state['completed_task'] = $task; - - // Add the list of available profiles to the installation state. - $install_state['profiles'] += drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.profile$/', 'profiles'); } /** @@ -787,10 +801,11 @@ function install_tasks($install_state) { 'install_download_translation' => array( 'run' => $needs_download ? INSTALL_TASK_RUN_IF_REACHED : INSTALL_TASK_SKIP, ), - 'install_select_profile' => array( + 'install_select_profile_form' => array( + 'type' => 'form', 'display_name' => t('Choose profile'), - 'display' => count($install_state['profiles']) != 1, - 'run' => INSTALL_TASK_RUN_IF_REACHED, + 'display' => empty($install_state['parameters']['profile']) && count($install_state['profiles']) != 1, + 'run' => empty($install_state['parameters']['profile']) ? INSTALL_TASK_RUN_IF_REACHED : INSTALL_TASK_SKIP, ), 'install_load_profile' => array( 'run' => INSTALL_TASK_RUN_IF_REACHED, @@ -814,7 +829,7 @@ function install_tasks($install_state) { 'run' => INSTALL_TASK_RUN_IF_REACHED, ), 'install_profile_modules' => array( - 'display_name' => count($install_state['profiles']) == 1 ? t('Install site') : t('Installation profile'), + 'display_name' => t('Install site'), 'type' => 'batch', ), 'install_import_translations' => array( @@ -1285,88 +1300,42 @@ function install_settings_form_submit($form, &$form_state) { } /** - * Selects which profile to install. + * Determines the installation profile to use in the installer. * - * @param $install_state - * An array of information about the current installation state. The chosen - * profile will be added here, if it was not already selected previously, as - * will a list of all available profiles. - * - * @return - * For interactive installations, a form allowing the profile to be selected, - * if the user has a choice that needs to be made. Otherwise, an exception is - * thrown if a profile cannot be chosen automatically. - */ -function install_select_profile(&$install_state) { - if (empty($install_state['parameters']['profile'])) { - // Try to find a profile. - $profile = _install_select_profile($install_state['profiles']); - if (empty($profile)) { - // We still don't have a profile, so display a form for selecting one. - // Only do this in the case of interactive installations, since this is - // not a real form with submit handlers (the database isn't even set up - // yet), rather just a convenience method for setting parameters in the - // URL. - if ($install_state['interactive']) { - include_once __DIR__ . '/form.inc'; - drupal_set_title(t('Select an installation profile')); - $form = drupal_get_form('install_select_profile_form', $install_state); - return drupal_render($form); - } - else { - throw new Exception(install_no_profile_error()); - } - } - else { - $install_state['parameters']['profile'] = $profile; - } - } -} - -/** - * Selects an installation profile. + * A profile will be selected in the following order of conditions: * - * A profile will be selected if: - * - Only one profile is available, - * - A profile was submitted through \Drupal::request()->request, - * - Exactly one of the profiles is marked as "exclusive". - * If multiple profiles are marked as "exclusive" then no profile will be - * selected. + * 1. Only one profile is available. + * 2. A specific profile name is requested in installation parameters: + * - for interactive installations via request query parameters. + * - for non-interactive installations via install_drupal() settings. + * 3. A discvered profile that is a distribution. + * If multiple profiles are distributions, then the first discovered profile + * will be selected. * - * @param array $profiles - * An associative array of profiles with the machine-readable names as keys. + * @param array $install_state + * The current installer state, containing a 'profiles' key, which is an + * associative array of profiles with the machine-readable names as keys. * * @return * The machine-readable name of the selected profile or NULL if no profile was * selected. */ -function _install_select_profile($profiles) { +function _install_select_profile(&$install_state) { // Don't need to choose profile if only one available. - $request_params = \Drupal::request()->request; - if (count($profiles) == 1) { - $profile = array_pop($profiles); + if (count($install_state['profiles']) == 1) { + $profile = reset($install_state['profiles']); return $profile->name; } - elseif ($request_params->has('profile') && ($profile = $request_params->get('profile')) && isset($profiles[$profile])) { - return $profiles[$profile]->name; + if (!empty($install_state['parameters']['profile']) && ($profile = $install_state['parameters']['profile']) && isset($install_state['profiles'][$profile])) { + return $install_state['profiles'][$profile]->name; } - // Check for a profile marked as "exclusive" and ensure that only one - // profile is marked as such. - $exclusive_profile = NULL; - foreach ($profiles as $profile) { + // Check for a distribution profile. + foreach ($install_state['profiles'] as $profile) { $profile_info = install_profile_info($profile->name); - if (!empty($profile_info['exclusive'])) { - if (empty($exclusive_profile)) { - $exclusive_profile = $profile->name; - } - else { - // We found a second "exclusive" profile. There's no way to choose - // between them, so we ignore the property. - return; - } + if (!empty($profile_info['distribution'])) { + return $profile->name; } } - return $exclusive_profile; } /** @@ -1378,6 +1347,8 @@ function _install_select_profile($profiles) { * @ingroup forms */ function install_select_profile_form($form, &$form_state, $install_state) { + drupal_set_title(t('Select an installation profile')); + $profiles = array(); $names = array(); @@ -1440,6 +1411,14 @@ function install_select_profile_form($form, &$form_state, $install_state) { } /** + * Form submission handler for install_select_profile_form(). + */ +function install_select_profile_form_submit($form, &$form_state) { + global $install_state; + $install_state['parameters']['profile'] = $form_state['values']['profile']; +} + +/** * Finds all .po files that are useful to the installer. * * @return @@ -1895,7 +1874,7 @@ function install_load_profile(&$install_state) { $profile_file = $install_state['profiles'][$profile]->uri; if (file_exists($profile_file)) { include_once DRUPAL_ROOT . '/' . $profile_file; - $install_state['profile_info'] = install_profile_info($install_state['parameters']['profile'], $install_state['parameters']['langcode']); + $install_state['profile_info'] = install_profile_info($install_state['parameters']['profile'], isset($install_state['parameters']['langcode']) ? $install_state['parameters']['langcode'] : 'en'); } else { throw new Exception(t('Sorry, the profile you have chosen cannot be loaded.')); diff --git a/core/includes/install.inc b/core/includes/install.inc index 8c91dc8..276f08d 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -95,13 +95,13 @@ function drupal_install_profile_distribution_name() { // installation state (it might not be saved anywhere yet). if (drupal_installation_attempted()) { global $install_state; - return isset($install_state['profile_info']['distribution_name']) ? $install_state['profile_info']['distribution_name'] : 'Drupal'; + return isset($install_state['profile_info']['distribution']['name']) ? $install_state['profile_info']['distribution']['name'] : 'Drupal'; } // At all other times, we load the profile via standard methods. else { $profile = drupal_get_profile(); $info = system_get_info('module', $profile); - return $info['distribution_name']; + return $info['distribution']['name']; } } @@ -577,7 +577,7 @@ function drupal_verify_profile($install_state) { // The installation profile is also a module, which needs to be installed // after all the other dependencies have been installed. - $present_modules[] = drupal_get_profile(); + $present_modules[] = $profile; // Verify that all of the profile's required modules are present. $missing_modules = array_diff($info['dependencies'], $present_modules); @@ -1036,15 +1036,14 @@ function drupal_check_module($module) { * Additional, less commonly-used information that can appear in a * profile.info.yml file but not in a normal Drupal module .info.yml file * includes: - * - distribution_name: The name of the Drupal distribution that is being - * installed, to be shown throughout the installation process. Defaults to - * 'Drupal'. - * - exclusive: If the install profile is intended to be the only eligible - * choice in a distribution, setting exclusive = TRUE will auto-select it - * during installation, and the install profile selection screen will be - * skipped. If more than one profile is found where exclusive = TRUE then - * this property will have no effect and the profile selection screen will - * be shown as normal with all available profiles shown. + * - distribution: Existence of this key denotes that the install profile is + * intended to be the only eligible choice in a distribution and will be + * auto-selected during installation, whereas the installation profile + * selection screen will be skipped. If more than one distribution profile is + * found then the first discovered one will be selected. + * The following subproperties may be set: + * - name: The name of the Drupal distribution that is being installed, to be + * shown throughout the installation process. Defaults to 'Drupal'. * * Note that this function does an expensive file system scan to get info file * information for dependencies. If you only need information from the info @@ -1074,7 +1073,6 @@ function install_profile_info($profile, $langcode = 'en') { $defaults = array( 'dependencies' => array(), 'description' => '', - 'distribution_name' => 'Drupal', 'version' => NULL, 'hidden' => FALSE, 'php' => DRUPAL_MINIMUM_PHP, diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 96a0466..f60ab91 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -2556,7 +2556,11 @@ function template_preprocess_install_page(&$variables) { template_preprocess_maintenance_page($variables); // Override the site name that is displayed on the page, since Drupal is // still in the process of being installed. - $variables['site_name'] = drupal_install_profile_distribution_name(); + $distribution_name = String::checkPlain(drupal_install_profile_distribution_name()); + $variables['site_name'] = $distribution_name; + $variables['head_title_array']['name'] = $distribution_name; + + $variables['head_title'] = implode(' | ', $variables['head_title_array']); } /** diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc index 8456eee..e8acd6b 100644 --- a/core/includes/theme.maintenance.inc +++ b/core/includes/theme.maintenance.inc @@ -34,7 +34,12 @@ function _drupal_maintenance_theme() { // Install and update pages are treated differently to prevent theming overrides. if (defined('MAINTENANCE_MODE') && (MAINTENANCE_MODE == 'install' || MAINTENANCE_MODE == 'update')) { - $custom_theme = settings()->get('maintenance_theme', 'seven'); + if (drupal_installation_attempted()) { + $custom_theme = $GLOBALS['install_state']['theme']; + } + else { + $custom_theme = settings()->get('maintenance_theme', 'seven'); + } } else { // The bootstrap was not complete. So we are operating in a crippled diff --git a/core/lib/Drupal/Core/SystemListingInfo.php b/core/lib/Drupal/Core/SystemListingInfo.php index d302699..34a8599 100644 --- a/core/lib/Drupal/Core/SystemListingInfo.php +++ b/core/lib/Drupal/Core/SystemListingInfo.php @@ -19,6 +19,15 @@ class SystemListingInfo extends SystemListing { */ protected function profiles($directory) { $searchdir = array(); + // If install.php is invoked with a ?profile= query parameter, then + // $install_state['parameters']['profile'] will contain that value already, + // drupal_get_profile() will return it, and the below calls to + // drupal_get_path() will call into drupal_get_filename(), which triggers an + // infinite recursion. + // @todo Use SystemListing in install_begin_request()? + if (drupal_installation_attempted() && empty($GLOBALS['install_state']['profiles'])) { + return $searchdir; + } // The 'core/profiles' directory contains pristine collections of modules // and themes as provided by a distribution. It is pristine in the same // way that the 'core/modules' directory is pristine for core; users diff --git a/core/modules/system/system.module b/core/modules/system/system.module index cc647a2..02809e6 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -2648,8 +2648,8 @@ function _system_rebuild_module_data() { $modules[$profile]->info['required'] = TRUE; // Add a default distribution name if the profile did not provide one. This // matches the default value used in install_profile_info(). - if (!isset($modules[$profile]->info['distribution_name'])) { - $modules[$profile]->info['distribution_name'] = 'Drupal'; + if (!isset($modules[$profile]->info['distribution']['name'])) { + $modules[$profile]->info['distribution']['name'] = 'Drupal'; } }