300def99319f9423a314370bbba51eb1dd54b587
[yaffs-website] / web / core / lib / Drupal / Core / Installer / Form / SiteSettingsForm.php
1 <?php
2
3 namespace Drupal\Core\Installer\Form;
4
5 use Drupal\Component\Utility\Crypt;
6 use Drupal\Core\Database\Database;
7 use Drupal\Core\Form\FormBase;
8 use Drupal\Core\Form\FormStateInterface;
9 use Drupal\Core\Render\RendererInterface;
10 use Symfony\Component\DependencyInjection\ContainerInterface;
11
12 /**
13  * Provides a form to configure and rewrite settings.php.
14  *
15  * @internal
16  */
17 class SiteSettingsForm extends FormBase {
18
19   /**
20    * The site path.
21    *
22    * @var string
23    */
24   protected $sitePath;
25
26   /**
27    * The renderer.
28    *
29    * @var \Drupal\Core\Render\RendererInterface
30    */
31   protected $renderer;
32
33   /**
34    * Constructs a new SiteSettingsForm.
35    *
36    * @param string $site_path
37    *   The site path.
38    */
39   public function __construct($site_path, RendererInterface $renderer) {
40     $this->sitePath = $site_path;
41     $this->renderer = $renderer;
42   }
43
44   /**
45     * {@inheritdoc}
46     */
47   public static function create(ContainerInterface $container) {
48     return new static(
49       $container->get('site.path'),
50       $container->get('renderer')
51     );
52   }
53
54   /**
55    * {@inheritdoc}
56    */
57   public function getFormId() {
58     return 'install_settings_form';
59   }
60
61   /**
62    * {@inheritdoc}
63    */
64   public function buildForm(array $form, FormStateInterface $form_state) {
65     $settings_file = './' . $this->sitePath . '/settings.php';
66
67     $form['#title'] = $this->t('Database configuration');
68
69     $drivers = drupal_get_database_types();
70     $drivers_keys = array_keys($drivers);
71
72     // Unless there is input for this form (for a non-interactive installation,
73     // input originates from the $settings array passed into install_drupal()),
74     // check whether database connection settings have been prepared in
75     // settings.php already.
76     // Note: The installer even executes this form if there is a valid database
77     // connection already, since the submit handler of this form is responsible
78     // for writing all $settings to settings.php (not limited to $databases).
79     $input = &$form_state->getUserInput();
80     if (!isset($input['driver']) && $database = Database::getConnectionInfo()) {
81       $input['driver'] = $database['default']['driver'];
82       $input[$database['default']['driver']] = $database['default'];
83     }
84
85     if (isset($input['driver'])) {
86       $default_driver = $input['driver'];
87       // In case of database connection info from settings.php, as well as for a
88       // programmed form submission (non-interactive installer), the table prefix
89       // information is usually normalized into an array already, but the form
90       // element only allows to configure one default prefix for all tables.
91       $prefix = &$input[$default_driver]['prefix'];
92       if (isset($prefix) && is_array($prefix)) {
93         $prefix = $prefix['default'];
94       }
95       $default_options = $input[$default_driver];
96     }
97     // If there is no database information yet, suggest the first available driver
98     // as default value, so that its settings form is made visible via #states
99     // when JavaScript is enabled (see below).
100     else {
101       $default_driver = current($drivers_keys);
102       $default_options = [];
103     }
104
105     $form['driver'] = [
106       '#type' => 'radios',
107       '#title' => $this->t('Database type'),
108       '#required' => TRUE,
109       '#default_value' => $default_driver,
110     ];
111     if (count($drivers) == 1) {
112       $form['driver']['#disabled'] = TRUE;
113     }
114
115     // Add driver specific configuration options.
116     foreach ($drivers as $key => $driver) {
117       $form['driver']['#options'][$key] = $driver->name();
118
119       $form['settings'][$key] = $driver->getFormOptions($default_options);
120       $form['settings'][$key]['#prefix'] = '<h2 class="js-hide">' . $this->t('@driver_name settings', ['@driver_name' => $driver->name()]) . '</h2>';
121       $form['settings'][$key]['#type'] = 'container';
122       $form['settings'][$key]['#tree'] = TRUE;
123       $form['settings'][$key]['advanced_options']['#parents'] = [$key];
124       $form['settings'][$key]['#states'] = [
125         'visible' => [
126           ':input[name=driver]' => ['value' => $key],
127         ]
128       ];
129     }
130
131     $form['actions'] = ['#type' => 'actions'];
132     $form['actions']['save'] = [
133       '#type' => 'submit',
134       '#value' => $this->t('Save and continue'),
135       '#button_type' => 'primary',
136       '#limit_validation_errors' => [
137         ['driver'],
138         [$default_driver],
139       ],
140       '#submit' => ['::submitForm'],
141     ];
142
143     $form['errors'] = [];
144     $form['settings_file'] = ['#type' => 'value', '#value' => $settings_file];
145
146     return $form;
147   }
148
149   /**
150    * {@inheritdoc}
151    */
152   public function validateForm(array &$form, FormStateInterface $form_state) {
153     $driver = $form_state->getValue('driver');
154     $database = $form_state->getValue($driver);
155     $drivers = drupal_get_database_types();
156     $reflection = new \ReflectionClass($drivers[$driver]);
157     $install_namespace = $reflection->getNamespaceName();
158     // Cut the trailing \Install from namespace.
159     $database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\'));
160     $database['driver'] = $driver;
161
162     $form_state->set('database', $database);
163     foreach ($this->getDatabaseErrors($database, $form_state->getValue('settings_file')) as $name => $message) {
164       $form_state->setErrorByName($name, $message);
165     }
166   }
167
168   /**
169    * Get any database errors and links them to a form element.
170    *
171    * @param array $database
172    *   An array of database settings.
173    * @param string $settings_file
174    *   The settings file that contains the database settings.
175    *
176    * @return array
177    *   An array of form errors keyed by the element name and parents.
178    */
179   protected function getDatabaseErrors(array $database, $settings_file) {
180     $errors = install_database_errors($database, $settings_file);
181     $form_errors = array_filter($errors, function ($value) {
182       // Errors keyed by something other than an integer already are linked to
183       // form elements.
184       return is_int($value);
185     });
186
187     // Find the generic errors.
188     $errors = array_diff_key($errors, $form_errors);
189
190     if (count($errors)) {
191       $error_message = [
192         '#type' => 'inline_template',
193         '#template' => '{% trans %}Resolve all issues below to continue the installation. For help configuring your database server, see the <a href="https://www.drupal.org/getting-started/install">installation handbook</a>, or contact your hosting provider.{% endtrans%}{{ errors }}',
194         '#context' => [
195           'errors' => [
196             '#theme' => 'item_list',
197             '#items' => $errors,
198           ],
199         ],
200       ];
201
202       // These are generic errors, so we do not have any specific key of the
203       // database connection array to attach them to; therefore, we just put
204       // them in the error array with standard numeric keys.
205       $form_errors[$database['driver'] . '][0'] = $this->renderer->renderPlain($error_message);
206     }
207
208     return $form_errors;
209   }
210
211   /**
212    * {@inheritdoc}
213    */
214   public function submitForm(array &$form, FormStateInterface $form_state) {
215     global $install_state;
216
217     // Update global settings array and save.
218     $settings = [];
219     $database = $form_state->get('database');
220     $settings['databases']['default']['default'] = (object) [
221       'value'    => $database,
222       'required' => TRUE,
223     ];
224     $settings['settings']['hash_salt'] = (object) [
225       'value'    => Crypt::randomBytesBase64(55),
226       'required' => TRUE,
227     ];
228     // Remember the profile which was used.
229     $settings['settings']['install_profile'] = (object) [
230       'value' => $install_state['parameters']['profile'],
231       'required' => TRUE,
232     ];
233
234     drupal_rewrite_settings($settings);
235
236     // Add the config directories to settings.php.
237     drupal_install_config_directories();
238
239     // Indicate that the settings file has been verified, and check the database
240     // for the last completed task, now that we have a valid connection. This
241     // last step is important since we want to trigger an error if the new
242     // database already has Drupal installed.
243     $install_state['settings_verified'] = TRUE;
244     $install_state['config_verified'] = TRUE;
245     $install_state['database_verified'] = TRUE;
246     $install_state['completed_task'] = install_verify_completed_task();
247   }
248
249 }