From 16f07ea54783ee067706fe8004bd93e89bd327f7 Mon Sep 17 00:00:00 2001 From: webchick Date: Tue, 22 Apr 2014 21:03:50 -0700 Subject: [PATCH] Issue #2245249 by tim.plunkett: Convert installer forms to FormInterface. --- core/includes/install.core.inc | 550 +----------------- .../Installer/Form/SelectLanguageForm.php | 104 ++++ .../Core/Installer/Form/SelectProfileForm.php | 99 ++++ .../Core/Installer/Form/SiteConfigureForm.php | 278 +++++++++ .../Core/Installer/Form/SiteSettingsForm.php | 165 ++++++ 5 files changed, 657 insertions(+), 539 deletions(-) create mode 100644 core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php create mode 100644 core/lib/Drupal/Core/Installer/Form/SelectProfileForm.php create mode 100644 core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php create mode 100644 core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 202f8d5b275..d0795b8cd3d 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1,11 +1,7 @@ $install_state['settings_verified'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED, + 'function' => 'Drupal\Core\Installer\Form\SiteSettingsForm', ), 'install_base_system' => array( 'run' => $install_state['base_system_verified'] ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_NOT_COMPLETED, @@ -697,6 +694,7 @@ function install_tasks($install_state) { 'install_configure_form' => array( 'display_name' => t('Configure site'), 'type' => 'form', + 'function' => 'Drupal\Core\Installer\Form\SiteConfigureForm', ), ); @@ -811,8 +809,9 @@ function install_get_form($form_id, array &$install_state) { ), 'no_redirect' => TRUE, ); + $form_builder = \Drupal::formBuilder(); if ($install_state['interactive']) { - $form = drupal_build_form($form_id, $form_state); + $form = $form_builder->buildForm($form_id, $form_state); // If the form submission was not successful, the form needs to be rendered, // which means the task is not complete yet. if (empty($form_state['executed'])) { @@ -824,13 +823,14 @@ function install_get_form($form_id, array &$install_state) { // For non-interactive installs, submit the form programmatically with the // values taken from the installation state. $form_state['values'] = array(); - if (!empty($install_state['forms'][$form_id])) { - $form_state['values'] = $install_state['forms'][$form_id]; + $install_form_id = $form_builder->getFormId($form_id, $form_state); + if (!empty($install_state['forms'][$install_form_id])) { + $form_state['values'] = $install_state['forms'][$install_form_id]; } - drupal_form_submit($form_id, $form_state); + $form_builder->submitForm($form_id, $form_state); // Throw an exception in case of any form validation error. - if ($errors = form_get_errors($form_state)) { + if ($errors = $form_builder->getErrors($form_state)) { throw new InstallerException(implode("\n", $errors)); } } @@ -1016,117 +1016,6 @@ function install_verify_database_settings() { return FALSE; } -/** - * Form constructor for a form to configure and rewrite settings.php. - * - * @param $install_state - * An array of information about the current installation state. - * - * @see install_settings_form_validate() - * @see install_settings_form_submit() - * @ingroup forms - */ -function install_settings_form($form, &$form_state, &$install_state) { - global $databases; - - $conf_path = './' . conf_path(FALSE); - $settings_file = $conf_path . '/settings.php'; - - $form['#title'] = t('Database configuration'); - - $drivers = drupal_get_database_types(); - $drivers_keys = array_keys($drivers); - - // If database connection settings have been prepared in settings.php already, - // then the existing values need to be taken over. - // Note: The installer even executes this form if there is a valid database - // connection already, since the submit handler of this form is responsible - // for writing all $settings to settings.php (not limited to $databases). - if (isset($databases['default']['default'])) { - $default_driver = $databases['default']['default']['driver']; - $default_options = $databases['default']['default']; - } - // Otherwise, use the database connection settings from the form input. - // For a non-interactive installation, this is derived from the original - // $settings array passed into install_drupal(). - elseif (isset($form_state['input']['driver'])) { - $default_driver = $form_state['input']['driver']; - $default_options = $form_state['input'][$default_driver]; - } - // If there is no database information at all yet, just suggest the first - // available driver as default value, so that its settings form is made - // visible via #states when JavaScript is enabled (see below). - else { - $default_driver = current($drivers_keys); - $default_options = array(); - } - - $form['driver'] = array( - '#type' => 'radios', - '#title' => t('Database type'), - '#required' => TRUE, - '#default_value' => $default_driver, - ); - if (count($drivers) == 1) { - $form['driver']['#disabled'] = TRUE; - } - - // Add driver specific configuration options. - foreach ($drivers as $key => $driver) { - $form['driver']['#options'][$key] = $driver->name(); - - $form['settings'][$key] = $driver->getFormOptions($default_options); - $form['settings'][$key]['#prefix'] = '

' . t('@driver_name settings', array('@driver_name' => $driver->name())) . '

'; - $form['settings'][$key]['#type'] = 'container'; - $form['settings'][$key]['#tree'] = TRUE; - $form['settings'][$key]['advanced_options']['#parents'] = array($key); - $form['settings'][$key]['#states'] = array( - 'visible' => array( - ':input[name=driver]' => array('value' => $key), - ) - ); - } - - $form['actions'] = array('#type' => 'actions'); - $form['actions']['save'] = array( - '#type' => 'submit', - '#value' => t('Save and continue'), - '#button_type' => 'primary', - '#limit_validation_errors' => array( - array('driver'), - array($default_driver), - ), - '#submit' => array('install_settings_form_submit'), - ); - - $form['errors'] = array(); - $form['settings_file'] = array('#type' => 'value', '#value' => $settings_file); - - return $form; -} - -/** - * Form validation handler for install_settings_form(). - * - * @see install_settings_form_submit() - */ -function install_settings_form_validate($form, &$form_state) { - $driver = $form_state['values']['driver']; - $database = $form_state['values'][$driver]; - $drivers = drupal_get_database_types(); - $reflection = new \ReflectionClass($drivers[$driver]); - $install_namespace = $reflection->getNamespaceName(); - // Cut the trailing \Install from namespace. - $database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\')); - $database['driver'] = $driver; - - $form_state['storage']['database'] = $database; - $errors = install_database_errors($database, $form_state['values']['settings_file']); - foreach ($errors as $name => $message) { - form_set_error($name, $form_state, $message); - } -} - /** * Checks a database connection and returns any errors. */ @@ -1168,46 +1057,6 @@ function install_database_errors($database, $settings_file) { return $errors; } -/** - * Form submission handler for install_settings_form(). - * - * @see install_settings_form_validate() - */ -function install_settings_form_submit($form, &$form_state) { - global $install_state; - - // Update global settings array and save. - $settings = array(); - $database = $form_state['storage']['database']; - $settings['databases']['default']['default'] = (object) array( - 'value' => $database, - 'required' => TRUE, - ); - $settings['settings']['hash_salt'] = (object) array( - 'value' => Crypt::randomBytesBase64(55), - 'required' => TRUE, - ); - // Remember the profile which was used. - $settings['settings']['install_profile'] = (object) array( - 'value' => $install_state['parameters']['profile'], - 'required' => TRUE, - ); - - drupal_rewrite_settings($settings); - - // Add the config directories to settings.php. - drupal_install_config_directories(); - - // Indicate that the settings file has been verified, and check the database - // for the last completed task, now that we have a valid connection. This - // last step is important since we want to trigger an error if the new - // database already has Drupal installed. - $install_state['settings_verified'] = TRUE; - $install_state['config_verified'] = TRUE; - $install_state['database_verified'] = TRUE; - $install_state['completed_task'] = install_verify_completed_task(); -} - /** * Selects which profile to install. * @@ -1237,7 +1086,7 @@ function install_select_profile(&$install_state) { throw new InstallerException(t('Missing profile parameter.')); } // Otherwise, display a form to select a profile. - return install_get_form('install_select_profile_form', $install_state); + return install_get_form('Drupal\Core\Installer\Form\SelectProfileForm', $install_state); } } } @@ -1283,85 +1132,6 @@ function _install_select_profile(&$install_state) { } } -/** - * Form constructor for the profile selection form. - * - * @param array $install_state - * An array of information about the current installation state. - * - * @ingroup forms - */ -function install_select_profile_form($form, &$form_state, $install_state) { - $form['#title'] = t('Select an installation profile'); - - $profiles = array(); - $names = array(); - foreach ($install_state['profiles'] as $profile) { - $details = install_profile_info($profile->getName()); - // Skip this extension if its type is not profile. - if (!isset($details['type']) || $details['type'] != 'profile') { - continue; - } - // Don't show hidden profiles. This is used by to hide the testing profile, - // which only exists to speed up test runs. - if ($details['hidden'] === TRUE) { - continue; - } - $profiles[$profile->getName()] = $details; - - // Determine the name of the profile; default to file name if defined name - // is unspecified. - $name = isset($details['name']) ? $details['name'] : $profile->getName(); - $names[$profile->getName()] = $name; - } - - // Display radio buttons alphabetically by human-readable name, but always - // put the core profiles first (if they are present in the filesystem). - natcasesort($names); - if (isset($names['minimal'])) { - // If the expert ("Minimal") core profile is present, put it in front of - // any non-core profiles rather than including it with them alphabetically, - // since the other profiles might be intended to group together in a - // particular way. - $names = array('minimal' => $names['minimal']) + $names; - } - if (isset($names['standard'])) { - // If the default ("Standard") core profile is present, put it at the very - // top of the list. This profile will have its radio button pre-selected, - // so we want it to always appear at the top. - $names = array('standard' => $names['standard']) + $names; - } - - // The profile name and description are extracted for translation from the - // .info file, so we can use t() on them even though they are dynamic data - // at this point. - $form['profile'] = array( - '#type' => 'radios', - '#title' => t('Select an installation profile'), - '#title_display' => 'invisible', - '#options' => array_map('t', $names), - '#default_value' => 'standard', - ); - foreach (array_keys($names) as $profile) { - $form['profile'][$profile]['#description'] = isset($profiles[$profile]['description']) ? t($profiles[$profile]['description']) : ''; - } - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Save and continue'), - '#button_type' => 'primary', - ); - return $form; -} - -/** - * 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. * @@ -1429,7 +1199,7 @@ function install_select_language(&$install_state) { // translation files were found the form shows a select list of the // corresponding languages to choose from. if ($install_state['interactive']) { - return install_get_form('install_select_language_form', $install_state); + return install_get_form('Drupal\Core\Installer\Form\SelectLanguageForm', $install_state); } // If we are performing a non-interactive installation. If only one language // (English) is available, assume the user knows what he is doing. Otherwise @@ -1446,88 +1216,6 @@ function install_select_language(&$install_state) { } } -/** - * Form constructor for the language selection form. - * - * @param $install_state - * An array of information about the current installation state. - * - * @see file_scan_directory() - * @ingroup forms - */ -function install_select_language_form($form, &$form_state, &$install_state) { - if (count($install_state['translations']) > 1) { - $files = $install_state['translations']; - } - else { - $files = array(); - } - $standard_languages = LanguageManager::getStandardLanguageList(); - $select_options = array(); - $browser_options = array(); - - $form['#title'] = t('Choose language'); - - // Build a select list with language names in native language for the user - // to choose from. And build a list of available languages for the browser - // to select the language default from. - if (count($files)) { - // Select lists based on available language files. - foreach ($files as $langcode => $uri) { - $select_options[$langcode] = isset($standard_languages[$langcode]) ? $standard_languages[$langcode][1] : $langcode; - $browser_options[] = $langcode; - } - } - else { - // Select lists based on all standard languages. - foreach ($standard_languages as $langcode => $language_names) { - $select_options[$langcode] = $language_names[1]; - $browser_options[] = $langcode; - } - } - - $request = Request::createFromGlobals(); - $browser_langcode = UserAgent::getBestMatchingLangcode($request->server->get('HTTP_ACCEPT_LANGUAGE'), $browser_options); - $form['langcode'] = array( - '#type' => 'select', - '#title' => t('Choose language'), - '#title_display' => 'invisible', - '#options' => $select_options, - // Use the browser detected language as default or English if nothing found. - '#default_value' => !empty($browser_langcode) ? $browser_langcode : 'en', - ); - - if (empty($files)) { - $form['help'] = array( - '#type' => 'item', - '#markup' => \Drupal\Component\Utility\String::format('

Translations will be downloaded from the Drupal Translation website. - If you do not want this, select English.

', array( - '!english' => install_full_redirect_url(array('parameters' => array('langcode' => 'en'))), - )), - '#states' => array( - 'invisible' => array( - 'select[name="langcode"]' => array('value' => 'en'), - ), - ), - ); - } - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Save and continue'), - '#button_type' => 'primary', - ); - return $form; -} - -/** - * Form submission handler for the language selection form. - */ -function install_select_language_form_submit($form, &$form_state) { - $install_state = &$form_state['build_info']['args'][0]; - $install_state['parameters']['langcode'] = $form_state['values']['langcode']; -} - /** * Download a translation file for the selected langaguage. * @@ -1943,55 +1631,6 @@ function _install_prepare_import($langcode) { } } -/** - * Form constructor for a form to configure the new site. - * - * @param $install_state - * An array of information about the current installation state. - * - * @see install_configure_form_validate() - * @see install_configure_form_submit() - * @ingroup forms - */ -function install_configure_form($form, &$form_state, &$install_state) { - $form['#title'] = t('Configure site'); - - // Warn about settings.php permissions risk - $settings_dir = conf_path(); - $settings_file = $settings_dir . '/settings.php'; - // Check that $_POST is empty so we only show this message when the form is - // first displayed, not on the next page after it is submitted. (We do not - // want to repeat it multiple times because it is a general warning that is - // not related to the rest of the installation process; it would also be - // especially out of place on the last page of the installer, where it would - // distract from the message that the Drupal installation has completed - // successfully.) - $post_params = \Drupal::request()->request->all(); - if (empty($post_params) && (!drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || !drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_dir, FILE_NOT_WRITABLE, 'dir'))) { - drupal_set_message(t('All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the online handbook.', array('%dir' => $settings_dir, '%file' => $settings_file, '@handbook_url' => 'http://drupal.org/server-permissions')), 'warning'); - } - - $form['#attached']['library'][] = 'system/drupal.system'; - // Add JavaScript time zone detection. - $form['#attached']['library'][] = 'core/drupal.timezone'; - // We add these strings as settings because JavaScript translation does not - // work during installation. - $js = array('copyFieldValue' => array('edit-site-mail' => array('edit-account-mail'))); - $form['#attached']['js'][] = array('data' => $js, 'type' => 'setting'); - - // Cache a fully-built schema. This is necessary for any invocation of - // index.php because: (1) setting cache table entries requires schema - // information, (2) that occurs during bootstrap before any module are - // loaded, so (3) if there is no cached schema, drupal_get_schema() will - // try to generate one but with no loaded modules will return nothing. - // - // @todo Move this to the 'install_finished' task? - drupal_get_schema(NULL, TRUE); - - // Return the form. - return _install_configure_form($form, $form_state, $install_state); -} - /** * Finishes importing files at end of installation. * @@ -2442,170 +2081,3 @@ function install_display_requirements($install_state, $requirements) { } } } - -/** - * Form constructor for a site configuration form. - * - * @param $install_state - * An array of information about the current installation state. - * - * @see install_configure_form() - * @see install_configure_form_validate() - * @see install_configure_form_submit() - * @ingroup forms - */ -function _install_configure_form($form, &$form_state, &$install_state) { - $form['site_information'] = array( - '#type' => 'fieldgroup', - '#title' => t('Site information'), - ); - $form['site_information']['site_name'] = array( - '#type' => 'textfield', - '#title' => t('Site name'), - '#required' => TRUE, - '#weight' => -20, - ); - $form['site_information']['site_mail'] = array( - '#type' => 'email', - '#title' => t('Site e-mail address'), - '#default_value' => ini_get('sendmail_from'), - '#description' => t("Automated e-mails, such as registration information, will be sent from this address. Use an address ending in your site's domain to help prevent these e-mails from being flagged as spam."), - '#required' => TRUE, - '#weight' => -15, - ); - - $form['admin_account'] = array( - '#type' => 'fieldgroup', - '#title' => t('Site maintenance account'), - ); - $form['admin_account']['account']['#tree'] = TRUE; - $form['admin_account']['account']['name'] = array('#type' => 'textfield', - '#title' => t('Username'), - '#maxlength' => USERNAME_MAX_LENGTH, - '#description' => t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, and underscores.'), - '#required' => TRUE, - '#weight' => -10, - '#attributes' => array('class' => array('username')), - ); - $form['admin_account']['account']['mail'] = array( - '#type' => 'email', - '#title' => t('E-mail address'), - '#required' => TRUE, - '#weight' => -5, - ); - $form['admin_account']['account']['pass'] = array( - '#type' => 'password_confirm', - '#required' => TRUE, - '#size' => 25, - '#weight' => 0, - ); - - $form['regional_settings'] = array( - '#type' => 'fieldgroup', - '#title' => t('Regional settings'), - ); - $countries = \Drupal::service('country_manager')->getList(); - $form['regional_settings']['site_default_country'] = array( - '#type' => 'select', - '#title' => t('Default country'), - '#empty_value' => '', - '#default_value' => \Drupal::config('system.date')->get('country.default'), - '#options' => $countries, - '#description' => t('Select the default country for the site.'), - '#weight' => 0, - ); - $form['regional_settings']['date_default_timezone'] = array( - '#type' => 'select', - '#title' => t('Default time zone'), - '#default_value' => date_default_timezone_get(), - '#options' => system_time_zones(), - '#description' => t('By default, dates in this site will be displayed in the chosen time zone.'), - '#weight' => 5, - '#attributes' => array('class' => array('timezone-detect')), - ); - - $form['update_notifications'] = array( - '#type' => 'fieldgroup', - '#title' => t('Update notifications'), - ); - $form['update_notifications']['update_status_module'] = array( - '#type' => 'checkboxes', - '#title' => t('Update notifications'), - '#options' => array( - 1 => t('Check for updates automatically'), - 2 => t('Receive e-mail notifications'), - ), - '#default_value' => array(1, 2), - '#description' => t('The system will notify you when updates and important security releases are available for installed components. Anonymous information about your site is sent to Drupal.org.', array('@drupal' => 'http://drupal.org')), - '#weight' => 15, - ); - $form['update_notifications']['update_status_module'][2] = array( - '#states' => array( - 'visible' => array( - 'input[name="update_status_module[1]"]' => array('checked' => TRUE), - ), - ), - ); - - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Save and continue'), - '#weight' => 15, - '#button_type' => 'primary', - ); - - return $form; -} - -/** - * Form validation handler for install_configure_form(). - * - * @see install_configure_form_submit() - */ -function install_configure_form_validate($form, &$form_state) { - if ($error = user_validate_name($form_state['values']['account']['name'])) { - form_error($form['admin_account']['account']['name'], $form_state, $error); - } -} - -/** - * Form submission handler for install_configure_form(). - * - * @see install_configure_form_validate() - */ -function install_configure_form_submit($form, &$form_state) { - \Drupal::config('system.site') - ->set('name', $form_state['values']['site_name']) - ->set('mail', $form_state['values']['site_mail']) - ->save(); - - \Drupal::config('system.date') - ->set('timezone.default', $form_state['values']['date_default_timezone']) - ->set('country.default', $form_state['values']['site_default_country']) - ->save(); - - // Enable update.module if this option was selected. - if ($form_state['values']['update_status_module'][1]) { - \Drupal::moduleHandler()->install(array('file', 'update'), FALSE); - - // Add the site maintenance account's email address to the list of - // addresses to be notified when updates are available, if selected. - if ($form_state['values']['update_status_module'][2]) { - \Drupal::config('update.settings')->set('notification.emails', array($form_state['values']['account']['mail']))->save(); - } - } - - // We precreated user 1 with placeholder values. Let's save the real values. - $account = user_load(1); - $account->init = $account->mail = $form_state['values']['account']['mail']; - $account->roles = $account->getRoles(); - $account->activate(); - $account->timezone = $form_state['values']['date_default_timezone']; - $account->pass = $form_state['values']['account']['pass']; - $account->name = $form_state['values']['account']['name']; - $account->save(); - - // Record when this install ran. - \Drupal::state()->set('install_time', $_SERVER['REQUEST_TIME']); -} diff --git a/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php b/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php new file mode 100644 index 00000000000..d3667f7d785 --- /dev/null +++ b/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php @@ -0,0 +1,104 @@ + 1) { + $files = $install_state['translations']; + } + else { + $files = array(); + } + $standard_languages = LanguageManager::getStandardLanguageList(); + $select_options = array(); + $browser_options = array(); + + $form['#title'] = $this->t('Choose language'); + + // Build a select list with language names in native language for the user + // to choose from. And build a list of available languages for the browser + // to select the language default from. + if (count($files)) { + // Select lists based on available language files. + foreach ($files as $langcode => $uri) { + $select_options[$langcode] = isset($standard_languages[$langcode]) ? $standard_languages[$langcode][1] : $langcode; + $browser_options[] = $langcode; + } + } + else { + // Select lists based on all standard languages. + foreach ($standard_languages as $langcode => $language_names) { + $select_options[$langcode] = $language_names[1]; + $browser_options[] = $langcode; + } + } + + $request = Request::createFromGlobals(); + $browser_langcode = UserAgent::getBestMatchingLangcode($request->server->get('HTTP_ACCEPT_LANGUAGE'), $browser_options); + $form['langcode'] = array( + '#type' => 'select', + '#title' => $this->t('Choose language'), + '#title_display' => 'invisible', + '#options' => $select_options, + // Use the browser detected language as default or English if nothing found. + '#default_value' => !empty($browser_langcode) ? $browser_langcode : 'en', + ); + + if (empty($files)) { + $form['help'] = array( + '#type' => 'item', + '#markup' => String::format('

Translations will be downloaded from the Drupal Translation website. + If you do not want this, select English.

', array( + '!english' => install_full_redirect_url(array('parameters' => array('langcode' => 'en'))), + )), + '#states' => array( + 'invisible' => array( + 'select[name="langcode"]' => array('value' => 'en'), + ), + ), + ); + } + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => $this->t('Save and continue'), + '#button_type' => 'primary', + ); + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $install_state = &$form_state['build_info']['args'][0]; + $install_state['parameters']['langcode'] = $form_state['values']['langcode']; + } + +} diff --git a/core/lib/Drupal/Core/Installer/Form/SelectProfileForm.php b/core/lib/Drupal/Core/Installer/Form/SelectProfileForm.php new file mode 100644 index 00000000000..38bb96f132b --- /dev/null +++ b/core/lib/Drupal/Core/Installer/Form/SelectProfileForm.php @@ -0,0 +1,99 @@ +t('Select an installation profile'); + + $profiles = array(); + $names = array(); + foreach ($install_state['profiles'] as $profile) { + /** @var $profile \Drupal\Core\Extension\Extension */ + $details = install_profile_info($profile->getName()); + // Skip this extension if its type is not profile. + if (!isset($details['type']) || $details['type'] != 'profile') { + continue; + } + // Don't show hidden profiles. This is used by to hide the testing profile, + // which only exists to speed up test runs. + if ($details['hidden'] === TRUE) { + continue; + } + $profiles[$profile->getName()] = $details; + + // Determine the name of the profile; default to file name if defined name + // is unspecified. + $name = isset($details['name']) ? $details['name'] : $profile->getName(); + $names[$profile->getName()] = $name; + } + + // Display radio buttons alphabetically by human-readable name, but always + // put the core profiles first (if they are present in the filesystem). + natcasesort($names); + if (isset($names['minimal'])) { + // If the expert ("Minimal") core profile is present, put it in front of + // any non-core profiles rather than including it with them alphabetically, + // since the other profiles might be intended to group together in a + // particular way. + $names = array('minimal' => $names['minimal']) + $names; + } + if (isset($names['standard'])) { + // If the default ("Standard") core profile is present, put it at the very + // top of the list. This profile will have its radio button pre-selected, + // so we want it to always appear at the top. + $names = array('standard' => $names['standard']) + $names; + } + + // The profile name and description are extracted for translation from the + // .info file, so we can use $this->t() on them even though they are dynamic + // data at this point. + $form['profile'] = array( + '#type' => 'radios', + '#title' => $this->t('Select an installation profile'), + '#title_display' => 'invisible', + '#options' => array_map(array($this, 't'), $names), + '#default_value' => 'standard', + ); + foreach (array_keys($names) as $profile_name) { + $form['profile'][$profile_name]['#description'] = isset($profiles[$profile_name]['description']) ? $this->t($profiles[$profile_name]['description']) : ''; + } + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => $this->t('Save and continue'), + '#button_type' => 'primary', + ); + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + global $install_state; + $install_state['parameters']['profile'] = $form_state['values']['profile']; + } + +} diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php new file mode 100644 index 00000000000..fdb6783ef28 --- /dev/null +++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php @@ -0,0 +1,278 @@ +userStorage = $user_storage; + $this->state = $state; + $this->moduleHandler = $module_handler; + $this->countryManager = $country_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('entity.manager')->getStorage('user'), + $container->get('state'), + $container->get('module_handler'), + $container->get('country_manager') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() { + return 'install_configure_form'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $form['#title'] = $this->t('Configure site'); + + // Warn about settings.php permissions risk + $settings_dir = conf_path(); + $settings_file = $settings_dir . '/settings.php'; + // Check that $_POST is empty so we only show this message when the form is + // first displayed, not on the next page after it is submitted. (We do not + // want to repeat it multiple times because it is a general warning that is + // not related to the rest of the installation process; it would also be + // especially out of place on the last page of the installer, where it would + // distract from the message that the Drupal installation has completed + // successfully.) + $post_params = $this->getRequest()->request->all(); + if (empty($post_params) && (!drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || !drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_dir, FILE_NOT_WRITABLE, 'dir'))) { + drupal_set_message(t('All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the online handbook.', array('%dir' => $settings_dir, '%file' => $settings_file, '@handbook_url' => 'http://drupal.org/server-permissions')), 'warning'); + } + + $form['#attached']['library'][] = 'system/drupal.system'; + // Add JavaScript time zone detection. + $form['#attached']['library'][] = 'core/drupal.timezone'; + // We add these strings as settings because JavaScript translation does not + // work during installation. + $js = array('copyFieldValue' => array('edit-site-mail' => array('edit-account-mail'))); + $form['#attached']['js'][] = array('data' => $js, 'type' => 'setting'); + + // Cache a fully-built schema. This is necessary for any invocation of + // index.php because: (1) setting cache table entries requires schema + // information, (2) that occurs during bootstrap before any module are + // loaded, so (3) if there is no cached schema, drupal_get_schema() will + // try to generate one but with no loaded modules will return nothing. + // + // @todo Move this to the 'install_finished' task? + drupal_get_schema(NULL, TRUE); + + $form['site_information'] = array( + '#type' => 'fieldgroup', + '#title' => $this->t('Site information'), + ); + $form['site_information']['site_name'] = array( + '#type' => 'textfield', + '#title' => $this->t('Site name'), + '#required' => TRUE, + '#weight' => -20, + ); + $form['site_information']['site_mail'] = array( + '#type' => 'email', + '#title' => $this->t('Site e-mail address'), + '#default_value' => ini_get('sendmail_from'), + '#description' => $this->t("Automated e-mails, such as registration information, will be sent from this address. Use an address ending in your site's domain to help prevent these e-mails from being flagged as spam."), + '#required' => TRUE, + '#weight' => -15, + ); + + $form['admin_account'] = array( + '#type' => 'fieldgroup', + '#title' => $this->t('Site maintenance account'), + ); + $form['admin_account']['account']['#tree'] = TRUE; + $form['admin_account']['account']['name'] = array( + '#type' => 'textfield', + '#title' => $this->t('Username'), + '#maxlength' => USERNAME_MAX_LENGTH, + '#description' => $this->t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, and underscores.'), + '#required' => TRUE, + '#weight' => -10, + '#attributes' => array('class' => array('username')), + ); + $form['admin_account']['account']['mail'] = array( + '#type' => 'email', + '#title' => $this->t('E-mail address'), + '#required' => TRUE, + '#weight' => -5, + ); + $form['admin_account']['account']['pass'] = array( + '#type' => 'password_confirm', + '#required' => TRUE, + '#size' => 25, + '#weight' => 0, + ); + + $form['regional_settings'] = array( + '#type' => 'fieldgroup', + '#title' => $this->t('Regional settings'), + ); + $countries = $this->countryManager->getList(); + $form['regional_settings']['site_default_country'] = array( + '#type' => 'select', + '#title' => $this->t('Default country'), + '#empty_value' => '', + '#default_value' => $this->config('system.date')->get('country.default'), + '#options' => $countries, + '#description' => $this->t('Select the default country for the site.'), + '#weight' => 0, + ); + $form['regional_settings']['date_default_timezone'] = array( + '#type' => 'select', + '#title' => $this->t('Default time zone'), + '#default_value' => date_default_timezone_get(), + '#options' => system_time_zones(), + '#description' => $this->t('By default, dates in this site will be displayed in the chosen time zone.'), + '#weight' => 5, + '#attributes' => array('class' => array('timezone-detect')), + ); + + $form['update_notifications'] = array( + '#type' => 'fieldgroup', + '#title' => $this->t('Update notifications'), + ); + $form['update_notifications']['update_status_module'] = array( + '#type' => 'checkboxes', + '#title' => $this->t('Update notifications'), + '#options' => array( + 1 => $this->t('Check for updates automatically'), + 2 => $this->t('Receive e-mail notifications'), + ), + '#default_value' => array(1, 2), + '#description' => $this->t('The system will notify you when updates and important security releases are available for installed components. Anonymous information about your site is sent to Drupal.org.', array('@drupal' => 'http://drupal.org')), + '#weight' => 15, + ); + $form['update_notifications']['update_status_module'][2] = array( + '#states' => array( + 'visible' => array( + 'input[name="update_status_module[1]"]' => array('checked' => TRUE), + ), + ), + ); + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => $this->t('Save and continue'), + '#weight' => 15, + '#button_type' => 'primary', + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + if ($error = user_validate_name($form_state['values']['account']['name'])) { + $this->setFormError('account][name', $form_state, $error); + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $this->config('system.site') + ->set('name', $form_state['values']['site_name']) + ->set('mail', $form_state['values']['site_mail']) + ->save(); + + $this->config('system.date') + ->set('timezone.default', $form_state['values']['date_default_timezone']) + ->set('country.default', $form_state['values']['site_default_country']) + ->save(); + + // Enable update.module if this option was selected. + if ($form_state['values']['update_status_module'][1]) { + $this->moduleHandler->install(array('file', 'update'), FALSE); + + // Add the site maintenance account's email address to the list of + // addresses to be notified when updates are available, if selected. + if ($form_state['values']['update_status_module'][2]) { + $this->config('update.settings')->set('notification.emails', array($form_state['values']['account']['mail']))->save(); + } + } + + // We precreated user 1 with placeholder values. Let's save the real values. + $account = $this->userStorage->load(1); + $account->init = $account->mail = $form_state['values']['account']['mail']; + $account->roles = $account->getRoles(); + $account->activate(); + $account->timezone = $form_state['values']['date_default_timezone']; + $account->pass = $form_state['values']['account']['pass']; + $account->name = $form_state['values']['account']['name']; + $account->save(); + + // Record when this install ran. + $this->state->set('install_time', $_SERVER['REQUEST_TIME']); + } + +} diff --git a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php new file mode 100644 index 00000000000..0d4f599e58d --- /dev/null +++ b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php @@ -0,0 +1,165 @@ +t('Database configuration'); + + $drivers = drupal_get_database_types(); + $drivers_keys = array_keys($drivers); + + // If database connection settings have been prepared in settings.php already, + // then the existing values need to be taken over. + // Note: The installer even executes this form if there is a valid database + // connection already, since the submit handler of this form is responsible + // for writing all $settings to settings.php (not limited to $databases). + if (isset($databases['default']['default'])) { + $default_driver = $databases['default']['default']['driver']; + $default_options = $databases['default']['default']; + } + // Otherwise, use the database connection settings from the form input. + // For a non-interactive installation, this is derived from the original + // $settings array passed into install_drupal(). + elseif (isset($form_state['input']['driver'])) { + $default_driver = $form_state['input']['driver']; + $default_options = $form_state['input'][$default_driver]; + } + // If there is no database information at all yet, just suggest the first + // available driver as default value, so that its settings form is made + // visible via #states when JavaScript is enabled (see below). + else { + $default_driver = current($drivers_keys); + $default_options = array(); + } + + $form['driver'] = array( + '#type' => 'radios', + '#title' => $this->t('Database type'), + '#required' => TRUE, + '#default_value' => $default_driver, + ); + if (count($drivers) == 1) { + $form['driver']['#disabled'] = TRUE; + } + + // Add driver specific configuration options. + foreach ($drivers as $key => $driver) { + $form['driver']['#options'][$key] = $driver->name(); + + $form['settings'][$key] = $driver->getFormOptions($default_options); + $form['settings'][$key]['#prefix'] = '

' . $this->t('@driver_name settings', array('@driver_name' => $driver->name())) . '

'; + $form['settings'][$key]['#type'] = 'container'; + $form['settings'][$key]['#tree'] = TRUE; + $form['settings'][$key]['advanced_options']['#parents'] = array($key); + $form['settings'][$key]['#states'] = array( + 'visible' => array( + ':input[name=driver]' => array('value' => $key), + ) + ); + } + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['save'] = array( + '#type' => 'submit', + '#value' => $this->t('Save and continue'), + '#button_type' => 'primary', + '#limit_validation_errors' => array( + array('driver'), + array($default_driver), + ), + '#submit' => array(array($this, 'submitForm')), + ); + + $form['errors'] = array(); + $form['settings_file'] = array('#type' => 'value', '#value' => $settings_file); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + $driver = $form_state['values']['driver']; + $database = $form_state['values'][$driver]; + $drivers = drupal_get_database_types(); + $reflection = new \ReflectionClass($drivers[$driver]); + $install_namespace = $reflection->getNamespaceName(); + // Cut the trailing \Install from namespace. + $database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\')); + $database['driver'] = $driver; + + $form_state['storage']['database'] = $database; + $errors = install_database_errors($database, $form_state['values']['settings_file']); + foreach ($errors as $name => $message) { + $this->setFormError($name, $form_state, $message); + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + global $install_state; + + // Update global settings array and save. + $settings = array(); + $database = $form_state['storage']['database']; + $settings['databases']['default']['default'] = (object) array( + 'value' => $database, + 'required' => TRUE, + ); + $settings['settings']['hash_salt'] = (object) array( + 'value' => Crypt::randomBytesBase64(55), + 'required' => TRUE, + ); + // Remember the profile which was used. + $settings['settings']['install_profile'] = (object) array( + 'value' => $install_state['parameters']['profile'], + 'required' => TRUE, + ); + + drupal_rewrite_settings($settings); + + // Add the config directories to settings.php. + drupal_install_config_directories(); + + // Indicate that the settings file has been verified, and check the database + // for the last completed task, now that we have a valid connection. This + // last step is important since we want to trigger an error if the new + // database already has Drupal installed. + $install_state['settings_verified'] = TRUE; + $install_state['config_verified'] = TRUE; + $install_state['database_verified'] = TRUE; + $install_state['completed_task'] = install_verify_completed_task(); + } + +}