Issue #3096101 by quietone, danflanagan8, abhisekmazumdar, anmolgoyal74, alexpott, gabesullice, Wim Leers, Matroskeen, ankithashetty, mikelutz, benjifisher, daffie, webchick: Allow migrate_drupal_ui source database to be set in settings.php

merge-requests/2817/merge
Alex Pott 2022-10-03 14:17:48 +01:00
parent a6c49dbae4
commit 9fbab426bf
No known key found for this signature in database
GPG Key ID: BDA67E7EE836E5CE
4 changed files with 450 additions and 19 deletions

View File

@ -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.
*

View File

@ -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 <a href=":url">Upgrade documentation for more detailed instructions</a>.', [':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'] = '<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;
@ -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)) {

View File

@ -0,0 +1,274 @@
<?php
namespace Drupal\Tests\migrate_drupal_ui\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
/**
* Tests migrate upgrade credential form with settings in settings.php.
*
* @group migrate_drupal_ui
*/
class SettingsTest extends WebDriverTestBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $modules = [
'migrate',
'migrate_drupal',
'migrate_drupal_ui',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
// Log in as user 1. Migrations in the UI can only be performed as user 1.
$this->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' => '',
],
];
}
}

View File

@ -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.
*