diff --git a/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php b/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php index a730266e1d..a1777f6d1c 100644 --- a/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php +++ b/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php @@ -29,11 +29,20 @@ * joined. Using expressions in the query may result in column aliases in the * JOIN clause which would be invalid SQL. If you run into this, set * ignore_map to TRUE. - * - conditions: (optional) Conditons that should be included in the query. This + * - conditions: (optional) Conditions that should be included in the query. This * should be in array format with each array item providing values for field, * value (optional) and operator (optional). Defaults to an empty array. If * value is not defined, defaults to NULL. If operator is not defined, defaults * to '='. + * Example: + * @code + * source: + * conditions: + * - + * field: type + * value: article + * operator: <> + * @endcode * * For other optional configuration keys inherited from the parent class, refer * to \Drupal\migrate\Plugin\migrate\source\SourcePluginBase. @@ -113,6 +122,18 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state) { parent::__construct($configuration, $plugin_id, $plugin_definition, $migration); $this->state = $state; + + // Verify conditions configuration. + if (isset($this->configuration['conditions'])) { + if (!is_array($this->configuration['conditions'])) { + throw new \InvalidArgumentException('Source "conditions" should be an array of conditions including field, value (optional), and operator (optional) values.'); + } + foreach ($this->configuration['conditions'] as $condition) { + if (!is_array($condition) || !isset($condition['field'])) { + throw new \InvalidArgumentException('Source condition must be an array including field, value (optional), and operator (optional) values.'); + } + } + } } /** @@ -460,7 +481,7 @@ protected function mapJoinable() { if ($id_map_database_options['driver'] === 'pgsql' && $source_database_options['driver'] === 'pgsql' && $id_map_database_options['database'] != $source_database_options['database'] - ) { + ) { return FALSE; } diff --git a/core/modules/migrate/tests/src/Unit/SqlBaseTest.php b/core/modules/migrate/tests/src/Unit/SqlBaseTest.php index bc2843e1e2..61433534d2 100644 --- a/core/modules/migrate/tests/src/Unit/SqlBaseTest.php +++ b/core/modules/migrate/tests/src/Unit/SqlBaseTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\migrate\Unit; +use Drupal\Core\State\StateInterface; use Drupal\migrate\Plugin\MigrationInterface; use Drupal\migrate\Plugin\migrate\source\SqlBase; use Drupal\Tests\UnitTestCase; @@ -18,6 +19,82 @@ */ class SqlBaseTest extends UnitTestCase { + /** + * The default configuration array. + * + * @var array + */ + protected $configuration = []; + + /** + * The default plugin_id string. + * + * @var string + */ + protected $pluginId = ''; + + /** + * The default plugin_definition array. + * + * @var array + */ + protected $pluginDefinition = []; + + /** + * Tests that source conditions are recognized. + * + * @param bool $expected_result + * The expected result. + * @param array $conditions + * An array of source conditions. Defaults to an empty array. + * + * @dataProvider sqlBaseConstructorTestProvider + */ + public function testConstructor($expected_result, $conditions = []) { + $configuration = [ + 'conditions' => $conditions, + ]; + // Setup the migration interface. + $migration = $this->getMockBuilder('Drupal\migrate\Plugin\MigrationInterface') + ->disableOriginalConstructor() + ->getMock(); + + // Setup the state object. + $state = $this->getMockBuilder('Drupal\Core\State\State') + ->disableOriginalConstructor() + ->getMock(); + + // Test with an invalid process pipeline. + $this->expectException(\InvalidArgumentException::class); + $sql_base = new TestSqlBase($configuration, $this->pluginId, $this->pluginDefinition, $migration, $state); + } + + /** + * The data provider for testConstructor. + * + * @return array + * An array of data per test run. + */ + public function sqlBaseConstructorTestProvider() { + return [ + // Source conditions is not an array. + [ + TRUE, + '', + ], + // Source conditions is not a multidimensional array. + [ + TRUE, + [''], + ], + // Source conditions condition does not specify 'field'. + [ + TRUE, + [['']], + ], + ]; + } + /** * Tests that the ID map is joinable. * @@ -61,6 +138,11 @@ public function testMapJoinable($expected_result, $id_map_is_sql, $with_id_map, ->method('getDatabase') ->willReturn($idmap_connection); + // Setup the State object. + $state = $this->getMockBuilder('Drupal\Core\State\State') + ->disableOriginalConstructor() + ->getMock(); + // Setup a migration entity. $migration = $this->createMock(MigrationInterface::class); $migration->expects($with_id_map ? $this->once() : $this->never()) @@ -68,7 +150,7 @@ public function testMapJoinable($expected_result, $id_map_is_sql, $with_id_map, ->willReturn($id_map_is_sql ? $sql : NULL); // Create our SqlBase test class. - $sql_base = new TestSqlBase(); + $sql_base = new TestSqlBase($this->configuration, $this->pluginId, $this->pluginDefinition, $migration, $state); $sql_base->setMigration($migration); $sql_base->setDatabase($source_connection); @@ -162,9 +244,12 @@ class TestSqlBase extends SqlBase { protected $ids; /** - * Override the constructor so we can create one easily. + * {@inheritdoc} */ - public function __construct() {} + public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state) { + parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state); + return TRUE; + } /** * Allows us to set the database during tests.