Upgraded drupal core with security updates
[yaffs-website] / web / core / modules / migrate_drupal_ui / src / Form / MigrateUpgradeForm.php
1 <?php
2
3 namespace Drupal\migrate_drupal_ui\Form;
4
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;
10 use Drupal\Core\Url;
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;
15
16 /**
17  * Defines a multi-step form for performing direct site upgrades.
18  */
19 class MigrateUpgradeForm extends ConfirmFormBase {
20
21   use MigrationConfigurationTrait;
22
23   /**
24    * Mapping of known migrations and their source and destination modules.
25    *
26    * @todo https://www.drupal.org/node/2569805 Hardcoding this information is
27    *   not robust - the migrations themselves should hold the necessary
28    *   information.
29    *
30    * @var array[]
31    */
32   protected $moduleUpgradePaths = [
33     'action_settings' => [
34       'source_module' => 'system',
35       'destination_module' => 'action',
36     ],
37     'd6_aggregator_feed' => [
38       'source_module' => 'aggregator',
39       'destination_module' => 'aggregator',
40     ],
41     'd6_aggregator_item' => [
42       'source_module' => 'aggregator',
43       'destination_module' => 'aggregator',
44     ],
45     'd6_aggregator_settings' => [
46       'source_module' => 'aggregator',
47       'destination_module' => 'aggregator',
48     ],
49     'd7_aggregator_feed' => [
50       'source_module' => 'aggregator',
51       'destination_module' => 'aggregator',
52     ],
53     'd7_aggregator_item' => [
54       'source_module' => 'aggregator',
55       'destination_module' => 'aggregator',
56     ],
57     'd7_aggregator_settings' => [
58       'source_module' => 'aggregator',
59       'destination_module' => 'aggregator',
60     ],
61     'd7_blocked_ips' => [
62       'source_module' => 'system',
63       'destination_module' => 'ban',
64     ],
65     'd6_block' => [
66       'source_module' => 'block',
67       'destination_module' => 'block',
68     ],
69     'd7_block' => [
70       'source_module' => 'block',
71       'destination_module' => 'block',
72     ],
73     'block_content_entity_form_display' => [
74       'source_module' => 'block',
75       'destination_module' => 'block_content',
76     ],
77     'block_content_entity_display' => [
78       'source_module' => 'block',
79       'destination_module' => 'block_content',
80     ],
81     'block_content_body_field' => [
82       'source_module' => 'block',
83       'destination_module' => 'block_content',
84     ],
85     'block_content_type' => [
86       'source_module' => 'block',
87       'destination_module' => 'block_content',
88     ],
89     'd6_custom_block' => [
90       'source_module' => 'block',
91       'destination_module' => 'block_content',
92     ],
93     'd7_custom_block' => [
94       'source_module' => 'block',
95       'destination_module' => 'block_content',
96     ],
97     'd6_book' => [
98       'source_module' => 'book',
99       'destination_module' => 'book',
100     ],
101     'd6_book_settings' => [
102       'source_module' => 'book',
103       'destination_module' => 'book',
104     ],
105     'd6_comment' => [
106       'source_module' => 'comment',
107       'destination_module' => 'comment',
108     ],
109     'd6_comment_entity_display' => [
110       'source_module' => 'comment',
111       'destination_module' => 'comment',
112     ],
113     'd6_comment_entity_form_display' => [
114       'source_module' => 'comment',
115       'destination_module' => 'comment',
116     ],
117     'd6_comment_entity_form_display_subject' => [
118       'source_module' => 'comment',
119       'destination_module' => 'comment',
120     ],
121     'd6_comment_field' => [
122       'source_module' => 'comment',
123       'destination_module' => 'comment',
124     ],
125     'd6_comment_field_instance' => [
126       'source_module' => 'comment',
127       'destination_module' => 'comment',
128     ],
129     'd6_comment_type' => [
130       'source_module' => 'comment',
131       'destination_module' => 'comment',
132     ],
133     'd7_comment' => [
134       'source_module' => 'comment',
135       'destination_module' => 'comment',
136     ],
137     'd7_comment_entity_display' => [
138       'source_module' => 'comment',
139       'destination_module' => 'comment',
140     ],
141     'd7_comment_entity_form_display' => [
142       'source_module' => 'comment',
143       'destination_module' => 'comment',
144     ],
145     'd7_comment_entity_form_display_subject' => [
146       'source_module' => 'comment',
147       'destination_module' => 'comment',
148     ],
149     'd7_comment_field' => [
150       'source_module' => 'comment',
151       'destination_module' => 'comment',
152     ],
153     'd7_comment_field_instance' => [
154       'source_module' => 'comment',
155       'destination_module' => 'comment',
156     ],
157     'd7_comment_type' => [
158       'source_module' => 'comment',
159       'destination_module' => 'comment',
160     ],
161     'contact_category' => [
162       'source_module' => 'contact',
163       'destination_module' => 'contact',
164     ],
165     'd6_contact_settings' => [
166       'source_module' => 'contact',
167       'destination_module' => 'contact',
168     ],
169     'd7_contact_settings' => [
170       'source_module' => 'contact',
171       'destination_module' => 'contact',
172     ],
173     'd6_dblog_settings' => [
174       'source_module' => 'dblog',
175       'destination_module' => 'dblog',
176     ],
177     'd7_dblog_settings' => [
178       'source_module' => 'dblog',
179       'destination_module' => 'dblog',
180     ],
181     'default_language' => [
182       'source_module' => 'locale',
183       'destination_module' => 'language',
184     ],
185     'd6_field' => [
186       'source_module' => 'content',
187       'destination_module' => 'field',
188     ],
189     'd6_field_formatter_settings' => [
190       'source_module' => 'content',
191       'destination_module' => 'field',
192     ],
193     'd6_field_instance' => [
194       'source_module' => 'content',
195       'destination_module' => 'field',
196     ],
197     'd6_field_instance_widget_settings' => [
198       'source_module' => 'content',
199       'destination_module' => 'field',
200     ],
201     'd7_field' => [
202       'source_module' => 'field',
203       'destination_module' => 'field',
204     ],
205     'd7_field_formatter_settings' => [
206       'source_module' => 'field',
207       'destination_module' => 'field',
208     ],
209     'd7_field_instance' => [
210       'source_module' => 'field',
211       'destination_module' => 'field',
212     ],
213     'd7_field_instance_widget_settings' => [
214       'source_module' => 'field',
215       'destination_module' => 'field',
216     ],
217     'd7_view_modes' => [
218       'source_module' => 'field',
219       'destination_module' => 'field',
220     ],
221     'd6_file' => [
222       'source_module' => 'system',
223       'destination_module' => 'file',
224     ],
225     'file_settings' => [
226       'source_module' => 'system',
227       'destination_module' => 'file',
228     ],
229     'd6_upload' => [
230       'source_module' => 'upload',
231       'destination_module' => 'file',
232     ],
233     'd6_upload_entity_display' => [
234       'source_module' => 'upload',
235       'destination_module' => 'file',
236     ],
237     'd6_upload_entity_form_display' => [
238       'source_module' => 'upload',
239       'destination_module' => 'file',
240     ],
241     'd6_upload_field' => [
242       'source_module' => 'upload',
243       'destination_module' => 'file',
244     ],
245     'd6_upload_field_instance' => [
246       'source_module' => 'upload',
247       'destination_module' => 'file',
248     ],
249     'd7_file' => [
250       'source_module' => 'file',
251       'destination_module' => 'file',
252     ],
253     'd7_file_private' => [
254       'source_module' => 'file',
255       'destination_module' => 'file',
256     ],
257     'd6_filter_format' => [
258       'source_module' => 'filter',
259       'destination_module' => 'filter',
260     ],
261     'd7_filter_format' => [
262       'source_module' => 'filter',
263       'destination_module' => 'filter',
264     ],
265     'd7_filter_settings' => [
266       'source_module' => 'filter',
267       'destination_module' => 'filter',
268     ],
269     'd6_forum_settings' => [
270       'source_module' => 'forum',
271       'destination_module' => 'forum',
272     ],
273     'd7_forum_settings' => [
274       'source_module' => 'forum',
275       'destination_module' => 'forum',
276     ],
277     'd7_global_theme_settings' => [
278       'source_module' => 'system',
279       'destination_module' => 'system',
280     ],
281     'd6_imagecache_presets' => [
282       'source_module' => 'imagecache',
283       'destination_module' => 'image',
284     ],
285     'd7_image_settings' => [
286       'source_module' => 'image',
287       'destination_module' => 'image',
288     ],
289     'd7_image_styles' => [
290       'source_module' => 'image',
291       'destination_module' => 'image',
292     ],
293     'd6_language_content_settings' => [
294       'source_module' => 'locale',
295       'destination_module' => 'language',
296     ],
297     'd7_language_content_settings' => [
298       'source_module' => 'locale',
299       'destination_module' => 'language',
300     ],
301     'd6_language_negotiation_settings' => [
302       'source_module' => 'locale',
303       'destination_module' => 'language',
304     ],
305     'd7_language_negotiation_settings' => [
306       'source_module' => 'locale',
307       'destination_module' => 'language',
308     ],
309     'language_prefixes_and_domains' => [
310       'source_module' => 'locale',
311       'destination_module' => 'language',
312     ],
313     'd6_language_types' => [
314       'source_module' => 'locale',
315       'destination_module' => 'language',
316     ],
317     'language' => [
318       'source_module' => 'locale',
319       'destination_module' => 'language',
320     ],
321     'd7_language_types' => [
322       'source_module' => 'locale',
323       'destination_module' => 'language',
324     ],
325     'locale_settings' => [
326       'source_module' => 'locale',
327       'destination_module' => 'locale',
328     ],
329     'd6_menu_links' => [
330       'source_module' => 'menu',
331       'destination_module' => 'menu_link_content',
332     ],
333     'menu_settings' => [
334       'source_module' => 'menu',
335       'destination_module' => 'menu_ui',
336     ],
337     'd7_menu_links' => [
338       'source_module' => 'menu',
339       'destination_module' => 'menu_link_content',
340     ],
341     'd6_node' => [
342       'source_module' => 'node',
343       'destination_module' => 'node',
344     ],
345     'd6_node_translation' => [
346       'source_module' => 'translation',
347       'destination_module' => 'content_translation',
348     ],
349     'd6_node_revision' => [
350       'source_module' => 'node',
351       'destination_module' => 'node',
352     ],
353     'd6_node_setting_promote' => [
354       'source_module' => 'node',
355       'destination_module' => 'node',
356     ],
357     'd6_node_setting_status' => [
358       'source_module' => 'node',
359       'destination_module' => 'node',
360     ],
361     'd6_node_setting_sticky' => [
362       'source_module' => 'node',
363       'destination_module' => 'node',
364     ],
365     'd6_node_settings' => [
366       'source_module' => 'node',
367       'destination_module' => 'node',
368     ],
369     'd6_node_type' => [
370       'source_module' => 'node',
371       'destination_module' => 'node',
372     ],
373     'd6_view_modes' => [
374       'source_module' => 'node',
375       'destination_module' => 'node',
376     ],
377     'd7_node' => [
378       'source_module' => 'node',
379       'destination_module' => 'node',
380     ],
381     'd7_node_revision' => [
382       'source_module' => 'node',
383       'destination_module' => 'node',
384     ],
385     'd7_node_settings' => [
386       'source_module' => 'node',
387       'destination_module' => 'node',
388     ],
389     'd7_node_translation' => [
390       'source_module' => 'node',
391       'destination_module' => 'node',
392     ],
393     'd7_node_title_label' => [
394       'source_module' => 'node',
395       'destination_module' => 'node',
396     ],
397     'd7_node_type' => [
398       'source_module' => 'node',
399       'destination_module' => 'node',
400     ],
401     'd6_url_alias' => [
402       'source_module' => 'path',
403       'destination_module' => 'path',
404     ],
405     'd7_url_alias' => [
406       'source_module' => 'path',
407       'destination_module' => 'path',
408     ],
409     'search_page' => [
410       'source_module' => 'search',
411       'destination_module' => 'search',
412     ],
413     'd6_search_settings' => [
414       'source_module' => 'search',
415       'destination_module' => 'search',
416     ],
417     'd7_search_settings' => [
418       'source_module' => 'search',
419       'destination_module' => 'search',
420     ],
421     'd7_shortcut' => [
422       'source_module' => 'shortcut',
423       'destination_module' => 'shortcut',
424     ],
425     'd7_shortcut_set' => [
426       'source_module' => 'shortcut',
427       'destination_module' => 'shortcut',
428     ],
429     'd7_shortcut_set_users' => [
430       'source_module' => 'shortcut',
431       'destination_module' => 'shortcut',
432     ],
433     'd6_simpletest_settings' => [
434       'source_module' => 'simpletest',
435       'destination_module' => 'simpletest',
436     ],
437     'd7_simpletest_settings' => [
438       'source_module' => 'simpletest',
439       'destination_module' => 'simpletest',
440     ],
441     'statistics_settings' => [
442       'source_module' => 'statistics',
443       'destination_module' => 'statistics',
444     ],
445     'd6_syslog_settings' => [
446       'source_module' => 'syslog',
447       'destination_module' => 'syslog',
448     ],
449     'd7_syslog_settings' => [
450       'source_module' => 'syslog',
451       'destination_module' => 'syslog',
452     ],
453     'd6_date_formats' => [
454       'source_module' => 'system',
455       'destination_module' => 'system',
456     ],
457     'd6_system_cron' => [
458       'source_module' => 'system',
459       'destination_module' => 'system',
460     ],
461     'd6_system_date' => [
462       'source_module' => 'system',
463       'destination_module' => 'system',
464     ],
465     'd6_system_file' => [
466       'source_module' => 'system',
467       'destination_module' => 'system',
468     ],
469     'system_image' => [
470       'source_module' => 'system',
471       'destination_module' => 'system',
472     ],
473     'system_image_gd' => [
474       'source_module' => 'system',
475       'destination_module' => 'system',
476     ],
477     'system_logging' => [
478       'source_module' => 'system',
479       'destination_module' => 'system',
480     ],
481     'system_maintenance' => [
482       'source_module' => 'system',
483       'destination_module' => 'system',
484     ],
485     'd6_system_performance' => [
486       'source_module' => 'system',
487       'destination_module' => 'system',
488     ],
489     'system_rss' => [
490       'source_module' => 'system',
491       'destination_module' => 'system',
492     ],
493     'system_site' => [
494       'source_module' => 'system',
495       'destination_module' => 'system',
496     ],
497     'd7_system_authorize' => [
498       'source_module' => 'system',
499       'destination_module' => 'system',
500     ],
501     'd7_system_cron' => [
502       'source_module' => 'system',
503       'destination_module' => 'system',
504     ],
505     'd7_system_date' => [
506       'source_module' => 'system',
507       'destination_module' => 'system',
508     ],
509     'd7_system_file' => [
510       'source_module' => 'system',
511       'destination_module' => 'system',
512     ],
513     'd7_system_mail' => [
514       'source_module' => 'system',
515       'destination_module' => 'system',
516     ],
517     'd7_system_performance' => [
518       'source_module' => 'system',
519       'destination_module' => 'system',
520     ],
521     'd6_menu' => [
522       'source_module' => 'menu',
523       'destination_module' => 'system',
524     ],
525     'd7_menu' => [
526       'source_module' => 'menu',
527       'destination_module' => 'system',
528     ],
529     'taxonomy_settings' => [
530       'source_module' => 'taxonomy',
531       'destination_module' => 'taxonomy',
532     ],
533     'd6_taxonomy_term' => [
534       'source_module' => 'taxonomy',
535       'destination_module' => 'taxonomy',
536     ],
537     'd6_taxonomy_term_translation' => [
538       'source_module' => 'i18n',
539       'destination_module' => 'taxonomy',
540     ],
541     'd6_taxonomy_vocabulary' => [
542       'source_module' => 'taxonomy',
543       'destination_module' => 'taxonomy',
544     ],
545     'd6_taxonomy_vocabulary_translation' => [
546       'source_module' => 'i18n',
547       'destination_module' => 'taxonomy',
548     ],
549     'd6_term_node' => [
550       'source_module' => 'taxonomy',
551       'destination_module' => 'taxonomy',
552     ],
553     'd6_term_node_revision' => [
554       'source_module' => 'taxonomy',
555       'destination_module' => 'taxonomy',
556     ],
557     'd6_vocabulary_entity_display' => [
558       'source_module' => 'taxonomy',
559       'destination_module' => 'taxonomy',
560     ],
561     'd6_vocabulary_entity_form_display' => [
562       'source_module' => 'taxonomy',
563       'destination_module' => 'taxonomy',
564     ],
565     'd6_vocabulary_field' => [
566       'source_module' => 'taxonomy',
567       'destination_module' => 'taxonomy',
568     ],
569     'd6_vocabulary_field_instance' => [
570       'source_module' => 'taxonomy',
571       'destination_module' => 'taxonomy',
572     ],
573     'd7_taxonomy_term' => [
574       'source_module' => 'taxonomy',
575       'destination_module' => 'taxonomy',
576     ],
577     'd7_taxonomy_vocabulary' => [
578       'source_module' => 'taxonomy',
579       'destination_module' => 'taxonomy',
580     ],
581     'text_settings' => [
582       'source_module' => 'text',
583       'destination_module' => 'text',
584     ],
585     'd7_tracker_node' => [
586       'source_module' => 'tracker',
587       'destination_module' => 'tracker',
588     ],
589     'd7_tracker_settings' => [
590       'source_module' => 'tracker',
591       'destination_module' => 'tracker',
592     ],
593     'd7_tracker_user' => [
594       'source_module' => 'tracker',
595       'destination_module' => 'tracker',
596     ],
597     'update_settings' => [
598       'source_module' => 'update',
599       'destination_module' => 'update',
600     ],
601     'd6_profile_values' => [
602       'source_module' => 'profile',
603       'destination_module' => 'user',
604     ],
605     'd7_theme_settings' => [
606       'source_module' => 'system',
607       'destination_module' => 'system',
608     ],
609     'd6_user' => [
610       'source_module' => 'user',
611       'destination_module' => 'user',
612     ],
613     'd6_user_contact_settings' => [
614       'source_module' => 'user',
615       'destination_module' => 'user',
616     ],
617     'd6_user_mail' => [
618       'source_module' => 'user',
619       'destination_module' => 'user',
620     ],
621     'd6_user_picture_file' => [
622       'source_module' => 'user',
623       'destination_module' => 'user',
624     ],
625     'd6_user_role' => [
626       'source_module' => 'user',
627       'destination_module' => 'user',
628     ],
629     'd6_user_settings' => [
630       'source_module' => 'user',
631       'destination_module' => 'user',
632     ],
633     'd7_user' => [
634       'source_module' => 'user',
635       'destination_module' => 'user',
636     ],
637     'd7_user_flood' => [
638       'source_module' => 'user',
639       'destination_module' => 'user',
640     ],
641     'd7_user_mail' => [
642       'source_module' => 'user',
643       'destination_module' => 'user',
644     ],
645     'd7_user_role' => [
646       'source_module' => 'user',
647       'destination_module' => 'user',
648     ],
649     'user_picture_entity_display' => [
650       'source_module' => 'user',
651       'destination_module' => 'user',
652     ],
653     'user_picture_entity_form_display' => [
654       'source_module' => 'user',
655       'destination_module' => 'user',
656     ],
657     'user_picture_field' => [
658       'source_module' => 'user',
659       'destination_module' => 'user',
660     ],
661     'user_picture_field_instance' => [
662       'source_module' => 'user',
663       'destination_module' => 'user',
664     ],
665     'user_profile_entity_display' => [
666       'source_module' => 'profile',
667       'destination_module' => 'user',
668     ],
669     'user_profile_entity_form_display' => [
670       'source_module' => 'profile',
671       'destination_module' => 'user',
672     ],
673     'user_profile_field' => [
674       'source_module' => 'profile',
675       'destination_module' => 'user',
676     ],
677     'user_profile_field_instance' => [
678       'source_module' => 'profile',
679       'destination_module' => 'user',
680     ],
681     'd6_i18n_user_profile_field_instance' => [
682       'source_module' => 'i18n',
683       'destination_module' => 'user',
684     ],
685   ];
686
687   /**
688    * The state service.
689    *
690    * @var \Drupal\Core\State\StateInterface
691    */
692   protected $state;
693
694   /**
695    * The date formatter service.
696    *
697    * @var \Drupal\Core\Datetime\DateFormatterInterface
698    */
699   protected $dateFormatter;
700
701   /**
702    * The renderer service.
703    *
704    * @var \Drupal\Core\Render\RendererInterface
705    */
706   protected $renderer;
707
708   /**
709    * The migration plugin manager.
710    *
711    * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
712    */
713   protected $pluginManager;
714
715   /**
716    * Constructs the MigrateUpgradeForm.
717    *
718    * @param \Drupal\Core\State\StateInterface $state
719    *   The state service.
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.
726    */
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;
732   }
733
734   /**
735    * {@inheritdoc}
736    */
737   public static function create(ContainerInterface $container) {
738     return new static(
739       $container->get('state'),
740       $container->get('date.formatter'),
741       $container->get('renderer'),
742       $container->get('plugin.manager.migration')
743     );
744   }
745
746   /**
747    * {@inheritdoc}
748    */
749   public function getFormId() {
750     return 'migrate_drupal_ui_form';
751   }
752
753   /**
754    * {@inheritdoc}
755    */
756   public function buildForm(array $form, FormStateInterface $form_state) {
757     $step = $form_state->get('step') ?: 'overview';
758     switch ($step) {
759       case 'overview':
760         return $this->buildOverviewForm($form, $form_state);
761
762       case 'credentials':
763         return $this->buildCredentialForm($form, $form_state);
764
765       case 'confirm':
766         return $this->buildConfirmForm($form, $form_state);
767
768       default:
769         drupal_set_message($this->t('Unrecognized form step @step', ['@step' => $step]), 'error');
770         return [];
771     }
772   }
773
774   /**
775    * {@inheritdoc}
776    */
777   public function submitForm(array &$form, FormStateInterface $form_state) {
778     // This method is intentionally empty, see the specific submit methods for
779     // each form step.
780   }
781
782   /**
783    * Builds the form presenting an overview of the migration process.
784    *
785    * @param array $form
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.
789    *
790    * @return array
791    *   The form structure.
792    */
793   public function buildOverviewForm(array $form, FormStateInterface $form_state) {
794     $form['#title'] = $this->t('Upgrade');
795
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'] = [
801         '#type' => '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)]),
804       ];
805       return $form;
806     }
807     else {
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',
811         ]),
812       ];
813
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',
820       ]);
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(),
823       ]);
824
825       $form['info'] = [
826         '#theme' => 'item_list',
827         '#list_type' => 'ol',
828         '#items' => $info,
829       ];
830
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.'),
833       ];
834
835       $validate = [];
836     }
837
838     $form['actions'] = ['#type' => 'actions'];
839     $form['actions']['save'] = [
840       '#type' => 'submit',
841       '#value' => $this->t('Continue'),
842       '#button_type' => 'primary',
843       '#validate' => $validate,
844       '#submit' => ['::submitOverviewForm'],
845     ];
846     return $form;
847   }
848
849   /**
850    * Form submission handler for the overview form.
851    *
852    * @param array $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.
856    */
857   public function submitOverviewForm(array &$form, FormStateInterface $form_state) {
858     $form_state->set('step', 'credentials');
859     $form_state->setRebuild();
860   }
861
862   /**
863    * Builds the database credential form and adds file location information.
864    *
865    * This is largely borrowed from \Drupal\Core\Installer\Form\SiteSettingsForm.
866    *
867    * @param array $form
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.
871    *
872    * @return array
873    *   The form structure.
874    *
875    * @todo Private files directory not yet implemented, depends on
876    *   https://www.drupal.org/node/2547125.
877    */
878   public function buildCredentialForm(array $form, FormStateInterface $form_state) {
879     $form['#title'] = $this->t('Drupal Upgrade');
880
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);
889
890     $default_options = [];
891
892
893     $form['version'] = [
894       '#type' => 'radios',
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')],
898       '#required' => TRUE,
899     ];
900
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.'),
905       '#open' => TRUE,
906     ];
907
908     $form['database']['driver'] = [
909       '#type' => 'radios',
910       '#title' => $this->t('Database type'),
911       '#required' => TRUE,
912       '#default_value' => $default_driver,
913     ];
914     if (count($drivers) == 1) {
915       $form['database']['driver']['#disabled'] = TRUE;
916     }
917
918     // Add driver-specific configuration options.
919     foreach ($drivers as $key => $driver) {
920       $form['database']['driver']['#options'][$key] = $driver->name();
921
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'] = [
934         'visible' => [
935           ':input[name=driver]' => ['value' => $key],
936         ],
937       ];
938
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']);
946       }
947     }
948
949     $form['source'] = [
950       '#type' => 'details',
951       '#title' => $this->t('Source files'),
952       '#open' => TRUE,
953     ];
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).'),
958       '#states' => [
959         'visible' => [
960           ':input[name="version"]' => ['value' => 6],
961         ],
962       ],
963     ];
964
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).'),
969       '#states' => [
970         'visible' => [
971           ':input[name="version"]' => ['value' => 7],
972         ],
973       ],
974     ];
975
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).'),
981       '#states' => [
982         'visible' => [
983           ':input[name="version"]' => ['value' => 7],
984         ],
985       ],
986     ];
987
988     $form['actions'] = ['#type' => 'actions'];
989     $form['actions']['save'] = [
990       '#type' => 'submit',
991       '#value' => $this->t('Review upgrade'),
992       '#button_type' => 'primary',
993       '#validate' => ['::validateCredentialForm'],
994       '#submit' => ['::submitCredentialForm'],
995     ];
996     return $form;
997   }
998
999   /**
1000    * Validation handler for the credentials form.
1001    *
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.
1006    */
1007   public function validateCredentialForm(array &$form, FormStateInterface $form_state) {
1008
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
1011     // settings.php.
1012     $driver = $form_state->getValue('driver');
1013     $drivers = $this->getDatabaseTypes();
1014     $reflection = new \ReflectionClass($drivers[$driver]);
1015     $install_namespace = $reflection->getNamespaceName();
1016
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;
1021
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);
1026       }
1027       return;
1028     }
1029
1030     try {
1031       $connection = $this->getConnection($database);
1032       $version = $this->getLegacyDrupalVersion($connection);
1033       if (!$version) {
1034         $form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database does not contain a recognizable Drupal version.'));
1035       }
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'),
1040         ]));
1041       }
1042       else {
1043         $this->createDatabaseStateSettings($database, $version);
1044         $migrations = $this->getMigrations('migrate_drupal_' . $version, $version);
1045
1046         // Get the system data from source database.
1047         $system_data = $this->getSystemData($connection);
1048
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();
1054         }
1055
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'));
1060
1061         // Store the retrived system data in form storage.
1062         $form_state->set('system_data', $system_data);
1063       }
1064     }
1065     catch (\Exception $e) {
1066       $error_message = [
1067         '#title' => $this->t('Resolve the issue below to continue the upgrade.'),
1068         '#theme' => 'item_list',
1069         '#items' => [$e->getMessage()],
1070       ];
1071       $form_state->setErrorByName($database['driver'] . '][0', $this->renderer->renderPlain($error_message));
1072     }
1073   }
1074
1075   /**
1076    * Submission handler for the credentials form.
1077    *
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.
1082    */
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();
1087   }
1088
1089   /**
1090    * Confirmation form for missing migrations, etc.
1091    *
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.
1096    *
1097    * @return array
1098    *   The form structure.
1099    */
1100   public function buildConfirmForm(array $form, FormStateInterface $form_state) {
1101     $form = parent::buildForm($form, $form_state);
1102     $form['actions']['submit']['#submit'] = ['::submitConfirmForm'];
1103
1104     $form['actions']['submit']['#value'] = $this->t('Perform upgrade');
1105
1106     $table_data = [];
1107     $system_data = [];
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');
1112       }
1113
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;
1119     }
1120     // Sort the table by source module names and within that destination
1121     // module names.
1122     ksort($table_data);
1123     foreach ($table_data as $source_module => $destination_module_info) {
1124       ksort($table_data[$source_module]);
1125     }
1126     $unmigrated_source_modules = array_diff_key($system_data['module'], $table_data);
1127
1128     // Missing migrations.
1129     $form['missing_module_list_title'] = [
1130       '#type' => 'item',
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']),
1133     ];
1134     $form['missing_module_list'] = [
1135       '#type' => 'table',
1136       '#header' => [
1137         $this->t('Source'),
1138         $this->t('Destination'),
1139       ],
1140     ];
1141     $missing_count = 0;
1142     ksort($unmigrated_source_modules);
1143     foreach ($unmigrated_source_modules as $source_module => $module_data) {
1144       if ($module_data['status']) {
1145         $missing_count++;
1146         $form['missing_module_list'][$source_module] = [
1147           'source_module' => ['#plain_text' => $source_module],
1148           'destination_module' => ['#plain_text' => 'Missing'],
1149         ];
1150       }
1151     }
1152     // Available migrations.
1153     $form['available_module_list'] = [
1154       '#tree' => TRUE,
1155       '#type' => 'details',
1156       '#title' => $this->t('Available upgrade paths'),
1157     ];
1158
1159     $form['available_module_list']['module_list'] = [
1160       '#type' => 'table',
1161       '#header' => [
1162         $this->t('Source'),
1163         $this->t('Destination'),
1164       ],
1165     ];
1166
1167     $available_count = 0;
1168     foreach ($table_data as $source_module => $destination_module_info) {
1169       $available_count++;
1170       $destination_details = [];
1171       foreach ($destination_module_info as $destination_module => $migration_ids) {
1172         $destination_details[$destination_module] = [
1173           '#type' => 'item',
1174           '#plain_text' => $destination_module,
1175         ];
1176       }
1177       $form['available_module_list']['module_list'][$source_module] = [
1178         'source_module' => ['#plain_text' => $source_module],
1179         'destination_module' => $destination_details,
1180       ];
1181     }
1182     $form['counts'] = [
1183       '#title' => 'Upgrade analysis report',
1184       '#theme' => 'item_list',
1185       '#items' => [
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'),
1188       ],
1189       '#weight' => -15,
1190     ];
1191
1192     return $form;
1193   }
1194
1195   /**
1196    * Submission handler for the confirmation form.
1197    *
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.
1202    */
1203   public function submitConfirmForm(array &$form, FormStateInterface $form_state) {
1204     $storage = $form_state->getStorage();
1205
1206     $migrations = $storage['migrations'];
1207     $config['source_base_path'] = $storage['source_base_path'];
1208     $batch = [
1209       'title' => $this->t('Running upgrade'),
1210       'progress_message' => '',
1211       'operations' => [
1212         [
1213           [MigrateUpgradeImportBatch::class, 'run'],
1214           [array_keys($migrations), $config],
1215         ],
1216       ],
1217       'finished' => [
1218         MigrateUpgradeImportBatch::class, 'finished',
1219       ],
1220     ];
1221     batch_set($batch);
1222     $form_state->setRedirect('<front>');
1223     $this->state->set('migrate_drupal_ui.performed', REQUEST_TIME);
1224   }
1225
1226   /**
1227    * Returns all supported database driver installer objects.
1228    *
1229    * @return \Drupal\Core\Database\Install\Tasks[]
1230    *   An array of available database driver installer objects.
1231    */
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();
1236   }
1237
1238   /**
1239    * {@inheritdoc}
1240    */
1241   public function getQuestion() {
1242     return $this->t('Are you sure?');
1243   }
1244
1245   /**
1246    * {@inheritdoc}
1247    */
1248   public function getCancelUrl() {
1249     return new Url('migrate_drupal_ui.upgrade');
1250   }
1251
1252   /**
1253    * {@inheritdoc}
1254    */
1255   public function getDescription() {
1256     // The description is added by the buildConfirmForm() method.
1257     // @see \Drupal\migrate_drupal_ui\Form\MigrateUpgradeForm::buildConfirmForm()
1258     return;
1259   }
1260
1261   /**
1262    * {@inheritdoc}
1263    */
1264   public function getConfirmText() {
1265     return $this->t('Perform upgrade');
1266   }
1267
1268 }