diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Form/MigrateDrupalUpgradeForm.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Form/MigrateDrupalUpgradeForm.php
new file mode 100644
index 0000000..3898241
--- /dev/null
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/Form/MigrateDrupalUpgradeForm.php
@@ -0,0 +1,313 @@
+t('Upgrade step 1: Source site information');
+
+ $form['site_address'] = array(
+ '#type' => 'textfield',
+ '#title' => $this->t('Source site address'),
+ '#description' => $this->t('Enter the address of your current Drupal ' .
+ 'site (e.g. "http://www.example.com"). This address will be used to ' .
+ 'retrieve any public files from the site.'),
+ );
+
+ $form['private_file_directory'] = array(
+ '#type' => 'textfield',
+ '#title' => $this->t('Private file directory'),
+ '#description' => $this->t('If you have private files on your current ' .
+ 'Drupal site which you want imported, please copy the complete private ' .
+ 'file directory to a place accessible by your new Drupal 8 web server. ' .
+ 'Enter the address of the directory (e.g., "/home/legacy_files/private" ' .
+ 'or "http://private.example.com/legacy_files/private") here.'),
+ );
+
+ $form['database_description'] = array(
+ '#markup' => $this->t('Enter the database credentials for the legacy Drupal ' .
+ 'site you are upgrading into this Drupal 8 instance:'),
+ );
+ // The following is stolen from install.core.inc. If the install process
+ // would use form classes (https://drupal.org/node/2112569), we could inherit.
+ global $databases;
+
+ $database = isset($databases['default']['default']) ? $databases['default']['default'] : array();
+
+ require_once DRUPAL_ROOT . '/core/includes/install.inc';
+ $drivers = drupal_get_database_types();
+ $drivers_keys = array_keys($drivers);
+
+ $form['driver'] = array(
+ '#type' => 'radios',
+ '#title' => t('Database type'),
+ '#required' => TRUE,
+ '#default_value' => !empty($database['driver']) ? $database['driver'] : current($drivers_keys),
+ );
+ if (count($drivers) == 1) {
+ $form['driver']['#disabled'] = TRUE;
+ }
+
+ // Add driver specific configuration options.
+ foreach ($drivers as $key => $driver) {
+ $form['driver']['#options'][$key] = $driver->name();
+
+ $form['settings'][$key] = $driver->getFormOptions($database);
+ $form['settings'][$key]['#prefix'] = '
' .
+ $this->t('@driver_name settings', array('@driver_name' => $driver->name())) . '
';
+ $form['settings'][$key]['#type'] = 'container';
+ $form['settings'][$key]['#tree'] = TRUE;
+ $form['settings'][$key]['advanced_options']['#parents'] = array($key);
+ $form['settings'][$key]['#states'] = array(
+ 'visible' => array(
+ ':input[name=driver]' => array('value' => $key),
+ )
+ );
+ }
+
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['save'] = array(
+ '#type' => 'submit',
+ '#value' => t('Next'),
+ '#button_type' => 'primary',
+ '#limit_validation_errors' => array(
+ array('driver'),
+ array(isset($form_state['input']['driver']) ? $form_state['input']['driver'] : current($drivers_keys)),
+ ),
+ );
+ return $form;
+ }
+
+ /**
+ * Prepare to import configuration.
+ */
+ public function configurationStep(array &$form_state) {
+ Database::addConnectionInfo('migrate', 'default', $form_state['database']);
+ $version = $form_state['drupal_version'];
+
+ $form['#title'] = $this->t('Upgrade step 2: Import configuration');
+
+ $form['description'] = array(
+ '#markup' => $this->t('We will now import configuration, including ' .
+ 'system settings and any vocabularies and content type and field ' .
+ 'definitions, from the Drupal @version version of your site into this ' .
+ 'new Drupal 8 site.', array('@version' => $version)),
+ '#suffix' => '
',
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => $this->t('Import configuration'),
+ );
+
+ return $form;
+ }
+
+ /**
+ * Prepare to import configuration.
+ */
+ public function contentStep(array &$form_state) {
+ Database::addConnectionInfo('migrate', 'default', $form_state['database']);
+ $version = $form_state['drupal_version'];
+
+ $form['#title'] = $this->t('Upgrade step 3: Import content');
+
+ $form['description'] = array(
+ '#markup' => $this->t('We will now import content, including any nodes, ' .
+ 'comments, users, and taxonomy terms, from the Drupal @version ' .
+ 'version of your site into this new Drupal 8 site.',
+ array('@version' => $version)),
+ '#suffix' => '
',
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => $this->t('Import content'),
+ );
+
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildForm(array $form, array &$form_state) {
+ // The multistep is for testing only. The final version will run a fixed
+ // set of migrations.
+ // @todo: Skip credential step if 'migrate' connection already defined.
+ if (!isset($form_state['database'])) {
+ $form = $this->credentialStep();
+ }
+ elseif (isset($form_state['step'])) {
+ $step = $form_state['step'];
+ switch ($step) {
+ case 'configuration':
+ // @todo: Skip configuration step if configuration import is complete.
+ $form = $this->configurationStep($form_state);
+ break;
+ case 'content':
+ $form = $this->contentStep($form_state);
+ break;
+ }
+ }
+
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateForm(array &$form, array &$form_state) {
+ if (isset($form_state['values']['driver'])) {
+ // Verify we have a valid connection to a Drupal database supported for
+ // upgrade.
+ $driver = $form_state['values']['driver'];
+ $form_state['database'] = $form_state['values'][$driver];
+ $form_state['database']['driver'] = $driver;
+ // @todo: There should be a DrupalSqlBase method to use to
+ // determine the version.
+ try {
+ Database::addConnectionInfo('migrate', 'default', $form_state['database']);
+ $connection = Database::getConnection('default', 'migrate');
+ }
+ catch (\Exception $e) {
+ $message = t('Unable to connect to the source database. %message',
+ array('%message' => $e->getMessage()));
+ $this->setFormError(NULL, $form_state, $message);
+ return;
+ }
+ if (!$connection->schema()->tableExists('node')) {
+ $this->setFormError(NULL, $form_state, t('Source database does not ' .
+ 'contain a Drupal installation.'));
+ }
+ // Note we check D8 first, because it's reintroduced the menu_router
+ // table we have used as the signature of D6.
+ elseif ($connection->schema()->tableExists('key_value')) {
+ $this->setFormError(NULL, $form_state, t('Upgrade from this version ' .
+ 'of Drupal is not supported.'));
+ }
+ elseif ($connection->schema()->tableExists('filter_format')) {
+ $form_state['drupal_version'] = 7;
+ }
+ elseif ($connection->schema()->tableExists('menu_router')) {
+ $form_state['drupal_version'] = 6;
+ }
+ else {
+ $this->setFormError(NULL, $form_state, t('Upgrade from this version ' .
+ 'of Drupal is not supported.'));
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function submitForm(array &$form, array &$form_state) {
+ if (isset($form_state['values']['driver'])) {
+ $form_state['rebuild'] = TRUE;
+ $form_state['step'] = 'configuration';
+ }
+ elseif (isset($form_state['step'])) {
+ $migration_ids = $this->getDestinationIds($form_state['step']);
+ if ($form_state['step'] == 'configuration') {
+ $form_state['rebuild'] = TRUE;
+ $form_state['step'] = 'content';
+ }
+ else {
+ $form_state['redirect'] = 'admin/config/system';
+ }
+ $batch = array(
+ 'title' => t('Running migrations'),
+ 'operations' => array(
+ array(array('Drupal\migrate_drupal\MigrateDrupalRunBatch', 'run'),
+ array($migration_ids, $form_state['database'])),
+ ),
+ 'finished' => array('Drupal\migrate_drupal\MigrateDrupalRunBatch',
+ 'finished'),
+ 'progress_message' => '',
+ 'url_options' => array('step' => 'content'),
+ );
+ $this->batchSet($batch);
+ }
+ }
+
+ /**
+ * Set a batch.
+ *
+ * @param $batch
+ */
+ protected function batchSet($batch) {
+ batch_set($batch);
+ }
+
+ /**
+ * @return EntityStorageInterface
+ */
+ protected function storage() {
+ if (!isset($this->storage)) {
+ $this->storage = \Drupal::entityManager()->getStorage('migration');
+ }
+ return $this->storage;
+ }
+
+ /**
+ * Returns the properties to be serialized
+ *
+ * @return array
+ */
+ public function __sleep() {
+ // This apparently contains a PDOStatement somewhere.
+ unset($this->storage);
+ return parent::__sleep();
+ }
+
+ /**
+ * Gets migrate_drupal configurations.
+ *
+ * @param string $step
+ * Migration configuration destination type form step.
+ *
+ * @return array
+ * An array of configuration and content migrations.
+ */
+ function getDestinationIds($step) {
+ $manifest = drupal_get_path('module', 'migrate_drupal') . '/migrate.';
+ if ($step == 'content') {
+ $manifest .= 'content';
+ }
+ else {
+ $manifest .= 'config';
+ }
+ $manifest .= '.yml';
+ $list = Yaml::parse($manifest);
+ $names = $list[$step];
+ return $names;
+ }
+}
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/MigrateDrupalRunBatch.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/MigrateDrupalRunBatch.php
index 7578161..7b5570b 100644
--- a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/MigrateDrupalRunBatch.php
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/MigrateDrupalRunBatch.php
@@ -10,7 +10,6 @@
use Drupal\Core\Database\Database;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\MigrateExecutable;
-use Drupal\migrate\MigrateMessage;
class MigrateDrupalRunBatch {
@@ -30,13 +29,55 @@ public static function run($initial_ids, $db_spec, &$context) {
}
$migration_id = reset($context['sandbox']['migration_ids']);
$migration = entity_load('migration', $migration_id);
- // @TODO: if there are no source IDs then remove php.ini time limit.
- // @TODO: move time limit back into MigrateExecutable so we can set it here.
- $executable = new MigrateExecutable($migration, new MigrateMessage());
- if ($executable->import() == MigrationInterface::RESULT_COMPLETED) {
+ if ($migration) {
+ // @TODO: if there are no source IDs then remove php.ini time limit.
+ // @TODO: move time limit back into MigrateExecutable so we can set it here.
+ $messages = new MigrateMessageCapture();
+ $executable = new MigrateExecutable($migration, $messages);
+ $migration_name = $migration->label() ? $migration->label() : $migration_id;
+ $migration_status = $executable->import();
+ switch ($migration_status) {
+ case MigrationInterface::RESULT_COMPLETED:
+ $context['message'] = t('Imported @migration',
+ array('@migration' => $migration_name));
+ break;
+ case MigrationInterface::RESULT_INCOMPLETE:
+ $context['message'] = t('Importing @migration',
+ array('@migration' => $migration_name));
+ break;
+ case MigrationInterface::RESULT_STOPPED:
+ $context['message'] = t('Import stopped by request');
+ break;
+ case MigrationInterface::RESULT_FAILED:
+ $context['message'] = t('Import of @migration failed',
+ array('@migration' => $migration_name));
+ break;
+ case MigrationInterface::RESULT_SKIPPED:
+ $context['message'] = t('Import of @migration skipped due to unfulfilled dependencies',
+ array('@migration' => $migration_name));
+ break;
+ case MigrationInterface::RESULT_DISABLED:
+ // Skip silently if disabled.
+ break;
+ }
+
+ // Add any captured messages.
+ foreach ($messages->getMessages() as $message) {
+ $context['message'] .= "
\n" . $message;
+ }
+
+ // Unless we're continuing on with this migration, take it off the list.
+ if ($executable->import() != MigrationInterface::RESULT_INCOMPLETE) {
+ array_shift($context['sandbox']['migration_ids']);
+ }
+ }
+ else {
array_shift($context['sandbox']['migration_ids']);
}
$context['finished'] = 1 - count($context['sandbox']['migration_ids']) / $context['sandbox']['max'];
+ if (!empty($context['message'])) {
+ $context['results'][] = $context['message'];
+ }
}
/**
@@ -46,6 +87,8 @@ public static function run($initial_ids, $db_spec, &$context) {
* @param $elapsed
*/
public static function finished($success, $results, $operations, $elapsed) {
-
+ foreach ($results as $message) {
+ drupal_set_message($message);
+ }
}
}
diff --git a/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/MigrateMessageCapture.php b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/MigrateMessageCapture.php
new file mode 100644
index 0000000..20a775a
--- /dev/null
+++ b/core/modules/migrate_drupal/lib/Drupal/migrate_drupal/MigrateMessageCapture.php
@@ -0,0 +1,45 @@
+messages[] = $message;
+ }
+
+ /**
+ * Clear out any captured messages.
+ */
+ public function clear() {
+ $this->messages = array();
+ }
+
+ /**
+ * Return any captured messages.
+ *
+ * @return array
+ */
+ public function getMessages() {
+ return $this->messages;
+ }
+}
diff --git a/core/modules/migrate_drupal/migrate.config.yml b/core/modules/migrate_drupal/migrate.config.yml
index 8c3d62d..a1ba7f2 100644
--- a/core/modules/migrate_drupal/migrate.config.yml
+++ b/core/modules/migrate_drupal/migrate.config.yml
@@ -4,27 +4,26 @@ configuration:
- d6_book_settings
- d6_cck_field_values:*
- d6_cck_field_revision:*
- - d6_comment_entity_display
- - d6_comment_entity_form_display
- - d6_comment_field
- - d6_comment_field_instance
- - d6_contact_category
- - d6_contact_settings
- d6_date_formats
- d6_dblog_settings
- - d6_field
- - d6_field_instance
- - d6_field_instance_widget_settings
- - d6_field_settings
- - d6_field_formatter_settings
+ - d6_view_modes
- d6_file_settings
- d6_filter_format
- d6_forum_settings
- d6_locale_settings
- d6_menu_settings
- d6_menu
- - d6_node_settings
- d6_node_type
+ - d6_node_settings
+ - d6_field
+ - d6_field_instance
+ - d6_field_instance_widget_settings
+ - d6_field_settings
+ - d6_field_formatter_settings
+ - d6_comment_field
+ - d6_comment_field_instance
+ - d6_comment_entity_display
+ - d6_comment_entity_form_display
- d6_search_page
- d6_search_settings
- d6_simpletest_settings
@@ -39,27 +38,27 @@ configuration:
- d6_system_performance
- d6_system_rss
- d6_system_site
- - d6_system_theme
- d6_taxonomy_settings
- d6_taxonomy_vocabulary
- d6_text_settings
- d6_update_settings
- - d6_upload_entity_display
- - d6_upload_entity_form_display
- d6_upload_field
- d6_upload_field_instance
+ - d6_upload_entity_display
+ - d6_upload_entity_form_display
- d6_user_mail
+ - d6_user_profile_field
- d6_user_profile_field_instance
+ - d6_user_picture_field
+ - d6_user_picture_field_instance
- d6_user_profile_entity_display
- d6_user_profile_entity_form_display
- - d6_user_profile_field
- d6_user_picture_entity_display
- d6_user_picture_entity_form_display
- - d6_user_picture_field_instance
- - d6_user_picture_field
- d6_user_role
- - d6_view_modes
+ - d6_contact_category
+ - d6_contact_settings
+ - d6_vocabulary_field
+ - d6_vocabulary_field_instance
- d6_vocabulary_entity_display
- d6_vocabulary_entity_form_display
- - d6_vocabulary_field_instance
- - d6_vocabulary_field
diff --git a/core/modules/migrate_drupal/migrate.content.yml b/core/modules/migrate_drupal/migrate.content.yml
index 9819a8d..3f6d993 100644
--- a/core/modules/migrate_drupal/migrate.content.yml
+++ b/core/modules/migrate_drupal/migrate.content.yml
@@ -2,14 +2,19 @@ content:
- d6_aggregator_feed
- d6_aggregator_item
- d6_block
- - d6_comment
- d6_custom_block
- d6_file
- - d6_profile_values:user
- d6_taxonomy_term
- - d6_term_node_revision:*
+ - d6_user_picture_file
+ - d6_user
+ - d6_profile_values:user
+ - d6_node:*
+ - d6_book
+ - d6_cck_field_values
+ - d6_node_revision:*
+ - d6_cck_field_revision
- d6_term_node:*
+ - d6_term_node_revision:*
+ - d6_comment
- d6_upload
- - d6_url_alias
- - d6_user
- - d6_user_picture_file
+# - d6_url_alias
diff --git a/core/modules/migrate_drupal/migrate_drupal.menu_links.yml b/core/modules/migrate_drupal/migrate_drupal.menu_links.yml
new file mode 100644
index 0000000..ccd137c
--- /dev/null
+++ b/core/modules/migrate_drupal/migrate_drupal.menu_links.yml
@@ -0,0 +1,5 @@
+migrate_drupal.upgrade:
+ title: Upgrade from Drupal 6 or Drupal 7
+ parent: system.admin_config_system
+ description: 'Migrate configuration and content from your previous Drupal version.'
+ route_name: migrate_drupal.upgrade
diff --git a/core/modules/migrate_drupal/migrate_drupal.routing.yml b/core/modules/migrate_drupal/migrate_drupal.routing.yml
index a7e8fef..eb24fee 100644
--- a/core/modules/migrate_drupal/migrate_drupal.routing.yml
+++ b/core/modules/migrate_drupal/migrate_drupal.routing.yml
@@ -5,3 +5,10 @@ migrate_drupal.run:
_title: 'Run'
requirements:
_permission: 'administer site configuration'
+migrate_drupal.upgrade:
+ path: '/admin/config/system/upgrade'
+ defaults:
+ _form: '\Drupal\migrate_drupal\Form\MigrateDrupalUpgradeForm'
+ _title: 'Migration'
+ requirements:
+ _permission: 'administer site configuration'