Verified Commit 9fbab426 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3096101 by quietone, danflanagan8, abhisekmazumdar, anmolgoyal74,...

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
parent a6c49dba
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -765,6 +765,49 @@
 */
$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.
 *
+92 −21
Original line number Diff line number Diff line
@@ -5,8 +5,10 @@
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 @@ public function buildForm(array $form, FormStateInterface $form_state) {
      '#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 @@ public function buildForm(array $form, FormStateInterface $form_state) {
      '#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 @@ public function buildForm(array $form, FormStateInterface $form_state) {
      // 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 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    $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 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    $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 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    $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,6 +258,12 @@ public function buildForm(array $form, FormStateInterface $form_state) {
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $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.
@@ -220,14 +279,15 @@ public function validateForm(array &$form, FormStateInterface $form_state) {

      // 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;
        }
      }
    }

    // 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 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
   * 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)) {
+274 −0
Original line number Diff line number Diff line
<?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' => '',
      ],
    ];
  }

}
+43 −0
Original line number Diff line number Diff line
@@ -765,6 +765,49 @@
 */
$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.
 *