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 'd7_file_private' => [
254 'source_module' => 'file',
255 'destination_module' => 'file',
257 'd6_filter_format' => [
258 'source_module' => 'filter',
259 'destination_module' => 'filter',
261 'd7_filter_format' => [
262 'source_module' => 'filter',
263 'destination_module' => 'filter',
265 'd7_filter_settings' => [
266 'source_module' => 'filter',
267 'destination_module' => 'filter',
269 'd6_forum_settings' => [
270 'source_module' => 'forum',
271 'destination_module' => 'forum',
273 'd7_forum_settings' => [
274 'source_module' => 'forum',
275 'destination_module' => 'forum',
277 'd7_global_theme_settings' => [
278 'source_module' => 'system',
279 'destination_module' => 'system',
281 'd6_imagecache_presets' => [
282 'source_module' => 'imagecache',
283 'destination_module' => 'image',
285 'd7_image_settings' => [
286 'source_module' => 'image',
287 'destination_module' => 'image',
289 'd7_image_styles' => [
290 'source_module' => 'image',
291 'destination_module' => 'image',
293 'd6_language_content_settings' => [
294 'source_module' => 'locale',
295 'destination_module' => 'language',
297 'd7_language_content_settings' => [
298 'source_module' => 'locale',
299 'destination_module' => 'language',
301 'd6_language_negotiation_settings' => [
302 'source_module' => 'locale',
303 'destination_module' => 'language',
305 'd7_language_negotiation_settings' => [
306 'source_module' => 'locale',
307 'destination_module' => 'language',
309 'language_prefixes_and_domains' => [
310 'source_module' => 'locale',
311 'destination_module' => 'language',
313 'd6_language_types' => [
314 'source_module' => 'locale',
315 'destination_module' => 'language',
318 'source_module' => 'locale',
319 'destination_module' => 'language',
321 'd7_language_types' => [
322 'source_module' => 'locale',
323 'destination_module' => 'language',
325 'locale_settings' => [
326 'source_module' => 'locale',
327 'destination_module' => 'locale',
330 'source_module' => 'menu',
331 'destination_module' => 'menu_link_content',
334 'source_module' => 'menu',
335 'destination_module' => 'menu_ui',
338 'source_module' => 'menu',
339 'destination_module' => 'menu_link_content',
342 'source_module' => 'node',
343 'destination_module' => 'node',
345 'd6_node_translation' => [
346 'source_module' => 'translation',
347 'destination_module' => 'content_translation',
349 'd6_node_revision' => [
350 'source_module' => 'node',
351 'destination_module' => 'node',
353 'd6_node_setting_promote' => [
354 'source_module' => 'node',
355 'destination_module' => 'node',
357 'd6_node_setting_status' => [
358 'source_module' => 'node',
359 'destination_module' => 'node',
361 'd6_node_setting_sticky' => [
362 'source_module' => 'node',
363 'destination_module' => 'node',
365 'd6_node_settings' => [
366 'source_module' => 'node',
367 'destination_module' => 'node',
370 'source_module' => 'node',
371 'destination_module' => 'node',
374 'source_module' => 'node',
375 'destination_module' => 'node',
378 'source_module' => 'node',
379 'destination_module' => 'node',
381 'd7_node_revision' => [
382 'source_module' => 'node',
383 'destination_module' => 'node',
385 'd7_node_settings' => [
386 'source_module' => 'node',
387 'destination_module' => 'node',
389 'd7_node_translation' => [
390 'source_module' => 'node',
391 'destination_module' => 'node',
393 'd7_node_title_label' => [
394 'source_module' => 'node',
395 'destination_module' => 'node',
398 'source_module' => 'node',
399 'destination_module' => 'node',
402 'source_module' => 'path',
403 'destination_module' => 'path',
406 'source_module' => 'path',
407 'destination_module' => 'path',
410 'source_module' => 'search',
411 'destination_module' => 'search',
413 'd6_search_settings' => [
414 'source_module' => 'search',
415 'destination_module' => 'search',
417 'd7_search_settings' => [
418 'source_module' => 'search',
419 'destination_module' => 'search',
422 'source_module' => 'shortcut',
423 'destination_module' => 'shortcut',
425 'd7_shortcut_set' => [
426 'source_module' => 'shortcut',
427 'destination_module' => 'shortcut',
429 'd7_shortcut_set_users' => [
430 'source_module' => 'shortcut',
431 'destination_module' => 'shortcut',
433 'd6_simpletest_settings' => [
434 'source_module' => 'simpletest',
435 'destination_module' => 'simpletest',
437 'd7_simpletest_settings' => [
438 'source_module' => 'simpletest',
439 'destination_module' => 'simpletest',
441 'statistics_settings' => [
442 'source_module' => 'statistics',
443 'destination_module' => 'statistics',
445 'd6_syslog_settings' => [
446 'source_module' => 'syslog',
447 'destination_module' => 'syslog',
449 'd7_syslog_settings' => [
450 'source_module' => 'syslog',
451 'destination_module' => 'syslog',
453 'd6_date_formats' => [
454 'source_module' => 'system',
455 'destination_module' => 'system',
457 'd6_system_cron' => [
458 'source_module' => 'system',
459 'destination_module' => 'system',
461 'd6_system_date' => [
462 'source_module' => 'system',
463 'destination_module' => 'system',
465 'd6_system_file' => [
466 'source_module' => 'system',
467 'destination_module' => 'system',
470 'source_module' => 'system',
471 'destination_module' => 'system',
473 'system_image_gd' => [
474 'source_module' => 'system',
475 'destination_module' => 'system',
477 'system_logging' => [
478 'source_module' => 'system',
479 'destination_module' => 'system',
481 'system_maintenance' => [
482 'source_module' => 'system',
483 'destination_module' => 'system',
485 'd6_system_performance' => [
486 'source_module' => 'system',
487 'destination_module' => 'system',
490 'source_module' => 'system',
491 'destination_module' => 'system',
494 'source_module' => 'system',
495 'destination_module' => 'system',
497 'd7_system_authorize' => [
498 'source_module' => 'system',
499 'destination_module' => 'system',
501 'd7_system_cron' => [
502 'source_module' => 'system',
503 'destination_module' => 'system',
505 'd7_system_date' => [
506 'source_module' => 'system',
507 'destination_module' => 'system',
509 'd7_system_file' => [
510 'source_module' => 'system',
511 'destination_module' => 'system',
513 'd7_system_mail' => [
514 'source_module' => 'system',
515 'destination_module' => 'system',
517 'd7_system_performance' => [
518 'source_module' => 'system',
519 'destination_module' => 'system',
522 'source_module' => 'menu',
523 'destination_module' => 'system',
526 'source_module' => 'menu',
527 'destination_module' => 'system',
529 'taxonomy_settings' => [
530 'source_module' => 'taxonomy',
531 'destination_module' => 'taxonomy',
533 'd6_taxonomy_term' => [
534 'source_module' => 'taxonomy',
535 'destination_module' => 'taxonomy',
537 'd6_taxonomy_term_translation' => [
538 'source_module' => 'i18n',
539 'destination_module' => 'taxonomy',
541 'd6_taxonomy_vocabulary' => [
542 'source_module' => 'taxonomy',
543 'destination_module' => 'taxonomy',
545 'd6_taxonomy_vocabulary_translation' => [
546 'source_module' => 'i18n',
547 'destination_module' => 'taxonomy',
550 'source_module' => 'taxonomy',
551 'destination_module' => 'taxonomy',
553 'd6_term_node_revision' => [
554 'source_module' => 'taxonomy',
555 'destination_module' => 'taxonomy',
557 'd6_vocabulary_entity_display' => [
558 'source_module' => 'taxonomy',
559 'destination_module' => 'taxonomy',
561 'd6_vocabulary_entity_form_display' => [
562 'source_module' => 'taxonomy',
563 'destination_module' => 'taxonomy',
565 'd6_vocabulary_field' => [
566 'source_module' => 'taxonomy',
567 'destination_module' => 'taxonomy',
569 'd6_vocabulary_field_instance' => [
570 'source_module' => 'taxonomy',
571 'destination_module' => 'taxonomy',
573 'd7_taxonomy_term' => [
574 'source_module' => 'taxonomy',
575 'destination_module' => 'taxonomy',
577 'd7_taxonomy_vocabulary' => [
578 'source_module' => 'taxonomy',
579 'destination_module' => 'taxonomy',
582 'source_module' => 'text',
583 'destination_module' => 'text',
585 'd7_tracker_node' => [
586 'source_module' => 'tracker',
587 'destination_module' => 'tracker',
589 'd7_tracker_settings' => [
590 'source_module' => 'tracker',
591 'destination_module' => 'tracker',
593 'd7_tracker_user' => [
594 'source_module' => 'tracker',
595 'destination_module' => 'tracker',
597 'update_settings' => [
598 'source_module' => 'update',
599 'destination_module' => 'update',
601 'd6_profile_values' => [
602 'source_module' => 'profile',
603 'destination_module' => 'user',
605 'd7_theme_settings' => [
606 'source_module' => 'system',
607 'destination_module' => 'system',
610 'source_module' => 'user',
611 'destination_module' => 'user',
613 'd6_user_contact_settings' => [
614 'source_module' => 'user',
615 'destination_module' => 'user',
618 'source_module' => 'user',
619 'destination_module' => 'user',
621 'd6_user_picture_file' => [
622 'source_module' => 'user',
623 'destination_module' => 'user',
626 'source_module' => 'user',
627 'destination_module' => 'user',
629 'd6_user_settings' => [
630 'source_module' => 'user',
631 'destination_module' => 'user',
634 'source_module' => 'user',
635 'destination_module' => 'user',
638 'source_module' => 'user',
639 'destination_module' => 'user',
642 'source_module' => 'user',
643 'destination_module' => 'user',
646 'source_module' => 'user',
647 'destination_module' => 'user',
649 'user_picture_entity_display' => [
650 'source_module' => 'user',
651 'destination_module' => 'user',
653 'user_picture_entity_form_display' => [
654 'source_module' => 'user',
655 'destination_module' => 'user',
657 'user_picture_field' => [
658 'source_module' => 'user',
659 'destination_module' => 'user',
661 'user_picture_field_instance' => [
662 'source_module' => 'user',
663 'destination_module' => 'user',
665 'user_profile_entity_display' => [
666 'source_module' => 'profile',
667 'destination_module' => 'user',
669 'user_profile_entity_form_display' => [
670 'source_module' => 'profile',
671 'destination_module' => 'user',
673 'user_profile_field' => [
674 'source_module' => 'profile',
675 'destination_module' => 'user',
677 'user_profile_field_instance' => [
678 'source_module' => 'profile',
679 'destination_module' => 'user',
681 'd6_i18n_user_profile_field_instance' => [
682 'source_module' => 'i18n',
683 'destination_module' => 'user',
690 * @var \Drupal\Core\State\StateInterface
695 * The date formatter service.
697 * @var \Drupal\Core\Datetime\DateFormatterInterface
699 protected $dateFormatter;
702 * The renderer service.
704 * @var \Drupal\Core\Render\RendererInterface
709 * The migration plugin manager.
711 * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
713 protected $pluginManager;
716 * Constructs the MigrateUpgradeForm.
718 * @param \Drupal\Core\State\StateInterface $state
720 * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
721 * The date formatter service.
722 * @param \Drupal\Core\Render\RendererInterface $renderer
723 * The renderer service.
724 * @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $plugin_manager
725 * The migration plugin manager.
727 public function __construct(StateInterface $state, DateFormatterInterface $date_formatter, RendererInterface $renderer, MigrationPluginManagerInterface $plugin_manager) {
728 $this->state = $state;
729 $this->dateFormatter = $date_formatter;
730 $this->renderer = $renderer;
731 $this->pluginManager = $plugin_manager;
737 public static function create(ContainerInterface $container) {
739 $container->get('state'),
740 $container->get('date.formatter'),
741 $container->get('renderer'),
742 $container->get('plugin.manager.migration')
749 public function getFormId() {
750 return 'migrate_drupal_ui_form';
756 public function buildForm(array $form, FormStateInterface $form_state) {
757 $step = $form_state->get('step') ?: 'overview';
760 return $this->buildOverviewForm($form, $form_state);
763 return $this->buildCredentialForm($form, $form_state);
766 return $this->buildConfirmForm($form, $form_state);
769 drupal_set_message($this->t('Unrecognized form step @step', ['@step' => $step]), 'error');
777 public function submitForm(array &$form, FormStateInterface $form_state) {
778 // This method is intentionally empty, see the specific submit methods for
783 * Builds the form presenting an overview of the migration process.
786 * An associative array containing the structure of the form.
787 * @param \Drupal\Core\Form\FormStateInterface $form_state
788 * The current state of the form.
791 * The form structure.
793 public function buildOverviewForm(array $form, FormStateInterface $form_state) {
794 $form['#title'] = $this->t('Upgrade');
796 if ($date_performed = $this->state->get('migrate_drupal_ui.performed')) {
797 // @todo Add back support for rollbacks and incremental migrations.
798 // https://www.drupal.org/node/2687843
799 // https://www.drupal.org/node/2687849
800 $form['upgrade_option_item'] = [
802 '#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']),
803 '#description' => $this->t('Last upgrade: @date', ['@date' => $this->dateFormatter->format($date_performed)]),
808 $form['info_header'] = [
809 '#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.', [
810 ':url' => 'https://www.drupal.org/upgrade/migrate',
814 $info[] = $this->t('<strong>Back up the database for this site</strong>. Upgrade will change the database for this site.');
815 $info[] = $this->t('Make sure that the host this site is on has access to the database for your previous site.');
816 $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.');
817 $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.');
818 $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.', [
819 ':url' => 'https://www.drupal.org/docs/8/upgrade/preparing-an-upgrade#dont_create_content',
821 $info[] = $this->t('Put this site into <a href=":url">maintenance mode</a>.', [
822 ':url' => Url::fromRoute('system.site_maintenance_mode')->toString(TRUE)->getGeneratedUrl(),
826 '#theme' => 'item_list',
827 '#list_type' => 'ol',
831 $form['info_footer'] = [
832 '#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.'),
838 $form['actions'] = ['#type' => 'actions'];
839 $form['actions']['save'] = [
841 '#value' => $this->t('Continue'),
842 '#button_type' => 'primary',
843 '#validate' => $validate,
844 '#submit' => ['::submitOverviewForm'],
850 * Form submission handler for the overview form.
853 * An associative array containing the structure of the form.
854 * @param \Drupal\Core\Form\FormStateInterface $form_state
855 * The current state of the form.
857 public function submitOverviewForm(array &$form, FormStateInterface $form_state) {
858 $form_state->set('step', 'credentials');
859 $form_state->setRebuild();
863 * Builds the database credential form and adds file location information.
865 * This is largely borrowed from \Drupal\Core\Installer\Form\SiteSettingsForm.
868 * An associative array containing the structure of the form.
869 * @param \Drupal\Core\Form\FormStateInterface $form_state
870 * The current state of the form.
873 * The form structure.
875 * @todo Private files directory not yet implemented, depends on
876 * https://www.drupal.org/node/2547125.
878 public function buildCredentialForm(array $form, FormStateInterface $form_state) {
879 $form['#title'] = $this->t('Drupal Upgrade');
881 $drivers = $this->getDatabaseTypes();
882 $drivers_keys = array_keys($drivers);
883 // @todo https://www.drupal.org/node/2678510 Because this is a multi-step
884 // form, the form is not rebuilt during submission. Ideally we would get
885 // the chosen driver from form input, if available, in order to use
886 // #limit_validation_errors in the same way
887 // \Drupal\Core\Installer\Form\SiteSettingsForm does.
888 $default_driver = current($drivers_keys);
890 $default_options = [];
895 '#default_value' => 7,
896 '#title' => $this->t('Drupal version of the source site'),
897 '#options' => [6 => $this->t('Drupal 6'), 7 => $this->t('Drupal 7')],
901 $form['database'] = [
902 '#type' => 'details',
903 '#title' => $this->t('Source database'),
904 '#description' => $this->t('Provide credentials for the database of the Drupal site you want to upgrade.'),
908 $form['database']['driver'] = [
910 '#title' => $this->t('Database type'),
912 '#default_value' => $default_driver,
914 if (count($drivers) == 1) {
915 $form['database']['driver']['#disabled'] = TRUE;
918 // Add driver-specific configuration options.
919 foreach ($drivers as $key => $driver) {
920 $form['database']['driver']['#options'][$key] = $driver->name();
922 $form['database']['settings'][$key] = $driver->getFormOptions($default_options);
923 // @todo https://www.drupal.org/node/2678510 Using
924 // #limit_validation_errors in the submit does not work so it is not
925 // possible to require the database and username for mysql and pgsql.
926 // This is because this is a multi-step form.
927 $form['database']['settings'][$key]['database']['#required'] = FALSE;
928 $form['database']['settings'][$key]['username']['#required'] = FALSE;
929 $form['database']['settings'][$key]['#prefix'] = '<h2 class="js-hide">' . $this->t('@driver_name settings', ['@driver_name' => $driver->name()]) . '</h2>';
930 $form['database']['settings'][$key]['#type'] = 'container';
931 $form['database']['settings'][$key]['#tree'] = TRUE;
932 $form['database']['settings'][$key]['advanced_options']['#parents'] = [$key];
933 $form['database']['settings'][$key]['#states'] = [
935 ':input[name=driver]' => ['value' => $key],
939 // Move the host fields out of advanced settings.
940 if (isset($form['database']['settings'][$key]['advanced_options']['host'])) {
941 $form['database']['settings'][$key]['host'] = $form['database']['settings'][$key]['advanced_options']['host'];
942 $form['database']['settings'][$key]['host']['#title'] = 'Database host';
943 $form['database']['settings'][$key]['host']['#weight'] = -1;
944 unset($form['database']['settings'][$key]['database']['#default_value']);
945 unset($form['database']['settings'][$key]['advanced_options']['host']);
950 '#type' => 'details',
951 '#title' => $this->t('Source files'),
954 $form['source']['d6_source_base_path'] = [
955 '#type' => 'textfield',
956 '#title' => $this->t('Files directory'),
957 '#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).'),
960 ':input[name="version"]' => ['value' => 6],
965 $form['source']['source_base_path'] = [
966 '#type' => 'textfield',
967 '#title' => $this->t('Public files directory'),
968 '#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).'),
971 ':input[name="version"]' => ['value' => 7],
976 $form['source']['source_private_file_path'] = [
977 '#type' => 'textfield',
978 '#title' => $this->t('Private file directory'),
979 '#default_value' => '',
980 '#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).'),
983 ':input[name="version"]' => ['value' => 7],
988 $form['actions'] = ['#type' => 'actions'];
989 $form['actions']['save'] = [
991 '#value' => $this->t('Review upgrade'),
992 '#button_type' => 'primary',
993 '#validate' => ['::validateCredentialForm'],
994 '#submit' => ['::submitCredentialForm'],
1000 * Validation handler for the credentials form.
1002 * @param array $form
1003 * An associative array containing the structure of the form.
1004 * @param \Drupal\Core\Form\FormStateInterface $form_state
1005 * The current state of the form.
1007 public function validateCredentialForm(array &$form, FormStateInterface $form_state) {
1009 // Retrieve the database driver from the form, use reflection to get the
1010 // namespace, and then construct a valid database array the same as in
1012 $driver = $form_state->getValue('driver');
1013 $drivers = $this->getDatabaseTypes();
1014 $reflection = new \ReflectionClass($drivers[$driver]);
1015 $install_namespace = $reflection->getNamespaceName();
1017 $database = $form_state->getValue($driver);
1018 // Cut the trailing \Install from namespace.
1019 $database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\'));
1020 $database['driver'] = $driver;
1022 // Validate the driver settings and just end here if we have any issues.
1023 if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) {
1024 foreach ($errors as $name => $message) {
1025 $form_state->setErrorByName($name, $message);
1031 $connection = $this->getConnection($database);
1032 $version = $this->getLegacyDrupalVersion($connection);
1034 $form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database does not contain a recognizable Drupal version.'));
1036 elseif ($version != $form_state->getValue('version')) {
1037 $form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database is Drupal version @version but version @selected was selected.', [
1038 '@version' => $version,
1039 '@selected' => $form_state->getValue('version'),
1043 $this->createDatabaseStateSettings($database, $version);
1044 $migrations = $this->getMigrations('migrate_drupal_' . $version, $version);
1046 // Get the system data from source database.
1047 $system_data = $this->getSystemData($connection);
1049 // Convert the migration object into array
1050 // so that it can be stored in form storage.
1051 $migration_array = [];
1052 foreach ($migrations as $migration) {
1053 $migration_array[$migration->id()] = $migration->label();
1056 // Store the retrieved migration IDs in form storage.
1057 $form_state->set('migrations', $migration_array);
1058 $form_state->set('source_base_path', $form_state->getValue('source_base_path'));
1059 $form_state->set('source_private_file_path', $form_state->getValue('source_private_file_path'));
1061 // Store the retrived system data in form storage.
1062 $form_state->set('system_data', $system_data);
1065 catch (\Exception $e) {
1067 '#title' => $this->t('Resolve the issue below to continue the upgrade.'),
1068 '#theme' => 'item_list',
1069 '#items' => [$e->getMessage()],
1071 $form_state->setErrorByName($database['driver'] . '][0', $this->renderer->renderPlain($error_message));
1076 * Submission handler for the credentials form.
1078 * @param array $form
1079 * An associative array containing the structure of the form.
1080 * @param \Drupal\Core\Form\FormStateInterface $form_state
1081 * The current state of the form.
1083 public function submitCredentialForm(array &$form, FormStateInterface $form_state) {
1084 // Indicate the next step is confirmation.
1085 $form_state->set('step', 'confirm');
1086 $form_state->setRebuild();
1090 * Confirmation form for missing migrations, etc.
1092 * @param array $form
1093 * An associative array containing the structure of the form.
1094 * @param \Drupal\Core\Form\FormStateInterface $form_state
1095 * The current state of the form.
1098 * The form structure.
1100 public function buildConfirmForm(array $form, FormStateInterface $form_state) {
1101 $form = parent::buildForm($form, $form_state);
1102 $form['actions']['submit']['#submit'] = ['::submitConfirmForm'];
1104 $form['actions']['submit']['#value'] = $this->t('Perform upgrade');
1108 foreach ($form_state->get('migrations') as $migration_id => $migration_label) {
1109 // Fetch the system data at the first opportunity.
1110 if (empty($system_data)) {
1111 $system_data = $form_state->get('system_data');
1114 // Handle derivatives.
1115 list($migration_id,) = explode(':', $migration_id, 2);
1116 $source_module = $this->moduleUpgradePaths[$migration_id]['source_module'];
1117 $destination_module = $this->moduleUpgradePaths[$migration_id]['destination_module'];
1118 $table_data[$source_module][$destination_module][$migration_id] = $migration_label;
1120 // Sort the table by source module names and within that destination
1123 foreach ($table_data as $source_module => $destination_module_info) {
1124 ksort($table_data[$source_module]);
1126 $unmigrated_source_modules = array_diff_key($system_data['module'], $table_data);
1128 // Missing migrations.
1129 $form['missing_module_list_title'] = [
1131 '#title' => $this->t('Missing upgrade paths'),
1132 '#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']),
1134 $form['missing_module_list'] = [
1138 $this->t('Destination'),
1142 ksort($unmigrated_source_modules);
1143 foreach ($unmigrated_source_modules as $source_module => $module_data) {
1144 if ($module_data['status']) {
1146 $form['missing_module_list'][$source_module] = [
1147 'source_module' => ['#plain_text' => $source_module],
1148 'destination_module' => ['#plain_text' => 'Missing'],
1152 // Available migrations.
1153 $form['available_module_list'] = [
1155 '#type' => 'details',
1156 '#title' => $this->t('Available upgrade paths'),
1159 $form['available_module_list']['module_list'] = [
1163 $this->t('Destination'),
1167 $available_count = 0;
1168 foreach ($table_data as $source_module => $destination_module_info) {
1170 $destination_details = [];
1171 foreach ($destination_module_info as $destination_module => $migration_ids) {
1172 $destination_details[$destination_module] = [
1174 '#plain_text' => $destination_module,
1177 $form['available_module_list']['module_list'][$source_module] = [
1178 'source_module' => ['#plain_text' => $source_module],
1179 'destination_module' => $destination_details,
1183 '#title' => 'Upgrade analysis report',
1184 '#theme' => 'item_list',
1186 $this->formatPlural($available_count, '@count available upgrade path', '@count available upgrade paths'),
1187 $this->formatPlural($missing_count, '@count missing upgrade path', '@count missing upgrade paths'),
1196 * Submission handler for the confirmation form.
1198 * @param array $form
1199 * An associative array containing the structure of the form.
1200 * @param \Drupal\Core\Form\FormStateInterface $form_state
1201 * The current state of the form.
1203 public function submitConfirmForm(array &$form, FormStateInterface $form_state) {
1204 $storage = $form_state->getStorage();
1206 $migrations = $storage['migrations'];
1207 $config['source_base_path'] = $storage['source_base_path'];
1209 'title' => $this->t('Running upgrade'),
1210 'progress_message' => '',
1213 [MigrateUpgradeImportBatch::class, 'run'],
1214 [array_keys($migrations), $config],
1218 MigrateUpgradeImportBatch::class, 'finished',
1222 $form_state->setRedirect('<front>');
1223 $this->state->set('migrate_drupal_ui.performed', REQUEST_TIME);
1227 * Returns all supported database driver installer objects.
1229 * @return \Drupal\Core\Database\Install\Tasks[]
1230 * An array of available database driver installer objects.
1232 protected function getDatabaseTypes() {
1233 // Make sure the install API is available.
1234 include_once DRUPAL_ROOT . '/core/includes/install.inc';
1235 return drupal_get_database_types();
1241 public function getQuestion() {
1242 return $this->t('Are you sure?');
1248 public function getCancelUrl() {
1249 return new Url('migrate_drupal_ui.upgrade');
1255 public function getDescription() {
1256 // The description is added by the buildConfirmForm() method.
1257 // @see \Drupal\migrate_drupal_ui\Form\MigrateUpgradeForm::buildConfirmForm()
1264 public function getConfirmText() {
1265 return $this->t('Perform upgrade');