sitePath = $site_path;
$this->renderer = $renderer;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('site.path'),
$container->get('renderer')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'install_settings_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$settings_file = './' . $this->sitePath . '/settings.php';
$form['#title'] = $this->t('Database configuration');
$drivers = drupal_get_database_types();
$drivers_keys = array_keys($drivers);
// Unless there is input for this form (for a non-interactive installation,
// input originates from the $settings array passed into install_drupal()),
// check whether database connection settings have been prepared in
// settings.php already.
// 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).
$input = &$form_state->getUserInput();
if (!isset($input['driver']) && $database = Database::getConnectionInfo()) {
$input['driver'] = $database['default']['driver'];
$input[$database['default']['driver']] = $database['default'];
}
if (isset($input['driver'])) {
$default_driver = $input['driver'];
// In case of database connection info from settings.php, as well as for a
// programmed form submission (non-interactive installer), the table prefix
// information is usually normalized into an array already, but the form
// element only allows to configure one default prefix for all tables.
$prefix = &$input[$default_driver]['prefix'];
if (isset($prefix) && is_array($prefix)) {
$prefix = $prefix['default'];
}
$default_options = $input[$default_driver];
}
// If there is no database information yet, 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 = [];
}
$form['driver'] = [
'#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', ['@driver_name' => $driver->name()]) . '
';
$form['settings'][$key]['#type'] = 'container';
$form['settings'][$key]['#tree'] = TRUE;
$form['settings'][$key]['advanced_options']['#parents'] = [$key];
$form['settings'][$key]['#states'] = [
'visible' => [
':input[name=driver]' => ['value' => $key],
]
];
}
$form['actions'] = ['#type' => 'actions'];
$form['actions']['save'] = [
'#type' => 'submit',
'#value' => $this->t('Save and continue'),
'#button_type' => 'primary',
'#limit_validation_errors' => [
['driver'],
[$default_driver],
],
'#submit' => ['::submitForm'],
];
$form['errors'] = [];
$form['settings_file'] = ['#type' => 'value', '#value' => $settings_file];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
$driver = $form_state->getValue('driver');
$database = $form_state->getValue($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->set('database', $database);
foreach ($this->getDatabaseErrors($database, $form_state->getValue('settings_file')) as $name => $message) {
$form_state->setErrorByName($name, $message);
}
}
/**
* Get any database errors and links them to a form element.
*
* @param array $database
* An array of database settings.
* @param string $settings_file
* The settings file that contains the database settings.
*
* @return array
* An array of form errors keyed by the element name and parents.
*/
protected function getDatabaseErrors(array $database, $settings_file) {
$errors = install_database_errors($database, $settings_file);
$form_errors = array_filter($errors, function ($value) {
// Errors keyed by something other than an integer already are linked to
// form elements.
return is_int($value);
});
// Find the generic errors.
$errors = array_diff_key($errors, $form_errors);
if (count($errors)) {
$error_message = [
'#type' => 'inline_template',
'#template' => '{% trans %}Resolve all issues below to continue the installation. For help configuring your database server, see the installation handbook, or contact your hosting provider.{% endtrans%}{{ errors }}',
'#context' => [
'errors' => [
'#theme' => 'item_list',
'#items' => $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;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
global $install_state;
// Update global settings array and save.
$settings = [];
$database = $form_state->get('database');
$settings['databases']['default']['default'] = (object) [
'value' => $database,
'required' => TRUE,
];
$settings['settings']['hash_salt'] = (object) [
'value' => Crypt::randomBytesBase64(55),
'required' => TRUE,
];
// Remember the profile which was used.
$settings['settings']['install_profile'] = (object) [
'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();
}
}