3 namespace Drupal\migrate_drupal_ui\Form;
5 use Drupal\Core\Form\FormStateInterface;
6 use Drupal\Core\State\StateInterface;
7 use Drupal\Core\TempStore\PrivateTempStoreFactory;
8 use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface;
9 use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
10 use Drupal\migrate_drupal_ui\Batch\MigrateUpgradeImportBatch;
11 use Symfony\Component\DependencyInjection\ContainerInterface;
14 * Migrate Upgrade review form.
16 * This confirmation form uses the source_module and destination_module
17 * properties on the source, destination and field plugins as well as the
18 * system data from the source to determine if there is a migration path for
19 * each module in the source.
23 class ReviewForm extends MigrateUpgradeFormBase {
28 * @var \Drupal\Core\State\StateInterface
33 * The migration plugin manager service.
35 * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
37 protected $pluginManager;
40 * The field plugin manager service.
42 * @var \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface
44 protected $fieldPluginManager;
49 * @var \Drupal\migrate\Plugin\MigrationInterface[]
51 protected $migrations;
54 * List of extensions that do not need an upgrade path.
56 * This property is an array where the keys are the major Drupal core version
57 * from which we are upgrading, and the values are arrays of extension names
58 * that do not need an upgrade path.
62 protected $noUpgradePaths = [
70 'content_permissions',
88 'imageapi_imagemagick',
111 'ctools_access_ruleset',
112 'ctools_ajax_sample',
113 'ctools_custom_content',
135 'search_embedded_form',
150 * ReviewForm constructor.
152 * @param \Drupal\Core\State\StateInterface $state
154 * @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager
155 * The migration plugin manager service.
156 * @param \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface $field_plugin_manager
157 * The field plugin manager service.
158 * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private
159 * The private tempstore factory.
161 public function __construct(StateInterface $state, MigrationPluginManagerInterface $migration_plugin_manager, MigrateFieldPluginManagerInterface $field_plugin_manager, PrivateTempStoreFactory $tempstore_private) {
162 parent::__construct($tempstore_private);
163 $this->state = $state;
164 $this->pluginManager = $migration_plugin_manager;
165 $this->fieldPluginManager = $field_plugin_manager;
171 public static function create(ContainerInterface $container) {
173 $container->get('state'),
174 $container->get('plugin.manager.migration'),
175 $container->get('plugin.manager.migrate.field'),
176 $container->get('tempstore.private')
183 public function getFormId() {
184 return 'migrate_drupal_ui_review_form';
190 public function buildForm(array $form, FormStateInterface $form_state) {
191 // Get all the data needed for this form.
192 $version = $this->store->get('version');
193 $this->migrations = $this->store->get('migrations');
194 // Fetch the system data at the first opportunity.
195 $system_data = $this->store->get('system_data');
197 // If data is missing or this is the wrong step, start over.
198 if (!$version || !$this->migrations || !$system_data ||
199 ($this->store->get('step') != 'review')) {
200 return $this->restartUpgradeForm();
203 $form = parent::buildForm($form, $form_state);
204 $form['#title'] = $this->t('What will be upgraded?');
206 // Get the source_module and destination_module for each migration.
207 $migrations = $this->pluginManager->createInstances(array_keys($this->store->get('migrations')));
209 foreach ($migrations as $migration) {
210 $migration_id = $migration->getPluginId();
211 $source_module = $migration->getSourcePlugin()->getSourceModule();
212 if (!$source_module) {
213 $this->messenger()->addError($this->t('Source module not found for @migration_id.', ['@migration_id' => $migration_id]));
215 $destination_module = $migration->getDestinationPlugin()->getDestinationModule();
216 if (!$destination_module) {
217 $this->messenger()->addError($this->t('Destination module not found for @migration_id.', ['@migration_id' => $migration_id]));
220 if ($source_module && $destination_module) {
221 $table_data[$source_module][$destination_module][$migration_id] = $migration->label();
225 // Get the source_module and destination_module from the field plugins.
226 $definitions = $this->fieldPluginManager->getDefinitions();
227 foreach ($definitions as $definition) {
228 // This is not strict so that we find field plugins with an annotation
229 // where the Drupal core version is an integer and when it is a string.
230 if (in_array($version, $definition['core'])) {
231 $source_module = $definition['source_module'];
232 $destination_module = $definition['destination_module'];
233 $table_data[$source_module][$destination_module][$definition['id']] = $definition['id'];
237 // Add source_module and destination_module for modules that do not need an
238 // upgrade path and are enabled on the source site.
239 foreach ($this->noUpgradePaths[$version] as $extension) {
240 if ($system_data['module'][$extension]['status']) {
241 $table_data[$extension]['core'][$extension] = $extension;
245 // Sort the table by source module names and within that destination
248 foreach ($table_data as $source_module => $destination_module_info) {
249 ksort($table_data[$source_module]);
252 // Remove core profiles from the system data.
253 foreach (['standard', 'minimal'] as $profile) {
254 unset($system_data['module'][$profile]);
257 $unmigrated_source_modules = array_diff_key($system_data['module'], $table_data);
259 // Missing migrations.
260 $missing_module_list = [
261 '#type' => 'details',
264 '#type' => 'html_tag',
266 '#value' => $this->t('Modules that will not be upgraded'),
267 '#attributes' => ['id' => ['error']],
269 '#description' => $this->t('There are no modules installed on your new site to replace these modules. If you proceed with the upgrade now, configuration and/or content needed by these modules will not be available on your new site. For more information, see <a href=":review">Review the pre-upgrade analysis</a> in the <a href=":migrate">Upgrading to Drupal 8</a> handbook.', [':review' => 'https://www.drupal.org/docs/8/upgrade/upgrade-using-web-browser#pre-upgrade-analysis', ':migrate' => 'https://www.drupal.org/docs/8/upgrade']),
272 $missing_module_list['module_list'] = [
275 $this->t('Drupal @version', ['@version' => $version]),
276 $this->t('Drupal 8'),
280 ksort($unmigrated_source_modules);
281 foreach ($unmigrated_source_modules as $source_module => $module_data) {
282 if ($module_data['status']) {
284 $missing_module_list['module_list'][$source_module] = [
286 '#type' => 'html_tag',
288 '#value' => $source_module,
291 'upgrade-analysis-report__status-icon',
292 'upgrade-analysis-report__status-icon--error',
296 'destination_module' => ['#plain_text' => 'Not upgraded'],
301 // Available migrations.
302 $available_module_list = [
303 '#type' => 'details',
305 '#type' => 'html_tag',
307 '#value' => $this->t('Modules that will be upgraded'),
308 '#attributes' => ['id' => ['checked']],
313 $available_module_list['module_list'] = [
316 $this->t('Drupal @version', ['@version' => $version]),
317 $this->t('Drupal 8'),
321 $available_count = 0;
322 foreach ($table_data as $source_module => $destination_module_info) {
324 $destination_details = [];
325 foreach ($destination_module_info as $destination_module => $migration_ids) {
326 $destination_details[$destination_module] = [
328 '#plain_text' => $destination_module,
331 $available_module_list['module_list'][$source_module] = [
333 '#type' => 'html_tag',
335 '#value' => $source_module,
338 'upgrade-analysis-report__status-icon',
339 'upgrade-analysis-report__status-icon--checked',
343 'destination_module' => $destination_details,
350 if ($missing_count) {
352 '#theme' => 'status_report_counter',
353 '#amount' => $missing_count,
354 '#text' => $this->formatPlural($missing_count, 'Module will not be upgraded', 'Modules will not be upgraded'),
355 '#severity' => 'error',
358 $general_info[] = $missing_module_list;
360 if ($available_count) {
362 '#theme' => 'status_report_counter',
363 '#amount' => $available_count,
364 '#text' => $this->formatPlural($available_count, 'Module will be upgraded', 'Modules will be upgraded'),
365 '#severity' => 'checked',
368 $general_info[] = $available_module_list;
371 $form['status_report_page'] = [
372 '#theme' => 'status_report_page',
373 '#counters' => $counters,
374 '#general_info' => $general_info,
377 $form['#attached']['library'][] = 'migrate_drupal_ui/base';
385 public function submitForm(array &$form, FormStateInterface $form_state) {
386 $config['source_base_path'] = $this->store->get('source_base_path');
388 'title' => $this->t('Running upgrade'),
389 'progress_message' => '',
392 [MigrateUpgradeImportBatch::class, 'run'],
393 [array_keys($this->migrations), $config],
397 MigrateUpgradeImportBatch::class, 'finished',
401 $form_state->setRedirect('<front>');
402 $this->store->set('step', 'overview');
403 $this->state->set('migrate_drupal_ui.performed', REQUEST_TIME);
409 public function getConfirmText() {
410 return $this->t('Perform upgrade');