3 namespace Drupal\migrate_drupal_ui\Form;
5 use Drupal\Core\Datetime\DateFormatterInterface;
6 use Drupal\Core\Form\ConfirmFormBase;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\Core\Render\RendererInterface;
9 use Drupal\Core\State\StateInterface;
11 use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
12 use Drupal\migrate_drupal_ui\Batch\MigrateUpgradeImportBatch;
13 use Drupal\migrate_drupal\MigrationConfigurationTrait;
14 use Symfony\Component\DependencyInjection\ContainerInterface;
17 * Defines a multi-step form for performing direct site upgrades.
19 class MigrateUpgradeForm extends ConfirmFormBase {
21 use MigrationConfigurationTrait;
24 * Mapping of known migrations and their source and destination modules.
26 * @todo https://www.drupal.org/node/2569805 Hardcoding this information is
27 * not robust - the migrations themselves should hold the necessary
32 protected $moduleUpgradePaths = [
33 'action_settings' => [
34 'source_module' => 'system',
35 'destination_module' => 'action',
37 'd6_aggregator_feed' => [
38 'source_module' => 'aggregator',
39 'destination_module' => 'aggregator',
41 'd6_aggregator_item' => [
42 'source_module' => 'aggregator',
43 'destination_module' => 'aggregator',
45 'd6_aggregator_settings' => [
46 'source_module' => 'aggregator',
47 'destination_module' => 'aggregator',
49 'd7_aggregator_feed' => [
50 'source_module' => 'aggregator',
51 'destination_module' => 'aggregator',
53 'd7_aggregator_item' => [
54 'source_module' => 'aggregator',
55 'destination_module' => 'aggregator',
57 'd7_aggregator_settings' => [
58 'source_module' => 'aggregator',
59 'destination_module' => 'aggregator',
62 'source_module' => 'system',
63 'destination_module' => 'ban',
66 'source_module' => 'block',
67 'destination_module' => 'block',
70 'source_module' => 'block',
71 'destination_module' => 'block',
73 'block_content_entity_form_display' => [
74 'source_module' => 'block',
75 'destination_module' => 'block_content',
77 'block_content_entity_display' => [
78 'source_module' => 'block',
79 'destination_module' => 'block_content',
81 'block_content_body_field' => [
82 'source_module' => 'block',
83 'destination_module' => 'block_content',
85 'block_content_type' => [
86 'source_module' => 'block',
87 'destination_module' => 'block_content',
89 'd6_custom_block' => [
90 'source_module' => 'block',
91 'destination_module' => 'block_content',
93 'd7_custom_block' => [
94 'source_module' => 'block',
95 'destination_module' => 'block_content',
98 'source_module' => 'book',
99 'destination_module' => 'book',
101 'd6_book_settings' => [
102 'source_module' => 'book',
103 'destination_module' => 'book',
106 'source_module' => 'comment',
107 'destination_module' => 'comment',
109 'd6_comment_entity_display' => [
110 'source_module' => 'comment',
111 'destination_module' => 'comment',
113 'd6_comment_entity_form_display' => [
114 'source_module' => 'comment',
115 'destination_module' => 'comment',
117 'd6_comment_entity_form_display_subject' => [
118 'source_module' => 'comment',
119 'destination_module' => 'comment',
121 'd6_comment_field' => [
122 'source_module' => 'comment',
123 'destination_module' => 'comment',
125 'd6_comment_field_instance' => [
126 'source_module' => 'comment',
127 'destination_module' => 'comment',
129 'd6_comment_type' => [
130 'source_module' => 'comment',
131 'destination_module' => 'comment',
134 'source_module' => 'comment',
135 'destination_module' => 'comment',
137 'd7_comment_entity_display' => [
138 'source_module' => 'comment',
139 'destination_module' => 'comment',
141 'd7_comment_entity_form_display' => [
142 'source_module' => 'comment',
143 'destination_module' => 'comment',
145 'd7_comment_entity_form_display_subject' => [
146 'source_module' => 'comment',
147 'destination_module' => 'comment',
149 'd7_comment_field' => [
150 'source_module' => 'comment',
151 'destination_module' => 'comment',
153 'd7_comment_field_instance' => [
154 'source_module' => 'comment',
155 'destination_module' => 'comment',
157 'd7_comment_type' => [
158 'source_module' => 'comment',
159 'destination_module' => 'comment',
161 'contact_category' => [
162 'source_module' => 'contact',
163 'destination_module' => 'contact',
165 'd6_contact_settings' => [
166 'source_module' => 'contact',
167 'destination_module' => 'contact',
169 'd7_contact_settings' => [
170 'source_module' => 'contact',
171 'destination_module' => 'contact',
173 'd6_dblog_settings' => [
174 'source_module' => 'dblog',
175 'destination_module' => 'dblog',
177 'd7_dblog_settings' => [
178 'source_module' => 'dblog',
179 'destination_module' => 'dblog',
181 'default_language' => [
182 'source_module' => 'locale',
183 'destination_module' => 'language',
186 'source_module' => 'content',
187 'destination_module' => 'field',
189 'd6_field_formatter_settings' => [
190 'source_module' => 'content',
191 'destination_module' => 'field',
193 'd6_field_instance' => [
194 'source_module' => 'content',
195 'destination_module' => 'field',
197 'd6_field_instance_widget_settings' => [
198 'source_module' => 'content',
199 'destination_module' => 'field',
202 'source_module' => 'field',
203 'destination_module' => 'field',
205 'd7_field_formatter_settings' => [
206 'source_module' => 'field',
207 'destination_module' => 'field',
209 'd7_field_instance' => [
210 'source_module' => 'field',
211 'destination_module' => 'field',
213 'd7_field_instance_widget_settings' => [
214 'source_module' => 'field',
215 'destination_module' => 'field',
218 'source_module' => 'field',
219 'destination_module' => 'field',
222 'source_module' => 'system',
223 'destination_module' => 'file',
226 'source_module' => 'system',
227 'destination_module' => 'file',
230 'source_module' => 'upload',
231 'destination_module' => 'file',
233 'd6_upload_entity_display' => [
234 'source_module' => 'upload',
235 'destination_module' => 'file',
237 'd6_upload_entity_form_display' => [
238 'source_module' => 'upload',
239 'destination_module' => 'file',
241 'd6_upload_field' => [
242 'source_module' => 'upload',
243 'destination_module' => 'file',
245 'd6_upload_field_instance' => [
246 'source_module' => 'upload',
247 'destination_module' => 'file',
250 'source_module' => 'file',
251 'destination_module' => 'file',
253 'd6_filter_format' => [
254 'source_module' => 'filter',
255 'destination_module' => 'filter',
257 'd7_filter_format' => [
258 'source_module' => 'filter',
259 'destination_module' => 'filter',
261 'd7_filter_settings' => [
262 'source_module' => 'filter',
263 'destination_module' => 'filter',
265 'd6_forum_settings' => [
266 'source_module' => 'forum',
267 'destination_module' => 'forum',
269 'd7_forum_settings' => [
270 'source_module' => 'forum',
271 'destination_module' => 'forum',
273 'd7_global_theme_settings' => [
274 'source_module' => 'system',
275 'destination_module' => 'system',
277 'd6_imagecache_presets' => [
278 'source_module' => 'imagecache',
279 'destination_module' => 'image',
281 'd7_image_settings' => [
282 'source_module' => 'image',
283 'destination_module' => 'image',
285 'd7_image_styles' => [
286 'source_module' => 'image',
287 'destination_module' => 'image',
289 'd6_language_content_settings' => [
290 'source_module' => 'locale',
291 'destination_module' => 'language',
293 'd7_language_content_settings' => [
294 'source_module' => 'locale',
295 'destination_module' => 'language',
297 'd6_language_negotiation_settings' => [
298 'source_module' => 'locale',
299 'destination_module' => 'language',
301 'd7_language_negotiation_settings' => [
302 'source_module' => 'locale',
303 'destination_module' => 'language',
305 'language_prefixes_and_domains' => [
306 'source_module' => 'locale',
307 'destination_module' => 'language',
309 'd6_language_types' => [
310 'source_module' => 'locale',
311 'destination_module' => 'language',
314 'source_module' => 'locale',
315 'destination_module' => 'language',
317 'd7_language_types' => [
318 'source_module' => 'locale',
319 'destination_module' => 'language',
321 'locale_settings' => [
322 'source_module' => 'locale',
323 'destination_module' => 'locale',
326 'source_module' => 'menu',
327 'destination_module' => 'menu_link_content',
330 'source_module' => 'menu',
331 'destination_module' => 'menu_ui',
334 'source_module' => 'menu',
335 'destination_module' => 'menu_link_content',
338 'source_module' => 'node',
339 'destination_module' => 'node',
341 'd6_node_translation' => [
342 'source_module' => 'translation',
343 'destination_module' => 'content_translation',
345 'd6_node_revision' => [
346 'source_module' => 'node',
347 'destination_module' => 'node',
349 'd6_node_setting_promote' => [
350 'source_module' => 'node',
351 'destination_module' => 'node',
353 'd6_node_setting_status' => [
354 'source_module' => 'node',
355 'destination_module' => 'node',
357 'd6_node_setting_sticky' => [
358 'source_module' => 'node',
359 'destination_module' => 'node',
361 'd6_node_settings' => [
362 'source_module' => 'node',
363 'destination_module' => 'node',
366 'source_module' => 'node',
367 'destination_module' => 'node',
370 'source_module' => 'node',
371 'destination_module' => 'node',
374 'source_module' => 'node',
375 'destination_module' => 'node',
377 'd7_node_revision' => [
378 'source_module' => 'node',
379 'destination_module' => 'node',
381 'd7_node_settings' => [
382 'source_module' => 'node',
383 'destination_module' => 'node',
385 'd7_node_translation' => [
386 'source_module' => 'node',
387 'destination_module' => 'node',
389 'd7_node_title_label' => [
390 'source_module' => 'node',
391 'destination_module' => 'node',
394 'source_module' => 'node',
395 'destination_module' => 'node',
398 'source_module' => 'path',
399 'destination_module' => 'path',
402 'source_module' => 'path',
403 'destination_module' => 'path',
406 'source_module' => 'search',
407 'destination_module' => 'search',
409 'd6_search_settings' => [
410 'source_module' => 'search',
411 'destination_module' => 'search',
413 'd7_search_settings' => [
414 'source_module' => 'search',
415 'destination_module' => 'search',
418 'source_module' => 'shortcut',
419 'destination_module' => 'shortcut',
421 'd7_shortcut_set' => [
422 'source_module' => 'shortcut',
423 'destination_module' => 'shortcut',
425 'd7_shortcut_set_users' => [
426 'source_module' => 'shortcut',
427 'destination_module' => 'shortcut',
429 'd6_simpletest_settings' => [
430 'source_module' => 'simpletest',
431 'destination_module' => 'simpletest',
433 'd7_simpletest_settings' => [
434 'source_module' => 'simpletest',
435 'destination_module' => 'simpletest',
437 'statistics_settings' => [
438 'source_module' => 'statistics',
439 'destination_module' => 'statistics',
441 'd6_syslog_settings' => [
442 'source_module' => 'syslog',
443 'destination_module' => 'syslog',
445 'd7_syslog_settings' => [
446 'source_module' => 'syslog',
447 'destination_module' => 'syslog',
449 'd6_date_formats' => [
450 'source_module' => 'system',
451 'destination_module' => 'system',
453 'd6_system_cron' => [
454 'source_module' => 'system',
455 'destination_module' => 'system',
457 'd6_system_date' => [
458 'source_module' => 'system',
459 'destination_module' => 'system',
461 'd6_system_file' => [
462 'source_module' => 'system',
463 'destination_module' => 'system',
466 'source_module' => 'system',
467 'destination_module' => 'system',
469 'system_image_gd' => [
470 'source_module' => 'system',
471 'destination_module' => 'system',
473 'system_logging' => [
474 'source_module' => 'system',
475 'destination_module' => 'system',
477 'system_maintenance' => [
478 'source_module' => 'system',
479 'destination_module' => 'system',
481 'd6_system_performance' => [
482 'source_module' => 'system',
483 'destination_module' => 'system',
486 'source_module' => 'system',
487 'destination_module' => 'system',
490 'source_module' => 'system',
491 'destination_module' => 'system',
493 'd7_system_authorize' => [
494 'source_module' => 'system',
495 'destination_module' => 'system',
497 'd7_system_cron' => [
498 'source_module' => 'system',
499 'destination_module' => 'system',
501 'd7_system_date' => [
502 'source_module' => 'system',
503 'destination_module' => 'system',
505 'd7_system_file' => [
506 'source_module' => 'system',
507 'destination_module' => 'system',
509 'd7_system_mail' => [
510 'source_module' => 'system',
511 'destination_module' => 'system',
513 'd7_system_performance' => [
514 'source_module' => 'system',
515 'destination_module' => 'system',
518 'source_module' => 'menu',
519 'destination_module' => 'system',
522 'source_module' => 'menu',
523 'destination_module' => 'system',
525 'taxonomy_settings' => [
526 'source_module' => 'taxonomy',
527 'destination_module' => 'taxonomy',
529 'd6_taxonomy_term' => [
530 'source_module' => 'taxonomy',
531 'destination_module' => 'taxonomy',
533 'd6_taxonomy_vocabulary' => [
534 'source_module' => 'taxonomy',
535 'destination_module' => 'taxonomy',
538 'source_module' => 'taxonomy',
539 'destination_module' => 'taxonomy',
541 'd6_term_node_revision' => [
542 'source_module' => 'taxonomy',
543 'destination_module' => 'taxonomy',
545 'd6_vocabulary_entity_display' => [
546 'source_module' => 'taxonomy',
547 'destination_module' => 'taxonomy',
549 'd6_vocabulary_entity_form_display' => [
550 'source_module' => 'taxonomy',
551 'destination_module' => 'taxonomy',
553 'd6_vocabulary_field' => [
554 'source_module' => 'taxonomy',
555 'destination_module' => 'taxonomy',
557 'd6_vocabulary_field_instance' => [
558 'source_module' => 'taxonomy',
559 'destination_module' => 'taxonomy',
561 'd7_taxonomy_term' => [
562 'source_module' => 'taxonomy',
563 'destination_module' => 'taxonomy',
565 'd7_taxonomy_vocabulary' => [
566 'source_module' => 'taxonomy',
567 'destination_module' => 'taxonomy',
570 'source_module' => 'text',
571 'destination_module' => 'text',
573 'd7_tracker_node' => [
574 'source_module' => 'tracker',
575 'destination_module' => 'tracker',
577 'd7_tracker_settings' => [
578 'source_module' => 'tracker',
579 'destination_module' => 'tracker',
581 'd7_tracker_user' => [
582 'source_module' => 'tracker',
583 'destination_module' => 'tracker',
585 'update_settings' => [
586 'source_module' => 'update',
587 'destination_module' => 'update',
589 'd6_profile_values' => [
590 'source_module' => 'profile',
591 'destination_module' => 'user',
593 'd7_theme_settings' => [
594 'source_module' => 'system',
595 'destination_module' => 'system',
598 'source_module' => 'user',
599 'destination_module' => 'user',
601 'd6_user_contact_settings' => [
602 'source_module' => 'user',
603 'destination_module' => 'user',
606 'source_module' => 'user',
607 'destination_module' => 'user',
609 'd6_user_picture_file' => [
610 'source_module' => 'user',
611 'destination_module' => 'user',
614 'source_module' => 'user',
615 'destination_module' => 'user',
617 'd6_user_settings' => [
618 'source_module' => 'user',
619 'destination_module' => 'user',
622 'source_module' => 'user',
623 'destination_module' => 'user',
626 'source_module' => 'user',
627 'destination_module' => 'user',
630 'source_module' => 'user',
631 'destination_module' => 'user',
634 'source_module' => 'user',
635 'destination_module' => 'user',
637 'user_picture_entity_display' => [
638 'source_module' => 'user',
639 'destination_module' => 'user',
641 'user_picture_entity_form_display' => [
642 'source_module' => 'user',
643 'destination_module' => 'user',
645 'user_picture_field' => [
646 'source_module' => 'user',
647 'destination_module' => 'user',
649 'user_picture_field_instance' => [
650 'source_module' => 'user',
651 'destination_module' => 'user',
653 'user_profile_entity_display' => [
654 'source_module' => 'profile',
655 'destination_module' => 'user',
657 'user_profile_entity_form_display' => [
658 'source_module' => 'profile',
659 'destination_module' => 'user',
661 'user_profile_field' => [
662 'source_module' => 'profile',
663 'destination_module' => 'user',
665 'user_profile_field_instance' => [
666 'source_module' => 'profile',
667 'destination_module' => 'user',
669 'd6_i18n_user_profile_field_instance' => [
670 'source_module' => 'i18n',
671 'destination_module' => 'user',
678 * @var \Drupal\Core\State\StateInterface
683 * The date formatter service.
685 * @var \Drupal\Core\Datetime\DateFormatterInterface
687 protected $dateFormatter;
690 * The renderer service.
692 * @var \Drupal\Core\Render\RendererInterface
697 * The migration plugin manager.
699 * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
701 protected $pluginManager;
704 * Constructs the MigrateUpgradeForm.
706 * @param \Drupal\Core\State\StateInterface $state
708 * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
709 * The date formatter service.
710 * @param \Drupal\Core\Render\RendererInterface $renderer
711 * The renderer service.
712 * @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $plugin_manager
713 * The migration plugin manager.
715 public function __construct(StateInterface $state, DateFormatterInterface $date_formatter, RendererInterface $renderer, MigrationPluginManagerInterface $plugin_manager) {
716 $this->state = $state;
717 $this->dateFormatter = $date_formatter;
718 $this->renderer = $renderer;
719 $this->pluginManager = $plugin_manager;
725 public static function create(ContainerInterface $container) {
727 $container->get('state'),
728 $container->get('date.formatter'),
729 $container->get('renderer'),
730 $container->get('plugin.manager.migration')
737 public function getFormId() {
738 return 'migrate_drupal_ui_form';
744 public function buildForm(array $form, FormStateInterface $form_state) {
745 $step = $form_state->get('step') ?: 'overview';
748 return $this->buildOverviewForm($form, $form_state);
751 return $this->buildCredentialForm($form, $form_state);
754 return $this->buildConfirmForm($form, $form_state);
757 drupal_set_message($this->t('Unrecognized form step @step', ['@step' => $step]), 'error');
765 public function submitForm(array &$form, FormStateInterface $form_state) {
766 // This method is intentionally empty, see the specific submit methods for
771 * Builds the form presenting an overview of the migration process.
774 * An associative array containing the structure of the form.
775 * @param \Drupal\Core\Form\FormStateInterface $form_state
776 * The current state of the form.
779 * The form structure.
781 public function buildOverviewForm(array $form, FormStateInterface $form_state) {
782 $form['#title'] = $this->t('Upgrade');
784 if ($date_performed = $this->state->get('migrate_drupal_ui.performed')) {
785 // @todo Add back support for rollbacks and incremental migrations.
786 // https://www.drupal.org/node/2687843
787 // https://www.drupal.org/node/2687849
788 $form['upgrade_option_item'] = [
790 '#prefix' => $this->t('An upgrade has already been performed on this site. To perform a new migration, create a clean and empty new install of Drupal 8. Rollbacks and incremental migrations are not yet supported through the user interface. For more information, see the <a href=":url">upgrading handbook</a>.', [':url' => 'https://www.drupal.org/upgrade/migrate']),
791 '#description' => $this->t('Last upgrade: @date', ['@date' => $this->dateFormatter->format($date_performed)]),
796 $form['info_header'] = [
797 '#markup' => '<p>' . $this->t('Upgrade a site by importing it into a clean and empty new install of Drupal 8. You will lose any existing configuration once you import your site into it. See the <a href=":url">online documentation for Drupal site upgrades</a> for more detailed information.', [
798 ':url' => 'https://www.drupal.org/upgrade/migrate',
802 $info[] = $this->t('<strong>Back up the database for this site</strong>. Upgrade will change the database for this site.');
803 $info[] = $this->t('Make sure that the host this site is on has access to the database for your previous site.');
804 $info[] = $this->t('If your previous site has private files to be migrated, a copy of your files directory must be accessible on the host this site is on.');
805 $info[] = $this->t('In general, enable all modules on this site that are enabled on the previous site. For example, if you have used the book module on the previous site then you must enable the book module on this site for that data to be available on this site.');
806 $info[] = $this->t('Do not add any information on this site (including but not limited to user accounts, taxonomy terms, and node content) before upgrading. Any pre-existing information on the site risks being overwritten by the upgrade process. See <a href=":url">the upgrade preparation guide</a> for more information.', [
807 ':url' => 'https://www.drupal.org/docs/8/upgrade/preparing-an-upgrade#dont_create_content',
809 $info[] = $this->t('Put this site into <a href=":url">maintenance mode</a>.', [
810 ':url' => Url::fromRoute('system.site_maintenance_mode')->toString(TRUE)->getGeneratedUrl(),
814 '#theme' => 'item_list',
815 '#list_type' => 'ol',
819 $form['info_footer'] = [
820 '#markup' => '<p>' . $this->t('This upgrade can take a long time. It is better to import a local copy of your site instead of directly importing from your live site.'),
826 $form['actions'] = ['#type' => 'actions'];
827 $form['actions']['save'] = [
829 '#value' => $this->t('Continue'),
830 '#button_type' => 'primary',
831 '#validate' => $validate,
832 '#submit' => ['::submitOverviewForm'],
838 * Form submission handler for the overview form.
841 * An associative array containing the structure of the form.
842 * @param \Drupal\Core\Form\FormStateInterface $form_state
843 * The current state of the form.
845 public function submitOverviewForm(array &$form, FormStateInterface $form_state) {
846 $form_state->set('step', 'credentials');
847 $form_state->setRebuild();
851 * Builds the database credential form and adds file location information.
853 * This is largely borrowed from \Drupal\Core\Installer\Form\SiteSettingsForm.
856 * An associative array containing the structure of the form.
857 * @param \Drupal\Core\Form\FormStateInterface $form_state
858 * The current state of the form.
861 * The form structure.
863 * @todo Private files directory not yet implemented, depends on
864 * https://www.drupal.org/node/2547125.
866 public function buildCredentialForm(array $form, FormStateInterface $form_state) {
867 $form['#title'] = $this->t('Drupal Upgrade');
869 $drivers = $this->getDatabaseTypes();
870 $drivers_keys = array_keys($drivers);
871 // @todo https://www.drupal.org/node/2678510 Because this is a multi-step
872 // form, the form is not rebuilt during submission. Ideally we would get
873 // the chosen driver from form input, if available, in order to use
874 // #limit_validation_errors in the same way
875 // \Drupal\Core\Installer\Form\SiteSettingsForm does.
876 $default_driver = current($drivers_keys);
878 $default_options = [];
880 $form['database'] = [
881 '#type' => 'details',
882 '#title' => $this->t('Source database'),
883 '#description' => $this->t('Provide credentials for the database of the Drupal site you want to upgrade.'),
887 $form['database']['driver'] = [
889 '#title' => $this->t('Database type'),
891 '#default_value' => $default_driver,
893 if (count($drivers) == 1) {
894 $form['database']['driver']['#disabled'] = TRUE;
897 // Add driver-specific configuration options.
898 foreach ($drivers as $key => $driver) {
899 $form['database']['driver']['#options'][$key] = $driver->name();
901 $form['database']['settings'][$key] = $driver->getFormOptions($default_options);
902 // @todo https://www.drupal.org/node/2678510 Using
903 // #limit_validation_errors in the submit does not work so it is not
904 // possible to require the database and username for mysql and pgsql.
905 // This is because this is a multi-step form.
906 $form['database']['settings'][$key]['database']['#required'] = FALSE;
907 $form['database']['settings'][$key]['username']['#required'] = FALSE;
908 $form['database']['settings'][$key]['#prefix'] = '<h2 class="js-hide">' . $this->t('@driver_name settings', ['@driver_name' => $driver->name()]) . '</h2>';
909 $form['database']['settings'][$key]['#type'] = 'container';
910 $form['database']['settings'][$key]['#tree'] = TRUE;
911 $form['database']['settings'][$key]['advanced_options']['#parents'] = [$key];
912 $form['database']['settings'][$key]['#states'] = [
914 ':input[name=driver]' => ['value' => $key],
918 // Move the host fields out of advanced settings.
919 if (isset($form['database']['settings'][$key]['advanced_options']['host'])) {
920 $form['database']['settings'][$key]['host'] = $form['database']['settings'][$key]['advanced_options']['host'];
921 $form['database']['settings'][$key]['host']['#title'] = 'Database host';
922 $form['database']['settings'][$key]['host']['#weight'] = -1;
923 unset($form['database']['settings'][$key]['database']['#default_value']);
924 unset($form['database']['settings'][$key]['advanced_options']['host']);
929 '#type' => 'details',
930 '#title' => $this->t('Source files'),
933 $form['source']['source_base_path'] = [
934 '#type' => 'textfield',
935 '#title' => $this->t('Files directory'),
936 '#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).'),
939 $form['actions'] = ['#type' => 'actions'];
940 $form['actions']['save'] = [
942 '#value' => $this->t('Review upgrade'),
943 '#button_type' => 'primary',
944 '#validate' => ['::validateCredentialForm'],
945 '#submit' => ['::submitCredentialForm'],
951 * Validation handler for the credentials form.
954 * An associative array containing the structure of the form.
955 * @param \Drupal\Core\Form\FormStateInterface $form_state
956 * The current state of the form.
958 public function validateCredentialForm(array &$form, FormStateInterface $form_state) {
960 // Retrieve the database driver from the form, use reflection to get the
961 // namespace, and then construct a valid database array the same as in
963 $driver = $form_state->getValue('driver');
964 $drivers = $this->getDatabaseTypes();
965 $reflection = new \ReflectionClass($drivers[$driver]);
966 $install_namespace = $reflection->getNamespaceName();
968 $database = $form_state->getValue($driver);
969 // Cut the trailing \Install from namespace.
970 $database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\'));
971 $database['driver'] = $driver;
973 // Validate the driver settings and just end here if we have any issues.
974 if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) {
975 foreach ($errors as $name => $message) {
976 $form_state->setErrorByName($name, $message);
982 $connection = $this->getConnection($database);
983 $version = $this->getLegacyDrupalVersion($connection);
985 $form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database does not contain a recognizable Drupal version.'));
988 $this->createDatabaseStateSettings($database, $version);
989 $migrations = $this->getMigrations('migrate_drupal_' . $version, $version);
991 // Get the system data from source database.
992 $system_data = $this->getSystemData($connection);
994 // Convert the migration object into array
995 // so that it can be stored in form storage.
996 $migration_array = [];
997 foreach ($migrations as $migration) {
998 $migration_array[$migration->id()] = $migration->label();
1001 // Store the retrieved migration IDs in form storage.
1002 $form_state->set('migrations', $migration_array);
1003 $form_state->set('source_base_path', $form_state->getValue('source_base_path'));
1005 // Store the retrived system data in form storage.
1006 $form_state->set('system_data', $system_data);
1009 catch (\Exception $e) {
1011 '#title' => $this->t('Resolve the issue below to continue the upgrade.'),
1012 '#theme' => 'item_list',
1013 '#items' => [$e->getMessage()],
1015 $form_state->setErrorByName($database['driver'] . '][0', $this->renderer->renderPlain($error_message));
1020 * Submission handler for the credentials form.
1022 * @param array $form
1023 * An associative array containing the structure of the form.
1024 * @param \Drupal\Core\Form\FormStateInterface $form_state
1025 * The current state of the form.
1027 public function submitCredentialForm(array &$form, FormStateInterface $form_state) {
1028 // Indicate the next step is confirmation.
1029 $form_state->set('step', 'confirm');
1030 $form_state->setRebuild();
1034 * Confirmation form for missing migrations, etc.
1036 * @param array $form
1037 * An associative array containing the structure of the form.
1038 * @param \Drupal\Core\Form\FormStateInterface $form_state
1039 * The current state of the form.
1042 * The form structure.
1044 public function buildConfirmForm(array $form, FormStateInterface $form_state) {
1045 $form = parent::buildForm($form, $form_state);
1046 $form['actions']['submit']['#submit'] = ['::submitConfirmForm'];
1048 $form['actions']['submit']['#value'] = $this->t('Perform upgrade');
1052 foreach ($form_state->get('migrations') as $migration_id => $migration_label) {
1053 // Fetch the system data at the first opportunity.
1054 if (empty($system_data)) {
1055 $system_data = $form_state->get('system_data');
1058 // Handle derivatives.
1059 list($migration_id,) = explode(':', $migration_id, 2);
1060 $source_module = $this->moduleUpgradePaths[$migration_id]['source_module'];
1061 $destination_module = $this->moduleUpgradePaths[$migration_id]['destination_module'];
1062 $table_data[$source_module][$destination_module][$migration_id] = $migration_label;
1064 // Sort the table by source module names and within that destination
1067 foreach ($table_data as $source_module => $destination_module_info) {
1068 ksort($table_data[$source_module]);
1070 $unmigrated_source_modules = array_diff_key($system_data['module'], $table_data);
1072 // Missing migrations.
1073 $form['missing_module_list_title'] = [
1075 '#title' => $this->t('Missing upgrade paths'),
1076 '#description' => $this->t('The following items will not be upgraded. For more information see <a href=":migrate">Upgrading from Drupal 6 or 7 to Drupal 8</a>.', [':migrate' => 'https://www.drupal.org/upgrade/migrate']),
1078 $form['missing_module_list'] = [
1082 $this->t('Destination'),
1086 ksort($unmigrated_source_modules);
1087 foreach ($unmigrated_source_modules as $source_module => $module_data) {
1088 if ($module_data['status']) {
1090 $form['missing_module_list'][$source_module] = [
1091 'source_module' => ['#plain_text' => $source_module],
1092 'destination_module' => ['#plain_text' => 'Missing'],
1096 // Available migrations.
1097 $form['available_module_list'] = [
1099 '#type' => 'details',
1100 '#title' => $this->t('Available upgrade paths'),
1103 $form['available_module_list']['module_list'] = [
1107 $this->t('Destination'),
1111 $available_count = 0;
1112 foreach ($table_data as $source_module => $destination_module_info) {
1114 $destination_details = [];
1115 foreach ($destination_module_info as $destination_module => $migration_ids) {
1116 $destination_details[$destination_module] = [
1118 '#plain_text' => $destination_module,
1121 $form['available_module_list']['module_list'][$source_module] = [
1122 'source_module' => ['#plain_text' => $source_module],
1123 'destination_module' => $destination_details,
1127 '#title' => 'Upgrade analysis report',
1128 '#theme' => 'item_list',
1130 $this->formatPlural($available_count, '@count available upgrade path', '@count available upgrade paths'),
1131 $this->formatPlural($missing_count, '@count missing upgrade path', '@count missing upgrade paths'),
1140 * Submission handler for the confirmation form.
1142 * @param array $form
1143 * An associative array containing the structure of the form.
1144 * @param \Drupal\Core\Form\FormStateInterface $form_state
1145 * The current state of the form.
1147 public function submitConfirmForm(array &$form, FormStateInterface $form_state) {
1148 $storage = $form_state->getStorage();
1150 $migrations = $storage['migrations'];
1151 $config['source_base_path'] = $storage['source_base_path'];
1153 'title' => $this->t('Running upgrade'),
1154 'progress_message' => '',
1157 [MigrateUpgradeImportBatch::class, 'run'],
1158 [array_keys($migrations), $config],
1162 MigrateUpgradeImportBatch::class, 'finished',
1166 $form_state->setRedirect('<front>');
1167 $this->state->set('migrate_drupal_ui.performed', REQUEST_TIME);
1171 * Returns all supported database driver installer objects.
1173 * @return \Drupal\Core\Database\Install\Tasks[]
1174 * An array of available database driver installer objects.
1176 protected function getDatabaseTypes() {
1177 // Make sure the install API is available.
1178 include_once DRUPAL_ROOT . '/core/includes/install.inc';
1179 return drupal_get_database_types();
1185 public function getQuestion() {
1186 return $this->t('Are you sure?');
1192 public function getCancelUrl() {
1193 return new Url('migrate_drupal_ui.upgrade');
1199 public function getDescription() {
1200 // The description is added by the buildConfirmForm() method.
1201 // @see \Drupal\migrate_drupal_ui\Form\MigrateUpgradeForm::buildConfirmForm()
1208 public function getConfirmText() {
1209 return $this->t('Perform upgrade');