Issue #2918761 by quietone, chiranjeeb2410, phenaproxima, maxocub, heddn, alexpott: Break up MigrateUpgradeForm into smaller forms

8.6.x
Alex Pott 2018-02-12 21:25:39 +00:00
parent c7833e3553
commit da3818ab0e
8 changed files with 1206 additions and 1078 deletions

View File

@ -1,7 +1,43 @@
migrate_drupal_ui.upgrade:
path: '/upgrade'
defaults:
_form: '\Drupal\migrate_drupal_ui\Form\MigrateUpgradeForm'
_form: '\Drupal\migrate_drupal_ui\Form\OverviewForm'
_title: 'Upgrade'
requirements:
_custom_access: '\Drupal\migrate_drupal_ui\MigrateAccessCheck::checkAccess'
options:
_admin_route: TRUE
migrate_drupal_ui.upgrade_incremental:
path: '/upgrade/incremental'
defaults:
_form: '\Drupal\migrate_drupal_ui\Form\IncrementalForm'
_title: 'Upgrade'
requirements:
_custom_access: '\Drupal\migrate_drupal_ui\MigrateAccessCheck::checkAccess'
options:
_admin_route: TRUE
migrate_drupal_ui.upgrade_credential:
path: '/upgrade/credentials'
defaults:
_form: '\Drupal\migrate_drupal_ui\Form\CredentialForm'
_title: 'Upgrade'
requirements:
_custom_access: '\Drupal\migrate_drupal_ui\MigrateAccessCheck::checkAccess'
options:
_admin_route: TRUE
migrate_drupal_ui.upgrade_id_conflict:
path: '/upgrade/idconflict'
defaults:
_form: '\Drupal\migrate_drupal_ui\Form\IdConflictForm'
_title: 'Upgrade'
requirements:
_custom_access: '\Drupal\migrate_drupal_ui\MigrateAccessCheck::checkAccess'
options:
_admin_route: TRUE
migrate_drupal_ui.upgrade_review:
path: '/upgrade/review'
defaults:
_form: '\Drupal\migrate_drupal_ui\Form\ReviewForm'
_title: 'Upgrade'
requirements:
_custom_access: '\Drupal\migrate_drupal_ui\MigrateAccessCheck::checkAccess'

View File

@ -0,0 +1,257 @@
<?php
namespace Drupal\migrate_drupal_ui\Form;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Migrate Upgrade database credential form.
*
* @internal
*/
class CredentialForm extends MigrateUpgradeFormBase {
/**
* The renderer service.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* CredentialForm constructor.
*
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer service.
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private
* The private tempstore factory.
*/
public function __construct(RendererInterface $renderer, PrivateTempStoreFactory $tempstore_private) {
parent::__construct($tempstore_private);
$this->renderer = $renderer;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('renderer'),
$container->get('tempstore.private')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'migrate_drupal_ui_credential_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
if ($this->store->get('step') != 'credential') {
$this->store->set('step', 'overview');
return $this->redirect('migrate_drupal_ui.upgrade');
}
$form = parent::buildForm($form, $form_state);
$form['actions']['submit']['#value'] = $this->t('Review upgrade');
$form['#title'] = $this->t('Drupal Upgrade');
$drivers = $this->getDatabaseTypes();
$drivers_keys = array_keys($drivers);
// @todo https://www.drupal.org/node/2678510 Because this is a multi-step
// form, the form is not rebuilt during submission. Ideally we would get
// the chosen driver from form input, if available, in order to use
// #limit_validation_errors in the same way
// \Drupal\Core\Installer\Form\SiteSettingsForm does.
$default_driver = current($drivers_keys);
$default_options = [];
$form['version'] = [
'#type' => 'radios',
'#default_value' => 7,
'#title' => $this->t('Drupal version of the source site'),
'#options' => ['6' => $this->t('Drupal 6'), '7' => $this->t('Drupal 7')],
'#required' => TRUE,
];
$form['database'] = [
'#type' => 'details',
'#title' => $this->t('Source database'),
'#description' => $this->t('Provide credentials for the database of the Drupal site you want to upgrade.'),
'#open' => TRUE,
];
$form['database']['driver'] = [
'#type' => 'radios',
'#title' => $this->t('Database type'),
'#required' => TRUE,
'#default_value' => $default_driver,
];
if (count($drivers) == 1) {
$form['database']['driver']['#disabled'] = TRUE;
}
// Add driver-specific configuration options.
foreach ($drivers as $key => $driver) {
$form['database']['driver']['#options'][$key] = $driver->name();
$form['database']['settings'][$key] = $driver->getFormOptions($default_options);
// @todo https://www.drupal.org/node/2678510 Using
// #limit_validation_errors in the submit does not work so it is not
// possible to require the database and username for mysql and pgsql.
// This is because this is a multi-step form.
$form['database']['settings'][$key]['database']['#required'] = FALSE;
$form['database']['settings'][$key]['username']['#required'] = FALSE;
$form['database']['settings'][$key]['#prefix'] = '<h2 class="js-hide">' . $this->t('@driver_name settings', ['@driver_name' => $driver->name()]) . '</h2>';
$form['database']['settings'][$key]['#type'] = 'container';
$form['database']['settings'][$key]['#tree'] = TRUE;
$form['database']['settings'][$key]['advanced_options']['#parents'] = [$key];
$form['database']['settings'][$key]['#states'] = [
'visible' => [
':input[name=driver]' => ['value' => $key],
],
];
// Move the host fields out of advanced settings.
if (isset($form['database']['settings'][$key]['advanced_options']['host'])) {
$form['database']['settings'][$key]['host'] = $form['database']['settings'][$key]['advanced_options']['host'];
$form['database']['settings'][$key]['host']['#title'] = 'Database host';
$form['database']['settings'][$key]['host']['#weight'] = -1;
unset($form['database']['settings'][$key]['database']['#default_value']);
unset($form['database']['settings'][$key]['advanced_options']['host']);
}
}
$form['source'] = [
'#type' => 'details',
'#title' => $this->t('Source files'),
'#open' => TRUE,
];
$form['source']['d6_source_base_path'] = [
'#type' => 'textfield',
'#title' => $this->t('Files directory'),
'#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).'),
'#states' => [
'visible' => [
':input[name="version"]' => ['value' => '6'],
],
],
];
$form['source']['source_base_path'] = [
'#type' => 'textfield',
'#title' => $this->t('Public files directory'),
'#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).'),
'#states' => [
'visible' => [
':input[name="version"]' => ['value' => '7'],
],
],
];
$form['source']['source_private_file_path'] = [
'#type' => 'textfield',
'#title' => $this->t('Private file directory'),
'#default_value' => '',
'#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).'),
'#states' => [
'visible' => [
':input[name="version"]' => ['value' => '7'],
],
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Retrieve the database driver from the form, use reflection to get the
// namespace, and then construct a valid database array the same as in
// settings.php.
$driver = $form_state->getValue('driver');
$drivers = $this->getDatabaseTypes();
$reflection = new \ReflectionClass($drivers[$driver]);
$install_namespace = $reflection->getNamespaceName();
$database = $form_state->getValue($driver);
// Cut the trailing \Install from namespace.
$database['namespace'] = substr($install_namespace, 0, strrpos($install_namespace, '\\'));
$database['driver'] = $driver;
// Validate the driver settings and just end here if we have any issues.
if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) {
foreach ($errors as $name => $message) {
$form_state->setErrorByName($name, $message);
}
return;
}
try {
$connection = $this->getConnection($database);
$version = (string) $this->getLegacyDrupalVersion($connection);
if (!$version) {
$form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database does not contain a recognizable Drupal version.'));
}
elseif ($version !== (string) $form_state->getValue('version')) {
$form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database is Drupal version @version but version @selected was selected.', [
'@version' => $version,
'@selected' => $form_state->getValue('version'),
]));
}
else {
// Setup migrations and save form data to private store.
$this->setupMigrations($database, $form_state);
}
}
catch (\Exception $e) {
$error_message = [
'#title' => $this->t('Resolve the issue below to continue the upgrade.'),
'#theme' => 'item_list',
'#items' => [$e->getMessage()],
];
$form_state->setErrorByName($database['driver'] . '][0', $this->renderer->renderPlain($error_message));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->store->set('step', 'id_conflict');
$form_state->setRedirect('migrate_drupal_ui.upgrade_id_conflict');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Review upgrade');
}
/**
* Returns all supported database driver installer objects.
*
* @return \Drupal\Core\Database\Install\Tasks[]
* An array of available database driver installer objects.
*/
protected function getDatabaseTypes() {
// Make sure the install API is available.
include_once DRUPAL_ROOT . '/core/includes/install.inc';
return drupal_get_database_types();
}
}

View File

@ -0,0 +1,200 @@
<?php
namespace Drupal\migrate_drupal_ui\Form;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\migrate\Audit\IdAuditor;
use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Migrate Upgrade Id Conflict form.
*
* @internal
*/
class IdConflictForm extends MigrateUpgradeFormBase {
/**
* The migration plugin manager service.
*
* @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
*/
protected $pluginManager;
/**
* IdConflictForm constructor.
*
* @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager
* The migration plugin manager service.
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private
* The private tempstore factory.
*/
public function __construct(MigrationPluginManagerInterface $migration_plugin_manager, PrivateTempStoreFactory $tempstore_private) {
parent::__construct($tempstore_private);
$this->pluginManager = $migration_plugin_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('plugin.manager.migration'),
$container->get('tempstore.private')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'migrate_drupal_ui_id_conflict_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
if ($this->store->get('step') != 'id_conflict') {
$this->store->set('step', 'overview');
return $this->redirect('migrate_drupal_ui.upgrade');
}
// Check if there are conflicts. If none, just skip this form!
$migration_ids = array_keys($this->store->get('migrations'));
$migrations = $this->pluginManager->createInstances($migration_ids);
$translated_content_conflicts = $content_conflicts = [];
$results = (new IdAuditor())->auditMultiple($migrations);
/** @var \Drupal\migrate\Audit\AuditResult $result */
foreach ($results as $result) {
$destination = $result->getMigration()->getDestinationPlugin();
if ($destination instanceof EntityContentBase && $destination->isTranslationDestination()) {
// Translations are not yet supported by the audit system. For now, we
// only warn the user to be cautious when migrating translated content.
// I18n support should be added in https://www.drupal.org/node/2905759.
$translated_content_conflicts[] = $result;
}
elseif (!$result->passed()) {
$content_conflicts[] = $result;
}
}
if ($content_conflicts || $translated_content_conflicts) {
$this->messenger()->addWarning($this->t('WARNING: Content may be overwritten on your new site.'));
$form = parent::buildForm($form, $form_state);
$form['#title'] = $this->t('Upgrade analysis report');
if ($content_conflicts) {
$form = $this->conflictsForm($form, $content_conflicts);
}
if ($translated_content_conflicts) {
$form = $this->i18nWarningForm($form, $translated_content_conflicts);
}
return $form;
}
else {
$this->store->set('step', 'review');
return $this->redirect('migrate_drupal_ui.upgrade_review');
}
}
/**
* Build the markup for conflict warnings.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\migrate\Audit\AuditResult[] $conflicts
* The failing audit results.
*
* @return array
* The form structure.
*/
protected function conflictsForm(array &$form, array $conflicts) {
$form['conflicts'] = [
'#title' => $this->t('There is conflicting content of these types:'),
'#theme' => 'item_list',
'#items' => $this->formatConflicts($conflicts),
];
$form['warning'] = [
'#type' => 'markup',
'#markup' => '<p>' . $this->t('It looks like you have content on your new site which <strong>may be overwritten</strong> if you continue to run this upgrade. The upgrade should be performed on a clean Drupal 8 installation. For more information see the <a target="_blank" href=":id-conflicts-handbook">upgrade handbook</a>.', [':id-conflicts-handbook' => 'https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#id_conflicts']) . '</p>',
];
return $form;
}
/**
* Formats a set of failing audit results as strings.
*
* Each string is the label of the destination plugin of the migration that
* failed the audit, keyed by the destination plugin ID in order to prevent
* duplication.
*
* @param \Drupal\migrate\Audit\AuditResult[] $conflicts
* The failing audit results.
*
* @return string[]
* The formatted audit results.
*/
protected function formatConflicts(array $conflicts) {
$items = [];
foreach ($conflicts as $conflict) {
$definition = $conflict->getMigration()->getDestinationPlugin()->getPluginDefinition();
$id = $definition['id'];
$items[$id] = $definition['label'];
}
sort($items, SORT_STRING);
return $items;
}
/**
* Build the markup for i18n warnings.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\migrate\Audit\AuditResult[] $conflicts
* The failing audit results.
*
* @return array
* The form structure.
*/
protected function i18nWarningForm(array &$form, array $conflicts) {
$form['i18n'] = [
'#title' => $this->t('There is translated content of these types:'),
'#theme' => 'item_list',
'#items' => $this->formatConflicts($conflicts),
];
$form['i18n_warning'] = [
'#type' => 'markup',
'#markup' => '<p>' . $this->t('It looks like you are migrating translated content from your old site. Possible ID conflicts for translations are not automatically detected in the current version of Drupal. Refer to the <a target="_blank" href=":id-conflicts-handbook">upgrade handbook</a> for instructions on how to avoid ID conflicts with translated content.', [':id-conflicts-handbook' => 'https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#id_conflicts']) . '</p>',
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->store->set('step', 'review');
$form_state->setRedirect('migrate_drupal_ui.upgrade_review');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('I acknowledge I may lose data. Continue anyway.');
}
}

View File

@ -0,0 +1,131 @@
<?php
namespace Drupal\migrate_drupal_ui\Form;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Migrate Upgrade Incremental form.
*
* @internal
*/
class IncrementalForm extends MigrateUpgradeFormBase {
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The date formatter service.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/**
* IncrementalForm constructor.
*
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
* The date formatter service.
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private
* The private temp store factory.
*/
public function __construct(StateInterface $state, DateFormatterInterface $date_formatter, PrivateTempStoreFactory $tempstore_private) {
parent::__construct($tempstore_private);
$this->state = $state;
$this->dateFormatter = $date_formatter;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('state'),
$container->get('date.formatter'),
$container->get('tempstore.private')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'migrate_drupal_ui_incremental_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
if ($this->store->get('step') != 'incremental') {
$this->store->set('step', 'overview');
return $this->redirect('migrate_drupal_ui.upgrade');
}
$form = parent::buildForm($form, $form_state);
$form['#title'] = $this->t('Upgrade');
$date_performed = $this->store->get('performed');
// @todo Add back support for rollbacks.
// https://www.drupal.org/node/2687849
$form['upgrade_option_item'] = [
'#type' => 'item',
'#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 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']),
'#description' => $this->t('Last upgrade: @date', ['@date' => $this->dateFormatter->format($date_performed)]),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Retrieve the database driver from state.
$database_state_key = $this->state->get('migrate.fallback_state_key', '');
if ($database_state_key) {
try {
$database = $this->state->get($database_state_key, [])['database'];
if ($connection = $this->getConnection($database)) {
if ($version = $this->getLegacyDrupalVersion($connection)) {
$this->setupMigrations($database, $form_state);
$valid_legacy_database = TRUE;
}
}
}
catch (DatabaseExceptionWrapper $exception) {
// Hide DB exceptions and forward to the DB credentials form. In that
// form we can more properly display errors and accept new credentials.
}
}
if (empty($valid_legacy_database)) {
$form_state->setValue('step', 'credentials')->setRebuild();
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->store->set('step', 'id_conflict');
$form_state->setRedirect('migrate_drupal_ui.upgrade_id_conflict');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Import new configuration and content from old site');
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
<?php
namespace Drupal\migrate_drupal_ui\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\migrate_drupal\MigrationConfigurationTrait;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Form base for the Migrate Upgrade UI.
*/
abstract class MigrateUpgradeFormBase extends FormBase {
use MigrationConfigurationTrait;
/**
* Private temporary storage.
*
* @var \Drupal\Core\TempStore\PrivateTempStoreFactory
*/
protected $store;
/**
* Constructs the Migrate Upgrade Form Base.
*
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private
* Private store.
*/
public function __construct(PrivateTempStoreFactory $tempstore_private) {
$this->store = $tempstore_private->get('migrate_drupal_ui');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('tempstore.private')
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = [];
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->getConfirmText(),
'#button_type' => 'primary',
'#weight' => 10,
];
return $form;
}
/**
* Puts migrations information in form state.
*
* Gets all the migrations, converts each to an array and stores it in the
* form state. The source base path for public and private files is also
* put into form state.
*
* @param array $database
* Database array representing the source Drupal database.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
protected function setupMigrations(array $database, FormStateInterface $form_state) {
$connection = $this->getConnection($database);
$version = $this->getLegacyDrupalVersion($connection);
$this->createDatabaseStateSettings($database, $version);
$migrations = $this->getMigrations('migrate_drupal_' . $version, $version);
// Get the system data from source database.
$system_data = $this->getSystemData($connection);
// Convert the migration object into array
// so that it can be stored in form storage.
$migration_array = [];
foreach ($migrations as $migration) {
$migration_array[$migration->id()] = $migration->label();
}
// Store information in the private store.
$this->store->set('version', $version);
$this->store->set('migrations', $migration_array);
if ($version == 6) {
$this->store->set('source_base_path', $form_state->getValue('d6_source_base_path'));
}
else {
$this->store->set('source_base_path', $form_state->getValue('source_base_path'));
}
$this->store->set('source_private_file_path', $form_state->getValue('source_private_file_path'));
// Store the retrieved system data in the private store.
$this->store->set('system_data', $system_data);
}
/**
* Returns a caption for the button that confirms the action.
*
* @return string
* The form confirmation text.
*/
abstract protected function getConfirmText();
}

View File

@ -0,0 +1,92 @@
<?php
namespace Drupal\migrate_drupal_ui\Form;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
/**
* Migrate Upgrade Overview form.
*
* @internal
*/
class OverviewForm extends MigrateUpgradeFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'migrate_drupal_ui_overview_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
// If an upgrade has already been performed, redirect to the incremental
// form.
if ($this->store->get('performed')) {
$this->store->set('step', 'incremental');
return $this->redirect('migrate_drupal_ui.upgrade_incremental');
}
$form['#title'] = $this->t('Upgrade');
$form['info_header'] = [
'#markup' => '<p>' . $this->t('Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal 8. See the <a href=":url">Drupal site upgrades handbook</a> for more information.', [
':url' => 'https://www.drupal.org/upgrade/migrate',
]),
];
$form['legend']['#markup'] = '';
$form['legend']['#markup'] .= '<h3>' . $this->t('Definitions') . '</h3>';
$form['legend']['#markup'] .= '<dl>';
$form['legend']['#markup'] .= '<dt>' . $this->t('Old site') . '</dt>';
$form['legend']['#markup'] .= '<dd>' . $this->t('The site you want to upgrade.') . '</dd>';
$form['legend']['#markup'] .= '<dt>' . $this->t('New site') . '</dt>';
$form['legend']['#markup'] .= '<dd>' . $this->t('This empty Drupal 8 installation you will import the old site to.') . '</dd>';
$form['legend']['#markup'] .= '</dl>';
$info[] = $this->t('Make sure that <strong>access to the database</strong> for the old site is available from this new site.');
$info[] = $this->t('<strong>If the old site has private files</strong>, a copy of its files directory must also be accessible on the host of this new site.');
$info[] = $this->t('<strong>Enable all modules on this new site</strong> that are enabled on the old site. For example, if the old site uses the book module, then enable the book module on this new site so that the existing data can be imported to it.');
$info[] = $this->t('<strong>Do not add any content to the new site</strong> before upgrading. Any existing content is likely to be overwritten by the upgrade process. See <a href=":url">the upgrade preparation guide</a>.', [
':url' => 'https://www.drupal.org/docs/8/upgrade/preparing-an-upgrade#dont_create_content',
]);
$info[] = $this->t('Put this site into <a href=":url">maintenance mode</a>.', [
':url' => Url::fromRoute('system.site_maintenance_mode')
->toString(TRUE)
->getGeneratedUrl(),
]);
$form['info'] = [
'#theme' => 'item_list',
'#title' => $this->t('Preparation steps'),
'#list_type' => 'ol',
'#items' => $info,
];
$form['info_footer'] = [
'#markup' => '<p>' . $this->t('The upgrade can take a long time. It is better to upgrade from a local copy of your site instead of directly from your live site.'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->store->set('step', 'credential');
$form_state->setRedirect('migrate_drupal_ui.upgrade_credential');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Continue');
}
}

View File

@ -0,0 +1,380 @@
<?php
namespace Drupal\migrate_drupal_ui\Form;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface;
use Drupal\migrate_drupal_ui\Batch\MigrateUpgradeImportBatch;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Migrate Upgrade review form.
*
* This confirmation form uses the source_module and destination_module
* properties on the source, destination and field plugins as well as the
* system data from the source to determine if there is a migration path for
* each module in the source.
*
* @internal
*/
class ReviewForm extends MigrateUpgradeFormBase {
/**
* The field plugin manager service.
*
* @var \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface
*/
protected $fieldPluginManager;
/**
* List of extensions that do not need an upgrade path.
*
* This property is an array where the keys are the major Drupal core version
* from which we are upgrading, and the values are arrays of extension names
* that do not need an upgrade path.
*
* @var array[]
*/
protected $noUpgradePaths = [
'6' => [
'blog',
'blogapi',
'calendarsignup',
'color',
'content_copy',
'content_multigroup',
'content_permissions',
'date_api',
'date_locale',
'date_php4',
'date_popup',
'date_repeat',
'date_timezone',
'date_tools',
'datepicker',
'ddblock',
'event',
'fieldgroup',
'filefield_meta',
'help',
'i18n',
'i18nstrings',
'imageapi',
'imageapi_gd',
'imageapi_imagemagick',
'imagecache_ui',
'jquery_ui',
'nodeaccess',
'number',
'openid',
'php',
'ping',
'poll',
'throttle',
'tracker',
'translation',
'trigger',
'variable',
'variable_admin',
'views_export',
'views_ui',
],
'7' => [
'blog',
'bulk_export',
'contextual',
'ctools',
'ctools_access_ruleset',
'ctools_ajax_sample',
'ctools_custom_content',
'dashboard',
'date_all_day',
'date_api',
'date_context',
'date_migrate',
'date_popup',
'date_repeat',
'date_repeat_field',
'date_tools',
'date_views',
'entity',
'entity_feature',
'entity_token',
'entityreference',
'field_ui',
'help',
'openid',
'overlay',
'page_manager',
'php',
'poll',
'search_embedded_form',
'search_extra_type',
'search_node_tags',
'simpletest',
'stylizer',
'term_depth',
'toolbar',
'translation',
'trigger',
'views_content',
'views_ui',
],
];
/**
* ReviewForm constructor.
*
* @param \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface $field_plugin_manager
* The field plugin manager service.
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private
* The private tempstore factory.
*/
public function __construct(MigrateFieldPluginManagerInterface $field_plugin_manager, PrivateTempStoreFactory $tempstore_private) {
parent::__construct($tempstore_private);
$this->fieldPluginManager = $field_plugin_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('plugin.manager.migrate.field'),
$container->get('tempstore.private')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'migrate_drupal_ui_review_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
if ($this->store->get('step') != 'review') {
$this->store->set('step', 'overview');
return $this->redirect('migrate_drupal_ui.upgrade');
}
$form = parent::buildForm($form, $form_state);
$form['#title'] = $this->t('What will be upgraded?');
$version = $this->store->get('version');
// Get the source_module and destination_module for each migration.
$migrations = $this->getMigrations('migrate_drupal_' . $version, $version);
$table_data = [];
foreach ($migrations as $migration) {
$migration_id = $migration->getPluginId();
$source_module = $migration->getSourcePlugin()->getSourceModule();
if (!$source_module) {
$this->messenger()->addError($this->t('Source module not found for @migration_id.', ['@migration_id' => $migration_id]));
}
$destination_module = $migration->getDestinationPlugin()->getDestinationModule();
if (!$destination_module) {
$this->messenger()->addError($this->t('Destination module not found for @migration_id.', ['@migration_id' => $migration_id]));
}
if ($source_module && $destination_module) {
$table_data[$source_module][$destination_module][$migration_id] = $migration->label();
}
}
// Get the source_module and destination_module from the field plugins.
$definitions = $this->fieldPluginManager->getDefinitions();
foreach ($definitions as $definition) {
// This is not strict so that we find field plugins with an annotation
// where the Drupal core version is an integer and when it is a string.
if (in_array($version, $definition['core'])) {
$source_module = $definition['source_module'];
$destination_module = $definition['destination_module'];
$table_data[$source_module][$destination_module][$definition['id']] = $definition['id'];
}
}
// Fetch the system data at the first opportunity.
$system_data = $this->store->get('system_data');
// Add source_module and destination_module for modules that do not need an
// upgrade path and are enabled on the source site.
foreach ($this->noUpgradePaths[$version] as $extension) {
if ($system_data['module'][$extension]['status']) {
$table_data[$extension]['core'][$extension] = $extension;
}
}
// Sort the table by source module names and within that destination
// module names.
ksort($table_data);
foreach ($table_data as $source_module => $destination_module_info) {
ksort($table_data[$source_module]);
}
// Remove core profiles from the system data.
foreach (['standard', 'minimal'] as $profile) {
unset($system_data['module'][$profile]);
}
$unmigrated_source_modules = array_diff_key($system_data['module'], $table_data);
// Missing migrations.
$missing_module_list = [
'#type' => 'details',
'#open' => TRUE,
'#title' => [
'#type' => 'html_tag',
'#tag' => 'span',
'#value' => $this->t('Modules that will not be upgraded'),
'#attributes' => ['id' => ['error']],
],
'#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']),
'#weight' => 2,
];
$missing_module_list['module_list'] = [
'#type' => 'table',
'#header' => [
$this->t('Drupal @version', ['@version' => $version]),
$this->t('Drupal 8'),
],
];
$missing_count = 0;
ksort($unmigrated_source_modules);
foreach ($unmigrated_source_modules as $source_module => $module_data) {
if ($module_data['status']) {
$missing_count++;
$missing_module_list['module_list'][$source_module] = [
'source_module' => [
'#type' => 'html_tag',
'#tag' => 'span',
'#value' => $source_module,
'#attributes' => [
'class' => [
'upgrade-analysis-report__status-icon',
'upgrade-analysis-report__status-icon--error',
],
],
],
'destination_module' => ['#plain_text' => 'Not upgraded'],
];
}
}
// Available migrations.
$available_module_list = [
'#type' => 'details',
'#title' => [
'#type' => 'html_tag',
'#tag' => 'span',
'#value' => $this->t('Modules that will be upgraded'),
'#attributes' => ['id' => ['checked']],
],
'#weight' => 3,
];
$available_module_list['module_list'] = [
'#type' => 'table',
'#header' => [
$this->t('Drupal @version', ['@version' => $version]),
$this->t('Drupal 8'),
],
];
$available_count = 0;
foreach ($table_data as $source_module => $destination_module_info) {
$available_count++;
$destination_details = [];
foreach ($destination_module_info as $destination_module => $migration_ids) {
$destination_details[$destination_module] = [
'#type' => 'item',
'#plain_text' => $destination_module,
];
}
$available_module_list['module_list'][$source_module] = [
'source_module' => [
'#type' => 'html_tag',
'#tag' => 'span',
'#value' => $source_module,
'#attributes' => [
'class' => [
'upgrade-analysis-report__status-icon',
'upgrade-analysis-report__status-icon--checked',
],
],
],
'destination_module' => $destination_details,
];
}
$counters = [];
$general_info = [];
if ($missing_count) {
$counters[] = [
'#theme' => 'status_report_counter',
'#amount' => $missing_count,
'#text' => $this->formatPlural($missing_count, 'Module will not be upgraded', 'Modules will not be upgraded'),
'#severity' => 'error',
'#weight' => 0,
];
$general_info[] = $missing_module_list;
}
if ($available_count) {
$counters[] = [
'#theme' => 'status_report_counter',
'#amount' => $available_count,
'#text' => $this->formatPlural($available_count, 'Module will be upgraded', 'Modules will be upgraded'),
'#severity' => 'checked',
'#weight' => 1,
];
$general_info[] = $available_module_list;
}
$form['status_report_page'] = [
'#theme' => 'status_report_page',
'#counters' => $counters,
'#general_info' => $general_info,
];
$form['#attached']['library'][] = 'migrate_drupal_ui/base';
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$migrations = $this->store->get('migrations');
$config['source_base_path'] = $this->store->get('source_base_path');
$batch = [
'title' => $this->t('Running upgrade'),
'progress_message' => '',
'operations' => [
[
[MigrateUpgradeImportBatch::class, 'run'],
[array_keys($migrations), $config],
],
],
'finished' => [
MigrateUpgradeImportBatch::class, 'finished',
],
];
batch_set($batch);
$form_state->setRedirect('<front>');
$this->store->set('step', 'overview');
$this->store->set('performed', REQUEST_TIME);
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Perform upgrade');
}
}