Skip to content
Snippets Groups Projects
Commit fba5e54e authored by catch's avatar catch
Browse files

Issue #3312733 by benjifisher, quietone, longwave, mikelutz, smustgrave: SQL...

Issue #3312733 by benjifisher, quietone, longwave, mikelutz, smustgrave: SQL migrations cannot be instantiated if database is not available and Node, Migrate Drupal modules are enabled

(cherry picked from commit c326b923)
parent d238872a
No related branches found
No related tags found
27 merge requests!11628Update file MediaLibraryWidget.php,!7564Revert "Issue #3364773 by roshnichordiya, Chris Matthews, thakurnishant_06,...,!5752Issue #3275828 by joachim, quietone, bradjones1, Berdir: document the reason...,!5627Issue #3261805: Field not saved when change of 0 on string start,!5427Issue #3338518: send credentials in ajax if configured in CORS settings.,!5395Issue #3387916 by fjgarlin, Spokje: Each GitLab job exposes user email,!5217Issue #3386607 by alexpott: Improve spell checking in commit-code-check.sh,!5064Issue #3379522 by finnsky, Gauravvvv, kostyashupenko, smustgrave, Chi: Revert...,!5040SDC ComponentElement: Transform slots scalar values to #plain_text instead of throwing an exception,!4958Issue #3392147: Whitelist IP for a Ban module.,!4942Issue #3365945: Errors: The following table(s) do not have a primary key: forum_index,!4894Issue #3280279: Add API to allow sites to opt in to upload SVG images in CKEditor 5,!4857Issue #3336994: StringFormatter always displays links to entity even if the user in context does not have access,!4856Issue #3336994: StringFormatter always displays links to entity even if the user in context does not have access,!4788Issue #3272985: RSS Feed header reverts to text/html when cached,!4716Issue #3362929: Improve 400 responses for broken/invalid image style routes,!4553Draft: Issue #2980951: Permission to see own unpublished comments in comment thread,!4273Add UUID to sections,!4192Issue #3367204: [CKEditor5] Missing dependency on drupal.ajax,!3679Issue #115801: Allow password on registration without disabling e-mail verification,!3106Issue #3017548: "Filtered HTML" text format does not support manual teaser break (<!--break-->),!3066Issue #3325175: Deprecate calling \Drupal\menu_link_content\Form\MenuLinkContentForm::_construct() with the $language_manager argument,!3004Issue #2463967: Use .user.ini file for PHP settings,!2851Issue #2264739: Allow multiple field widgets to not use tabledrag,!1484Exposed filters get values from URL when Ajax is on,!925Issue #2339235: Remove taxonomy hard dependency on node module,!872Draft: Issue #3221319: Race condition when creating menu links and editing content deletes menu links
......@@ -4,6 +4,7 @@
use Drupal\Core\Database\ConnectionNotDefinedException;
use Drupal\Core\Database\Database;
use Drupal\Core\Database\DatabaseException;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\State\StateInterface;
use Drupal\migrate\Exception\RequirementsException;
......@@ -182,20 +183,10 @@ public function getDatabase() {
* Thrown if no source database connection is configured.
*/
protected function setUpDatabase(array $database_info) {
if (isset($database_info['key'])) {
$key = $database_info['key'];
}
else {
// If there is no explicit database configuration at all, fall back to a
// connection named 'migrate'.
$key = 'migrate';
}
if (isset($database_info['target'])) {
$target = $database_info['target'];
}
else {
$target = 'default';
}
// If there is no explicit database configuration at all, fall back to a
// connection named 'migrate'.
$key = $database_info['key'] ?? 'migrate';
$target = $database_info['target'] ?? 'default';
if (isset($database_info['database'])) {
Database::addConnectionInfo($key, $target, $database_info['database']);
}
......@@ -220,7 +211,12 @@ protected function setUpDatabase(array $database_info) {
*/
public function checkRequirements() {
if ($this->pluginDefinition['requirements_met'] === TRUE) {
$this->getDatabase();
try {
$this->getDatabase();
}
catch (\PDOException | DatabaseException $e) {
throw new RequirementsException("No database connection available for source plugin " . $this->pluginId, [], 0, $e);
}
}
}
......
name: 'Migration missing database test'
type: module
package: Testing
version: VERSION
dependencies:
- drupal:migrate
id: missing_database
label: Migration using a SQL source
source:
plugin: migrate_missing_database_test
process: {}
destination:
plugin: 'null'
migration_dependencies: {}
<?php
namespace Drupal\migrate_missing_database_test\Plugin\migrate\source;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
/**
* A simple migrate source for the missing database tests.
*
* @MigrateSource(
* id = "migrate_missing_database_test",
* source_module = "migrate_missing_database_test",
* requirements_met = true
* )
*/
class MigrateMissingDatabaseSource extends SqlBase {
/**
* {@inheritdoc}
*/
public function query(): SelectInterface {
$field_names = ['id'];
$query = $this
->select('missing_database', 'm')
->fields('m', $field_names);
return $query;
}
/**
* {@inheritdoc}
*/
public function fields(): array {
$fields = [
'id' => $this->t('ID'),
];
return $fields;
}
/**
* {@inheritdoc}
*/
public function getIds(): array {
return [
'id' => [
'type' => 'integer',
],
];
}
}
<?php
namespace Drupal\Tests\migrate\Kernel;
use Drupal\Core\Database\Database;
use Drupal\KernelTests\KernelTestBase;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Plugin\MigrationInterface;
/**
* Tests that a SQL migration can be instantiated without a database connection.
*
* @group migrate
*/
class MigrateMissingDatabaseTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['migrate', 'migrate_missing_database_test'];
/**
* The migration plugin manager.
*
* @var \Drupal\migrate\Plugin\MigrationPluginManager
*/
protected $migrationPluginManager;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->migrationPluginManager = \Drupal::service('plugin.manager.migration');
// Set the 'migrate' database connection to use a missing database.
$info = Database::getConnectionInfo('default')['default'];
$info['database'] = 'godot';
Database::addConnectionInfo('migrate', 'default', $info);
}
/**
* Tests a SQL migration without the database connection.
*
* - The migration can be instantiated.
* - The checkRequirements() method throws a RequirementsException.
*/
public function testMissingDatabase(): void {
$migration = $this->migrationPluginManager->createInstance('missing_database');
$this->assertInstanceOf(MigrationInterface::class, $migration);
$this->assertInstanceOf(MigrateIdMapInterface::class, $migration->getIdMap());
$this->expectException(RequirementsException::class);
$this->expectExceptionMessage('No database connection available for source plugin migrate_missing_database_test');
$migration->checkRequirements();
}
}
......@@ -128,6 +128,27 @@ public function testConnectionTypes() {
$sql_base->getDatabase();
}
/**
* Tests the exception when a connection is defined but not available.
*/
public function testBrokenConnection(): void {
$sql_base = new TestSqlBase([], $this->migration);
$target = 'test_state_db_target2';
$key = 'test_state_migrate_connection2';
$database = Database::getConnectionInfo('default')['default'];
$database['database'] = 'godot';
$config = ['target' => $target, 'key' => $key, 'database' => $database];
$database_state_key = 'migrate_sql_base_test2';
\Drupal::state()->set($database_state_key, $config);
$sql_base->setConfiguration(['database_state_key' => $database_state_key]);
// Call checkRequirements(): it will call getDatabase() and convert the
// exception to a RequirementsException.
$this->expectException(RequirementsException::class);
$this->expectExceptionMessage('No database connection available for source plugin sql_base');
$sql_base->checkRequirements();
}
/**
* Tests that SqlBase respects high-water values.
*
......@@ -201,7 +222,7 @@ class TestSqlBase extends SqlBase {
* (optional) The migration being run.
*/
public function __construct(array $configuration = [], MigrationInterface $migration = NULL) {
parent::__construct($configuration, 'sql_base', [], $migration, \Drupal::state());
parent::__construct($configuration, 'sql_base', ['requirements_met' => TRUE], $migration, \Drupal::state());
}
/**
......
<?php
namespace Drupal\Tests\migrate_drupal\Kernel;
use Drupal\Core\Database\Database;
use Drupal\KernelTests\KernelTestBase;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Plugin\MigrationInterface;
/**
* Tests that a migration can be instantiated without a database connection.
*
* @group migrate_drupal
*/
class MigrateMissingDatabaseTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['migrate', 'migrate_drupal', 'node'];
/**
* The migration plugin manager.
*
* @var \Drupal\migrate\Plugin\MigrationPluginManager
*/
protected $migrationPluginManager;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->migrationPluginManager = \Drupal::service('plugin.manager.migration');
// Set the 'migrate' database connection to use a missing host.
$info = Database::getConnectionInfo('default')['default'];
$info['host'] = 'does_not_exist';
Database::addConnectionInfo('migrate', 'default', $info);
}
/**
* Tests that a migration can be instantiated with the node module enabled.
*
* When the migrate_drupal and node modules are enabled, the migration
* derivers call checkRequirements() whenever createInstance() is used. If the
* database connection is not available, then Migration::setUpDatabase()
* throws an exception. Check that the exception is caught and the migration
* can still be used to access its IdMap.
*/
public function testMissingDatabase(): void {
$migration = $this->migrationPluginManager->createInstance('d7_node_type');
$this->assertInstanceOf(MigrationInterface::class, $migration);
$this->assertInstanceOf(MigrateIdMapInterface::class, $migration->getIdMap());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment