diff --git a/core/assets/scaffold/files/default.settings.php b/core/assets/scaffold/files/default.settings.php index 5784a9c7523..ee3b49c0a8d 100644 --- a/core/assets/scaffold/files/default.settings.php +++ b/core/assets/scaffold/files/default.settings.php @@ -765,6 +765,49 @@ $settings['entity_update_backup'] = TRUE; */ $settings['migrate_node_migrate_type_classic'] = FALSE; +/** + * The default settings for migration sources. + * + * These settings are used as the default settings on the Credential form at + * /upgrade/credentials. + * + * - migrate_source_version - The version of the source database. This can be + * '6' or '7'. Defaults to '7'. + * - migrate_source_connection - The key in the $databases array for the source + * site. + * - migrate_file_public_path - The location of the source Drupal 6 or Drupal 7 + * public files. This can be a local file directory containing the source + * Drupal 6 or Drupal 7 site (e.g /var/www/docroot), or the site address + * (e.g http://example.com). + * - migrate_file_private_path - The location of the source Drupal 7 private + * files. This can be a local file directory containing the source Drupal 7 + * site (e.g /var/www/docroot), or empty to use the same value as Public + * files directory. + * + * Sample configuration for a drupal 6 source site with the source files in a + * local directory. + * + * @code + * $settings['migrate_source_version'] = '6'; + * $settings['migrate_source_connection'] = 'migrate'; + * $settings['migrate_file_public_path'] = '/var/www/drupal6'; + * @endcode + * + * Sample configuration for a drupal 7 source site with public source files on + * the source site and the private files in a local directory. + * + * @code + * $settings['migrate_source_version'] = '7'; + * $settings['migrate_source_connection'] = 'migrate'; + * $settings['migrate_file_public_path'] = 'https://drupal7.com'; + * $settings['migrate_file_private_path'] = '/var/www/drupal7'; + * @endcode + */ +# $settings['migrate_source_connection'] = ''; +# $settings['migrate_source_version'] = ''; +# $settings['migrate_file_public_path'] = ''; +# $settings['migrate_file_private_path'] = ''; + /** * Load local development override configuration, if available. * diff --git a/core/modules/migrate_drupal_ui/src/Form/CredentialForm.php b/core/modules/migrate_drupal_ui/src/Form/CredentialForm.php index 8900a507684..87e57604bb8 100644 --- a/core/modules/migrate_drupal_ui/src/Form/CredentialForm.php +++ b/core/modules/migrate_drupal_ui/src/Form/CredentialForm.php @@ -5,8 +5,10 @@ namespace Drupal\migrate_drupal_ui\Form; use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Database\Connection; +use Drupal\Core\Database\Database; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\State\StateInterface; +use Drupal\Core\Site\Settings; use Drupal\Core\TempStore\PrivateTempStoreFactory; use Drupal\migrate\Exception\RequirementsException; use Drupal\migrate\Plugin\Exception\BadPluginDefinitionException; @@ -99,19 +101,42 @@ class CredentialForm extends MigrateUpgradeFormBase { '#description' => $this->t('Provide the information to access the Drupal site you want to upgrade. Files can be imported into the upgraded site as well. See the Upgrade documentation for more detailed instructions.', [':url' => 'https://www.drupal.org/upgrade/migrate']), ]; + $migrate_source_version = Settings::get('migrate_source_version') == '6' ? '6' : '7'; $form['version'] = [ '#type' => 'radios', - '#default_value' => 7, + '#default_value' => $migrate_source_version, '#title' => $this->t('Drupal version of the source site'), '#options' => ['6' => $this->t('Drupal 6'), '7' => $this->t('Drupal 7')], '#required' => TRUE, ]; + $available_connections = array_diff(array_keys(Database::getAllConnectionInfo()), ['default']); + $options = array_combine($available_connections, $available_connections); + $migrate_source_connection = Settings::get('migrate_source_connection'); + $preferred_connections = $migrate_source_connection + ? ['migrate', $migrate_source_connection] + : ['migrate']; + $default_options = array_intersect($preferred_connections, $available_connections); + $form['source_connection'] = [ + '#type' => 'select', + '#title' => $this->t('Source connection'), + '#options' => $options, + '#default_value' => array_pop($default_options), + '#empty_option' => $this->t('- User defined -'), + '#description' => $this->t('Choose one of the keys from the $databases array or else select "User defined" and enter database credentials.'), + '#access' => !empty($options), + ]; + $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, + '#states' => [ + 'visible' => [ + ':input[name=source_connection]' => ['value' => ''], + ], + ], ]; $form['database']['driver'] = [ @@ -119,6 +144,11 @@ class CredentialForm extends MigrateUpgradeFormBase { '#title' => $this->t('Database type'), '#required' => TRUE, '#default_value' => $default_driver, + '#states' => [ + 'required' => [ + ':input[name=source_connection]' => ['value' => ''], + ], + ], ]; if (count($drivers) == 1) { $form['database']['driver']['#disabled'] = TRUE; @@ -136,6 +166,27 @@ class CredentialForm extends MigrateUpgradeFormBase { // for mysql and pgsql must not be required. $form['database']['settings'][$key]['database']['#required'] = FALSE; $form['database']['settings'][$key]['username']['#required'] = FALSE; + $form['database']['settings'][$key]['database']['#states'] = [ + 'required' => [ + ':input[name=source_connection]' => ['value' => ''], + ':input[name=driver]' => ['value' => $key], + ], + ]; + if ($key != 'sqlite') { + $form['database']['settings'][$key]['username']['#states'] = [ + 'required' => [ + ':input[name=source_connection]' => ['value' => ''], + ':input[name=driver]' => ['value' => $key], + ], + ]; + $form['database']['settings'][$key]['password']['#states'] = [ + 'required' => [ + ':input[name=source_connection]' => ['value' => ''], + ':input[name=driver]' => ['value' => $key], + ], + ]; + } + $form['database']['settings'][$key]['#prefix'] = '

' . $this->t('@driver_name settings', ['@driver_name' => $driver->name()]) . '

'; $form['database']['settings'][$key]['#type'] = 'container'; $form['database']['settings'][$key]['#tree'] = TRUE; @@ -164,6 +215,7 @@ class CredentialForm extends MigrateUpgradeFormBase { $form['source']['d6_source_base_path'] = [ '#type' => 'textfield', '#title' => $this->t('Document root for files'), + '#default_value' => Settings::get('migrate_file_public_path') ?? '', '#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' => [ @@ -176,6 +228,7 @@ class CredentialForm extends MigrateUpgradeFormBase { $form['source']['source_base_path'] = [ '#type' => 'textfield', '#title' => $this->t('Document root for public files'), + '#default_value' => Settings::get('migrate_file_public_path') ?? '', '#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' => [ @@ -188,7 +241,7 @@ class CredentialForm extends MigrateUpgradeFormBase { $form['source']['source_private_file_path'] = [ '#type' => 'textfield', '#title' => $this->t('Document root for private files'), - '#default_value' => '', + '#default_value' => Settings::get('migrate_file_private_path') ?? '', '#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). Leave blank to use the same value as Public files directory.'), '#states' => [ 'visible' => [ @@ -205,29 +258,36 @@ class CredentialForm extends MigrateUpgradeFormBase { * {@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(); + $source_connection = $form_state->getValue('source_connection'); + if ($source_connection) { + $info = Database::getConnectionInfo($source_connection); + $database = reset($info); + } + else { + // 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; + $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. - $connection = NULL; - $error_key = $database['driver'] . '][database'; - if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) { - foreach ($errors as $name => $message) { - $this->errors[$name] = $message; + // Validate the driver settings and just end here if we have any issues. + $connection = NULL; + if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) { + foreach ($errors as $name => $message) { + $this->errors[$name] = $message; + } } } // Get the Drupal version of the source database so it can be validated. + $error_key = $database['driver'] . '][database'; if (!$this->errors) { try { $connection = $this->getConnection($database); @@ -283,6 +343,17 @@ class CredentialForm extends MigrateUpgradeFormBase { * Ensures that entered path can be read. */ public function validatePaths($element, FormStateInterface $form_state) { + $version = $form_state->getValue('version'); + // Only validate the paths relevant to the legacy Drupal version. + if (($version !== '7') + && ($element['#name'] == 'source_base_path' || $element['#name'] == 'source_private_file_path')) { + return; + } + + if ($version !== '6' && ($element['#name'] == 'd6_source_base_path')) { + return; + } + if ($source = $element['#value']) { $msg = $this->t('Failed to read from @title.', ['@title' => $element['#title']]); if (UrlHelper::isExternal($source)) { diff --git a/core/modules/migrate_drupal_ui/tests/src/FunctionalJavascript/SettingsTest.php b/core/modules/migrate_drupal_ui/tests/src/FunctionalJavascript/SettingsTest.php new file mode 100644 index 00000000000..776f115f7a6 --- /dev/null +++ b/core/modules/migrate_drupal_ui/tests/src/FunctionalJavascript/SettingsTest.php @@ -0,0 +1,274 @@ +drupalLogin($this->rootUser); + } + + /** + * Test the Credential form with defaults in settings.php. + * + * @param string|null $source_connection + * The value for the source_connection select field. + * @param string $version + * The legacy Drupal version. + * @param string[] $manual + * User entered form values. + * @param string[] $databases + * Databases data or the settings array. + * @param string $expected_source_connection + * The expected source database connection key. + * + * @throws \Behat\Mink\Exception\ElementNotFoundException + * @throws \Behat\Mink\Exception\ExpectationException + * + * @dataProvider providerTestCredentialForm + */ + public function testCredentialForm($source_connection, $version, array $manual, array $databases, $expected_source_connection) { + // Write settings. + $migrate_file_public_path = '/var/www/drupal7/sites/default/files'; + $migrate_file_private_path = '/var/www/drupal7/sites/default/files/private'; + $settings['settings']['migrate_source_version'] = (object) [ + 'value' => $version, + 'required' => TRUE, + ]; + $settings['settings']['migrate_source_connection'] = (object) [ + 'value' => $source_connection, + 'required' => TRUE, + ]; + $settings['settings']['migrate_file_public_path'] = (object) [ + 'value' => $migrate_file_public_path, + 'required' => TRUE, + ]; + $settings['settings']['migrate_file_private_path'] = (object) [ + 'value' => $migrate_file_private_path, + 'required' => TRUE, + ]; + foreach ($databases as $key => $value) { + $settings['databases'][$key]['default'] = (object) [ + 'value' => $value['default'], + 'required' => TRUE, + ]; + } + $this->writeSettings($settings); + + $edits = []; + // Enter the values manually if provided. + if (!empty($manual)) { + $edit = []; + $driver = 'mysql'; + $edit[$driver]['host'] = $manual['host']; + $edit[$driver]['database'] = $manual['database']; + $edit[$driver]['username'] = $manual['username']; + $edit[$driver]['password'] = $manual['password']; + $edits = $this->translatePostValues($edit); + } + + // Start the upgrade process. + $this->drupalGet('/upgrade'); + $this->submitForm([], 'Continue'); + $session = $this->assertSession(); + // The source connection field is only displayed when there are connections + // other than default. + if (empty($databases)) { + $session->fieldNotExists('source_connection'); + } + else { + $session->fieldExists('source_connection'); + } + + // Submit the Credential form. + $this->submitForm($edits, 'Review upgrade'); + + // Confirm that the form actually submitted. IF it submitted, we should see + // error messages about reading files. If there is no error message, that + // indicates that the form did not submit. + $session->responseContains('Failed to read from Document root'); + + // Assert the form values. + $session->fieldValueEquals('version', $version); + + // Check the manually entered credentials or simply the database key. + if (empty($manual)) { + $session->fieldValueEquals('source_connection', $expected_source_connection); + } + else { + $session->fieldValueEquals('mysql[host]', $manual['host']); + $session->fieldValueEquals('mysql[database]', $manual['database']); + $session->fieldValueEquals('mysql[username]', $manual['username']); + } + + // Confirm the file paths are correct. + $session->fieldValueEquals('d6_source_base_path', $migrate_file_public_path); + $session->fieldValueEquals('source_base_path', $migrate_file_public_path); + $session->fieldValueEquals('source_private_file_path', $migrate_file_private_path); + } + + /** + * Data provider for testCredentialForm. + */ + public function providerTestCredentialForm() { + return [ + 'no values in settings.php' => [ + 'source_connection' => "", + 'version' => '7', + 'manual' => [ + 'host' => '172.18.0.2', + 'database' => 'drupal7', + 'username' => 'kate', + 'password' => 'pwd', + ], + 'databases' => [], + 'expected_source_connection' => '', + ], + 'single database in settings, migrate' => [ + 'source_connection' => 'migrate', + 'version' => '7', + 'manual' => [], + 'databases' => [ + 'migrate' => [ + 'default' => [ + 'database' => 'drupal7', + 'username' => 'user', + 'password' => 'pwd', + 'prefix' => 'test', + 'host' => '172.18.0.3', + 'port' => '3307', + 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', + 'driver' => 'mysql', + ], + ], + ], + 'expected_source_connection' => 'migrate', + ], + 'migrate_source_connection not set' => [ + 'source_connection' => '', + 'version' => '7', + 'manual' => [], + 'databases' => [ + 'migrate' => [ + 'default' => [ + 'database' => 'drupal7', + 'username' => 'user', + 'password' => 'pwd', + 'prefix' => 'test', + 'host' => '172.18.0.3', + 'port' => '3307', + 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', + 'driver' => 'mysql', + ], + ], + ], + 'expected_source_connection' => 'migrate', + ], + 'single database in settings, legacy' => [ + 'source_connection' => 'legacy', + 'version' => '6', + 'manual' => [], + 'databases' => [ + 'legacy' => [ + 'default' => [ + 'database' => 'drupal6', + 'username' => 'user', + 'password' => 'pwd', + 'prefix' => 'test', + 'host' => '172.18.0.6', + 'port' => '3307', + 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', + 'driver' => 'mysql', + ], + ], + ], + 'expected_source_connection' => 'legacy', + ], + 'two databases in settings' => [ + 'source_connection' => 'source2', + 'version' => '7', + 'manual' => [], + 'databases' => [ + 'migrate' => [ + 'default' => [ + 'database' => 'drupal7', + 'username' => 'user', + 'password' => 'pwd', + 'prefix' => 'test', + 'host' => '172.18.0.3', + 'port' => '3307', + 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', + 'driver' => 'mysql', + ], + ], + 'legacy' => [ + 'default' => [ + 'database' => 'site', + 'username' => 'user', + 'password' => 'pwd', + 'prefix' => 'test', + 'host' => '172.18.0.2', + 'port' => '3307', + 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', + 'driver' => 'mysql', + ], + ], + ], + 'expected_source_connection' => 'migrate', + ], + 'database in settings, but use manual' => [ + 'source_connection' => '', + 'version' => '7', + 'manual' => [ + 'host' => '172.18.0.2', + 'database' => 'drupal7', + 'username' => 'kate', + 'password' => 'pwd', + ], + 'databases' => [ + 'legacy' => [ + 'default' => [ + 'database' => 'site', + 'username' => 'user', + 'password' => 'pwd', + 'prefix' => 'test', + 'host' => '172.18.0.2', + 'port' => '3307', + 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', + 'driver' => 'mysql', + ], + ], + ], + 'expected_source_connection' => '', + ], + ]; + } + +} diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 5784a9c7523..ee3b49c0a8d 100644 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -765,6 +765,49 @@ $settings['entity_update_backup'] = TRUE; */ $settings['migrate_node_migrate_type_classic'] = FALSE; +/** + * The default settings for migration sources. + * + * These settings are used as the default settings on the Credential form at + * /upgrade/credentials. + * + * - migrate_source_version - The version of the source database. This can be + * '6' or '7'. Defaults to '7'. + * - migrate_source_connection - The key in the $databases array for the source + * site. + * - migrate_file_public_path - The location of the source Drupal 6 or Drupal 7 + * public files. This can be a local file directory containing the source + * Drupal 6 or Drupal 7 site (e.g /var/www/docroot), or the site address + * (e.g http://example.com). + * - migrate_file_private_path - The location of the source Drupal 7 private + * files. This can be a local file directory containing the source Drupal 7 + * site (e.g /var/www/docroot), or empty to use the same value as Public + * files directory. + * + * Sample configuration for a drupal 6 source site with the source files in a + * local directory. + * + * @code + * $settings['migrate_source_version'] = '6'; + * $settings['migrate_source_connection'] = 'migrate'; + * $settings['migrate_file_public_path'] = '/var/www/drupal6'; + * @endcode + * + * Sample configuration for a drupal 7 source site with public source files on + * the source site and the private files in a local directory. + * + * @code + * $settings['migrate_source_version'] = '7'; + * $settings['migrate_source_connection'] = 'migrate'; + * $settings['migrate_file_public_path'] = 'https://drupal7.com'; + * $settings['migrate_file_private_path'] = '/var/www/drupal7'; + * @endcode + */ +# $settings['migrate_source_connection'] = ''; +# $settings['migrate_source_version'] = ''; +# $settings['migrate_file_public_path'] = ''; +# $settings['migrate_file_private_path'] = ''; + /** * Load local development override configuration, if available. *