3 namespace Drupal\migrate_drupal_ui\Form;
5 use Drupal\Component\Utility\UrlHelper;
6 use Drupal\Core\Form\FormStateInterface;
7 use Drupal\Core\Render\RendererInterface;
8 use Drupal\Core\TempStore\PrivateTempStoreFactory;
9 use GuzzleHttp\ClientInterface;
10 use GuzzleHttp\Exception\TransferException;
11 use Symfony\Component\DependencyInjection\ContainerInterface;
14 * Migrate Upgrade database credential form.
18 class CredentialForm extends MigrateUpgradeFormBase {
21 * The renderer service.
23 * @var \Drupal\Core\Render\RendererInterface
28 * The HTTP client to fetch the files with.
30 * @var \GuzzleHttp\ClientInterface
32 protected $httpClient;
35 * An array of error information.
39 protected $errors = [];
42 * CredentialForm constructor.
44 * @param \Drupal\Core\Render\RendererInterface $renderer
45 * The renderer service.
46 * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private
47 * The private tempstore factory.
48 * @param \GuzzleHttp\ClientInterface $http_client
49 * A Guzzle client object.
51 public function __construct(RendererInterface $renderer, PrivateTempStoreFactory $tempstore_private, ClientInterface $http_client) {
52 parent::__construct($tempstore_private);
53 $this->renderer = $renderer;
54 $this->httpClient = $http_client;
60 public static function create(ContainerInterface $container) {
62 $container->get('renderer'),
63 $container->get('tempstore.private'),
64 $container->get('http_client')
71 public function getFormId() {
72 return 'migrate_drupal_ui_credential_form';
78 public function buildForm(array $form, FormStateInterface $form_state) {
79 if ($this->store->get('step') != 'credential') {
80 return $this->restartUpgradeForm();
83 $form = parent::buildForm($form, $form_state);
84 $form['actions']['submit']['#value'] = $this->t('Review upgrade');
86 $form['#title'] = $this->t('Drupal Upgrade');
88 $drivers = $this->getDatabaseTypes();
89 $drivers_keys = array_keys($drivers);
90 // @todo https://www.drupal.org/node/2678510 Because this is a multi-step
91 // form, the form is not rebuilt during submission. Ideally we would get
92 // the chosen driver from form input, if available, in order to use
93 // #limit_validation_errors in the same way
94 // \Drupal\Core\Installer\Form\SiteSettingsForm does.
95 $default_driver = current($drivers_keys);
97 $default_options = [];
101 '#description' => $this->t('Provide the information to access the Drupal site you want to upgrade. Files can be imported into the upgraded site as well. See the <a href=":url">Upgrade documentation for more detailed instructions</a>.', [':url' => 'https://www.drupal.org/upgrade/migrate']),
106 '#default_value' => 7,
107 '#title' => $this->t('Drupal version of the source site'),
108 '#options' => ['6' => $this->t('Drupal 6'), '7' => $this->t('Drupal 7')],
112 $form['database'] = [
113 '#type' => 'details',
114 '#title' => $this->t('Source database'),
115 '#description' => $this->t('Provide credentials for the database of the Drupal site you want to upgrade.'),
119 $form['database']['driver'] = [
121 '#title' => $this->t('Database type'),
123 '#default_value' => $default_driver,
125 if (count($drivers) == 1) {
126 $form['database']['driver']['#disabled'] = TRUE;
129 // Add driver-specific configuration options.
130 foreach ($drivers as $key => $driver) {
131 $form['database']['driver']['#options'][$key] = $driver->name();
133 $form['database']['settings'][$key] = $driver->getFormOptions($default_options);
134 // @todo https://www.drupal.org/node/2678510 Using
135 // #limit_validation_errors in the submit does not work so it is not
136 // possible to require the database and username for mysql and pgsql.
137 // This is because this is a multi-step form.
138 $form['database']['settings'][$key]['database']['#required'] = FALSE;
139 $form['database']['settings'][$key]['username']['#required'] = FALSE;
140 $form['database']['settings'][$key]['#prefix'] = '<h2 class="js-hide">' . $this->t('@driver_name settings', ['@driver_name' => $driver->name()]) . '</h2>';
141 $form['database']['settings'][$key]['#type'] = 'container';
142 $form['database']['settings'][$key]['#tree'] = TRUE;
143 $form['database']['settings'][$key]['advanced_options']['#parents'] = [$key];
144 $form['database']['settings'][$key]['#states'] = [
146 ':input[name=driver]' => ['value' => $key],
150 // Move the host fields out of advanced settings.
151 if (isset($form['database']['settings'][$key]['advanced_options']['host'])) {
152 $form['database']['settings'][$key]['host'] = $form['database']['settings'][$key]['advanced_options']['host'];
153 $form['database']['settings'][$key]['host']['#title'] = 'Database host';
154 $form['database']['settings'][$key]['host']['#weight'] = -1;
155 unset($form['database']['settings'][$key]['database']['#default_value']);
156 unset($form['database']['settings'][$key]['advanced_options']['host']);
161 '#type' => 'details',
162 '#title' => $this->t('Source files'),
165 $form['source']['d6_source_base_path'] = [
166 '#type' => 'textfield',
167 '#title' => $this->t('Files directory'),
168 '#description' => $this->t('To import files from your current Drupal site, enter a local file directory containing your site (e.g. /var/www/docroot), or your site address (for example http://example.com).'),
171 ':input[name="version"]' => ['value' => '6'],
174 '#element_validate' => ['::validatePaths'],
177 $form['source']['source_base_path'] = [
178 '#type' => 'textfield',
179 '#title' => $this->t('Public files directory'),
180 '#description' => $this->t('To import public files from your current Drupal site, enter a local file directory containing your site (e.g. /var/www/docroot), or your site address (for example http://example.com).'),
183 ':input[name="version"]' => ['value' => '7'],
186 '#element_validate' => ['::validatePaths'],
189 $form['source']['source_private_file_path'] = [
190 '#type' => 'textfield',
191 '#title' => $this->t('Private files directory'),
192 '#default_value' => '',
193 '#description' => $this->t('To import private files from your current Drupal site, enter a local file directory containing your site (e.g. /var/www/docroot).'),
196 ':input[name="version"]' => ['value' => '7'],
199 '#element_validate' => ['::validatePaths'],
208 public function validateForm(array &$form, FormStateInterface $form_state) {
209 // Retrieve the database driver from the form, use reflection to get the
210 // namespace, and then construct a valid database array the same as in
212 $driver = $form_state->getValue('driver');
213 $drivers = $this->getDatabaseTypes();
214 $reflection = new \ReflectionClass($drivers[$driver]);
215 $install_namespace = $reflection->getNamespaceName();
217 $database = $form_state->getValue($driver);
218 // Cut the trailing \Install from namespace.
219 $database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\'));
220 $database['driver'] = $driver;
222 // Validate the driver settings and just end here if we have any issues.
223 if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) {
224 foreach ($errors as $name => $message) {
225 $this->errors[$name] = $message;
230 $connection = $this->getConnection($database);
231 $version = (string) $this->getLegacyDrupalVersion($connection);
233 $this->errors[$database['driver'] . '][database'] = $this->t('Source database does not contain a recognizable Drupal version.');
235 elseif ($version !== (string) $form_state->getValue('version')) {
236 $this->errors['version'] = $this->t('Source database is Drupal version @version but version @selected was selected.',
238 '@version' => $version,
239 '@selected' => $form_state->getValue('version'),
243 // Setup migrations and save form data to private store.
244 $this->setupMigrations($database, $form_state);
247 catch (\Exception $e) {
248 $this->errors[$database['driver'] . '][database'] = $e->getMessage();
252 // Display all errors as a list of items.
254 $form_state->setError($form, $this->t('<h3>Resolve all issues below to continue the upgrade.</h3>'));
255 foreach ($this->errors as $name => $message) {
256 $form_state->setErrorByName($name, $message);
262 * The #element_validate handler for the source path elements.
264 * Ensures that entered path can be read.
266 public function validatePaths($element, FormStateInterface $form_state) {
267 if ($source = $element['#value']) {
268 $msg = $this->t('Unable to read from @title.', ['@title' => $element['#title']]);
269 if (UrlHelper::isExternal($source)) {
271 $this->httpClient->head($source);
273 catch (TransferException $e) {
274 $this->errors[$element['#name']] = $msg . ' ' . $e->getMessage();
277 elseif (!file_exists($source) || (!is_dir($source)) || (!is_readable($source))) {
278 $this->errors[$element['#name']] = $msg;
286 public function submitForm(array &$form, FormStateInterface $form_state) {
287 $this->store->set('step', 'idconflict');
288 $form_state->setRedirect('migrate_drupal_ui.upgrade_idconflict');
294 public function getConfirmText() {
295 return $this->t('Review upgrade');
299 * Returns all supported database driver installer objects.
301 * @return \Drupal\Core\Database\Install\Tasks[]
302 * An array of available database driver installer objects.
304 protected function getDatabaseTypes() {
305 // Make sure the install API is available.
306 include_once DRUPAL_ROOT . '/core/includes/install.inc';
307 return drupal_get_database_types();