Issue #2548977 by mikeryan, phenaproxima, benjy: How best to persist source database credentials?

8.0.x
webchick 2015-09-30 11:07:07 -07:00
parent eb93c68b27
commit 7fdb772e8d
6 changed files with 111 additions and 23 deletions

View File

@ -8,9 +8,12 @@
namespace Drupal\migrate\Plugin\migrate\source;
use Drupal\Core\Database\Database;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\State\StateInterface;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Plugin\migrate\id_map\Sql;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Sources whose data may be fetched via DBTNG.
@ -21,7 +24,7 @@ use Drupal\migrate\Plugin\MigrateIdMapInterface;
* is present, it is used as a database connection information array to define
* the connection.
*/
abstract class SqlBase extends SourcePluginBase {
abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPluginInterface {
/**
* @var \Drupal\Core\Database\Query\SelectInterface
@ -33,11 +36,32 @@ abstract class SqlBase extends SourcePluginBase {
*/
protected $database;
/**
* State service for retrieving database info.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
$this->state = $state;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$migration,
$container->get('state')
);
}
/**
@ -58,26 +82,51 @@ abstract class SqlBase extends SourcePluginBase {
*/
public function getDatabase() {
if (!isset($this->database)) {
if (isset($this->configuration['target'])) {
$target = $this->configuration['target'];
// See if the database info is in state - if not, fallback to
// configuration.
if (isset($this->configuration['database_state_key'])) {
$this->database = $this->setUpDatabase($this->state->get($this->configuration['database_state_key']));
}
else {
$target = 'default';
$this->database = $this->setUpDatabase($this->configuration);
}
if (isset($this->configuration['key'])) {
$key = $this->configuration['key'];
}
else {
$key = 'migrate';
}
if (isset($this->configuration['database'])) {
Database::addConnectionInfo($key, $target, $this->configuration['database']);
}
$this->database = Database::getConnection($target, $key);
}
return $this->database;
}
/**
* Get a connection to the referenced database, adding the connection if
* necessary.
*
* @param array $database_info
* Configuration for the source database connection. The keys are:
* 'key' - The database connection key.
* 'target' - The database connection target.
* 'database' - Database configuration array as accepted by
* Database::addConnectionInfo.
*
* @return \Drupal\Core\Database\Connection
* The connection to use for this plugin's queries.
*/
protected function setUpDatabase(array $database_info) {
if (isset($database_info['key'])) {
$key = $database_info['key'];
}
else {
$key = 'migrate';
}
if (isset($database_info['target'])) {
$target = $database_info['target'];
}
else {
$target = 'default';
}
if (isset($database_info['database'])) {
Database::addConnectionInfo($key, $target, $database_info['database']);
}
return Database::getConnection($target, $key);
}
/**
* Wrapper for database select.
*/

View File

@ -24,6 +24,7 @@ class SqlBaseTest extends MigrateTestBase {
$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');
@ -52,6 +53,35 @@ class SqlBaseTest extends MigrateTestBase {
// Validate the connection has been created with the right values.
$this->assertIdentical(Database::getConnectionInfo($key)[$target], $database);
// Now, test this all works when using state to store db info.
$target = 'test_state_db_target';
$key = 'test_state_migrate_connection';
$config = ['target' => $target, 'key' => $key];
$database_state_key = 'migrate_sql_base_test';
\Drupal::state()->set($database_state_key, $config);
$sql_base->setConfiguration(['database_state_key' => $database_state_key]);
Database::addConnectionInfo($key, $target, Database::getConnectionInfo('default')['default']);
// Validate we've injected our custom key and target.
$this->assertIdentical($sql_base->getDatabase()->getTarget(), $target);
$this->assertIdentical($sql_base->getDatabase()->getKey(), $key);
// Now test we can have SqlBase create the connection from an info array.
$sql_base = new TestSqlBase();
$target = 'test_state_db_target2';
$key = 'test_state_migrate_connection2';
$database = Database::getConnectionInfo('default')['default'];
$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 getDatabase() to get the connection defined.
$sql_base->getDatabase();
// Validate the connection has been created with the right values.
$this->assertIdentical(Database::getConnectionInfo($key)[$target], $database);
}
}
@ -68,7 +98,9 @@ class TestSqlBase extends SqlBase {
/**
* Override the constructor so we can create one easily.
*/
public function __construct() {}
public function __construct() {
$this->state = \Drupal::state();
}
/**
* Get the database without caching it.

View File

@ -77,6 +77,7 @@ abstract class MigrateSqlSourceTestCase extends MigrateTestCase {
*/
protected function setUp() {
$module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
$state = $this->getMock('Drupal\Core\State\StateInterface');
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
$migration = $this->getMigration();
@ -86,7 +87,7 @@ abstract class MigrateSqlSourceTestCase extends MigrateTestCase {
// Setup the plugin.
$plugin_class = static::PLUGIN_CLASS;
$plugin = new $plugin_class($this->migrationConfiguration['source'], $this->migrationConfiguration['source']['plugin'], array(), $migration, $entity_manager);
$plugin = new $plugin_class($this->migrationConfiguration['source'], $this->migrationConfiguration['source']['plugin'], array(), $migration, $state, $entity_manager);
// Do some reflection to set the database and moduleHandler.
$plugin_reflection = new \ReflectionClass($plugin);

View File

@ -11,6 +11,7 @@ use Drupal\Component\Plugin\DependentPluginInterface;
use Drupal\Core\Entity\DependencyTrait;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\State\StateInterface;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
@ -51,8 +52,8 @@ abstract class DrupalSqlBase extends SqlBase implements ContainerFactoryPluginIn
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityManagerInterface $entity_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityManagerInterface $entity_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state);
$this->entityManager = $entity_manager;
}
@ -89,6 +90,7 @@ abstract class DrupalSqlBase extends SqlBase implements ContainerFactoryPluginIn
$plugin_id,
$plugin_definition,
$migration,
$container->get('state'),
$container->get('entity.manager')
);
}

View File

@ -8,6 +8,7 @@
namespace Drupal\migrate_drupal\Plugin\migrate\source;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\State\StateInterface;
use Drupal\migrate\Entity\MigrationInterface;
/**
@ -32,8 +33,8 @@ class Variable extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityManagerInterface $entity_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $entity_manager);
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityManagerInterface $entity_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_manager);
$this->variables = $this->configuration['variables'];
}

View File

@ -68,8 +68,11 @@ class Drupal6SqlBaseTest extends MigrateTestCase {
*/
protected function setUp() {
$plugin = 'placeholder_id';
$entity_manager = $this->getmock('Drupal\Core\Entity\EntityManagerInterface');
$this->base = new TestDrupal6SqlBase($this->migrationConfiguration, $plugin, array(), $this->getMigration(), $entity_manager);
/** @var \Drupal\Core\State\StateInterface $state */
$state = $this->getMock('Drupal\Core\State\StateInterface');
/** @var \Drupal\Core\Entity\EntityManagerInterface $entity_manager */
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
$this->base = new TestDrupal6SqlBase($this->migrationConfiguration, $plugin, array(), $this->getMigration(), $state, $entity_manager);
$this->base->setDatabase($this->getDatabase($this->databaseContents));
}