Commit 68d8cd26 authored by Gábor Hojtsy's avatar Gábor Hojtsy

Issue #2830031 by mikeryan, heddn, phenaproxima: Fix SqlBase fallback priorities and document them

parent 8a6aad98
......@@ -15,13 +15,37 @@
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Sources whose data may be fetched via DBTNG.
* Sources whose data may be fetched via a database connection.
*
* By default, an existing database connection with key 'migrate' and target
* 'default' is used. These may be overridden with explicit 'key' and/or
* 'target' configuration keys. In addition, if the configuration key 'database'
* is present, it is used as a database connection information array to define
* the connection.
* Database configuration, which may appear either within the source plugin
* configuration or in state, is structured as follows:
*
* 'key' - The database key name (defaults to 'migrate').
* 'target' - The database target name (defaults to 'default').
* 'database' - Database connection information as accepted by
* Database::addConnectionInfo(). If not present, the key/target is assumed
* to already be defined (e.g., in settings.php).
*
* This configuration info is obtained in the following order:
*
* 1. If the source plugin configuration contains a key 'database_state_key',
* its value is taken as the name of a state key which contains an array
* with the above database configuration.
* 2. Otherwise, if the source plugin configuration contains 'key', the above
* database configuration is obtained directly from the plugin configuration.
* 3. Otherwise, if the state 'migrate.fallback_state_key' exists, its value is
* taken as the name of a state key which contains an array with the above
* database configuration.
* 4. Otherwise, if a connection named 'migrate' exists, that is used as the
* database connection.
* 5. Otherwise, RequirementsException is thrown.
*
* It is strongly recommended that database connections be explicitly defined
* via 'database_state_key' or in the source plugin configuration. Defining
* migrate.fallback_state_key or a 'migrate' connection affects not only any
* migrations intended to use that particular connection, but all
* SqlBase-derived source plugins which do not have explicit database
* configuration.
*/
abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPluginInterface, RequirementsInterface {
......@@ -101,16 +125,21 @@ public function __toString() {
*/
public function getDatabase() {
if (!isset($this->database)) {
// See if the database info is in state - if not, fallback to
// configuration.
// Look first for an explicit state key containing the configuration.
if (isset($this->configuration['database_state_key'])) {
$this->database = $this->setUpDatabase($this->state->get($this->configuration['database_state_key']));
}
// Next, use explicit configuration in the source plugin.
elseif (isset($this->configuration['key'])) {
$this->database = $this->setUpDatabase($this->configuration);
}
// Next, try falling back to the global state key.
elseif (($fallback_state_key = $this->state->get('migrate.fallback_state_key'))) {
$this->database = $this->setUpDatabase($this->state->get($fallback_state_key));
}
// If all else fails, let setUpDatabase() fallback to the 'migrate' key.
else {
$this->database = $this->setUpDatabase($this->configuration);
$this->database = $this->setUpDatabase([]);
}
}
return $this->database;
......
......@@ -7,6 +7,7 @@
namespace Drupal\Tests\migrate\Kernel;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\Plugin\migrate\source\TestSqlBase;
use Drupal\Core\Database\Database;
......@@ -23,11 +24,24 @@ class SqlBaseTest extends MigrateTestBase {
public function testConnectionTypes() {
$sql_base = new TestSqlBase();
// Check the default values.
$sql_base->setConfiguration([]);
$this->assertIdentical($sql_base->getDatabase()->getTarget(), 'default');
$this->assertIdentical($sql_base->getDatabase()->getKey(), 'migrate');
// Verify that falling back to the default 'migrate' connection (defined in
// the base class) works.
$this->assertSame($sql_base->getDatabase()->getTarget(), 'default');
$this->assertSame($sql_base->getDatabase()->getKey(), 'migrate');
// Verify the fallback state key overrides the 'migrate' connection.
$target = 'test_fallback_target';
$key = 'test_fallback_key';
$config = ['target' => $target, 'key' => $key];
$database_state_key = 'test_fallback_state';
\Drupal::state()->set($database_state_key, $config);
\Drupal::state()->set('migrate.fallback_state_key', $database_state_key);
// Create a test connection using the default database configuration.
Database::addConnectionInfo($key, $target, Database::getConnectionInfo('default')['default']);
$this->assertSame($sql_base->getDatabase()->getTarget(), $target);
$this->assertSame($sql_base->getDatabase()->getKey(), $key);
// Verify that setting explicit connection information overrides fallbacks.
$target = 'test_db_target';
$key = 'test_migrate_connection';
$config = ['target' => $target, 'key' => $key];
......@@ -35,8 +49,8 @@ public function testConnectionTypes() {
Database::addConnectionInfo($key, $target, Database::getConnectionInfo('default')['default']);
// Validate we have injected our custom key and target.
$this->assertIdentical($sql_base->getDatabase()->getTarget(), $target);
$this->assertIdentical($sql_base->getDatabase()->getKey(), $key);
$this->assertSame($sql_base->getDatabase()->getTarget(), $target);
$this->assertSame($sql_base->getDatabase()->getKey(), $key);
// Now test we can have SqlBase create the connection from an info array.
$sql_base = new TestSqlBase();
......@@ -51,7 +65,7 @@ public function testConnectionTypes() {
$sql_base->getDatabase();
// Validate the connection has been created with the right values.
$this->assertIdentical(Database::getConnectionInfo($key)[$target], $database);
$this->assertSame(Database::getConnectionInfo($key)[$target], $database);
// Now, test this all works when using state to store db info.
$target = 'test_state_db_target';
......@@ -63,8 +77,8 @@ public function testConnectionTypes() {
Database::addConnectionInfo($key, $target, Database::getConnectionInfo('default')['default']);
// Validate we have injected our custom key and target.
$this->assertIdentical($sql_base->getDatabase()->getTarget(), $target);
$this->assertIdentical($sql_base->getDatabase()->getKey(), $key);
$this->assertSame($sql_base->getDatabase()->getTarget(), $target);
$this->assertSame($sql_base->getDatabase()->getKey(), $key);
// Now test we can have SqlBase create the connection from an info array.
$sql_base = new TestSqlBase();
......@@ -81,7 +95,16 @@ public function testConnectionTypes() {
$sql_base->getDatabase();
// Validate the connection has been created with the right values.
$this->assertIdentical(Database::getConnectionInfo($key)[$target], $database);
$this->assertSame(Database::getConnectionInfo($key)[$target], $database);
// Verify that falling back to 'migrate' when the connection is not defined
// throws a RequirementsException.
\Drupal::state()->delete('migrate.fallback_state_key');
$sql_base->setConfiguration([]);
Database::renameConnection('migrate', 'fallback_connection');
$this->setExpectedException(RequirementsException::class,
'No database connection configured for source plugin');
$sql_base->getDatabase();
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment