Commit a9f1973c authored by alexpott's avatar alexpott

Issue #2999906 by mikelutz, heddn, phenaproxima, alexpott: Move logic from the...

Issue #2999906 by mikelutz, heddn, phenaproxima, alexpott: Move logic from the get plugin into the Row class
parent d654e103
......@@ -109,23 +109,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
$return = [];
foreach ($properties as $property) {
if ($property || (string) $property === '0') {
$is_source = TRUE;
if ($property[0] == '@') {
$property = preg_replace_callback('/^(@?)((?:@@)*)([^@]|$)/', function ($matches) use (&$is_source) {
// If there are an odd number of @ in the beginning, it's a
// destination.
$is_source = empty($matches[1]);
// Remove the possible escaping and do not lose the terminating
// non-@ either.
return str_replace('@@', '@', $matches[2]) . $matches[3];
}, $property);
}
if ($is_source) {
$return[] = $row->getSourceProperty($property);
}
else {
$return[] = $row->getDestinationProperty($property);
}
$return[] = $row->get($property);
}
else {
$return[] = $value;
......
......@@ -4,7 +4,6 @@
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\MigrateSkipProcessException;
use Drupal\migrate\Plugin\MigratePluginManagerInterface;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\ProcessPluginBase;
......@@ -101,13 +100,6 @@
*/
class MigrationLookup extends ProcessPluginBase implements ContainerFactoryPluginInterface {
/**
* The process plugin manager.
*
* @var \Drupal\migrate\Plugin\MigratePluginManager
*/
protected $processPluginManager;
/**
* The migration plugin manager.
*
......@@ -123,13 +115,23 @@ class MigrationLookup extends ProcessPluginBase implements ContainerFactoryPlugi
protected $migration;
/**
* {@inheritdoc}
* Constructs a MigrationLookup object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The Migration the plugin is being used in.
* @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager
* The Migration Plugin Manager Interface.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrationPluginManagerInterface $migration_plugin_manager, MigratePluginManagerInterface $process_plugin_manager) {
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrationPluginManagerInterface $migration_plugin_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->migrationPluginManager = $migration_plugin_manager;
$this->migration = $migration;
$this->processPluginManager = $process_plugin_manager;
}
/**
......@@ -141,8 +143,7 @@ public static function create(ContainerInterface $container, array $configuratio
$plugin_id,
$plugin_definition,
$migration,
$container->get('plugin.manager.migration'),
$container->get('plugin.manager.migrate.process')
$container->get('plugin.manager.migration')
);
}
......@@ -166,10 +167,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
$self = TRUE;
}
if (isset($this->configuration['source_ids'][$lookup_migration_id])) {
$configuration = ['source' => $this->configuration['source_ids'][$lookup_migration_id]];
$value = $this->processPluginManager
->createInstance('get', $configuration, $this->migration)
->transform(NULL, $migrate_executable, $row, $destination_property);
$value = array_values($row->getMultiple($this->configuration['source_ids'][$lookup_migration_id]));
}
if (!is_array($value)) {
$value = [$value];
......
......@@ -136,6 +136,13 @@ public function hasSourceProperty($property) {
/**
* Retrieves a source property.
*
* This function directly retrieves a source property. It does not unescape
* '@' symbols. This is most useful in source plugins when you don't want to
* worry about escaping '@' symbols. If using this in a process plugin to
* retrieve a source property based on a configuration value, consider if the
* ::get() function might be more appropriate, to allow the migration to
* potentially specify a destination key as well.
*
* @param string $property
* A property on the source.
*
......@@ -285,6 +292,10 @@ public function getRawDestination() {
/**
* Returns the value of a destination property.
*
* This function directly returns a destination property. The property name
* should not begin with an @ symbol. This is most useful in a destination
* plugin.
*
* @param string $property
* The name of a property on the destination.
*
......@@ -295,6 +306,60 @@ public function getDestinationProperty($property) {
return NestedArray::getValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
}
/**
* Retrieve a source or destination property.
*
* If the property key begins with '@' return a destination property,
* otherwise return a source property. the '@' symbol itself can be escaped
* as '@@'. Returns NULL if property is not found. Useful in process plugins
* to retrieve a row property specified in a configuration key which may be
* either a source or destination property prefixed with an '@'.
*
* @param string $property
* The property to get.
*
* @return mixed|null
* The requested property.
*/
public function get($property) {
$values = $this->getMultiple([$property]);
return reset($values);
}
/**
* Retrieve multiple source and destination properties at once.
*
* @param string[] $properties
* An array of values to retrieve, with destination values prefixed with @.
*
* @return array
* An array of property values, keyed by property name.
*/
public function getMultiple(array $properties) {
$return = [];
foreach ($properties as $orig_property) {
$property = $orig_property;
$is_source = TRUE;
if ($property[0] == '@') {
$property = preg_replace_callback('/^(@?)((?:@@)*)([^@]|$)/', function ($matches) use (&$is_source) {
// If there are an odd number of @ in the beginning, it's a
// destination.
$is_source = empty($matches[1]);
// Remove the possible escaping and do not lose the terminating
// non-@ either.
return str_replace('@@', '@', $matches[2]) . $matches[3];
}, $property);
}
if ($is_source) {
$return[$orig_property] = $this->getSourceProperty($property);
}
else {
$return[$orig_property] = $this->getDestinationProperty($property);
}
}
return $return;
}
/**
* Sets the Migrate ID mappings.
*
......
......@@ -31,6 +31,43 @@ class RowTest extends UnitTestCase {
'title' => 'node 1',
];
/**
* Test source properties for testing get and getMultiple.
*
* @var array
*/
protected $testGetSourceProperties = [
'source_key_1' => 'source_value_1',
'source_key_2' => 'source_value_2',
'@source_key_3' => 'source_value_3',
'shared_key_1' => 'source_shared_value_1',
'@shared_key_2' => 'source_shared_value_2',
'@@@@shared_key_3' => 'source_shared_value_3',
];
/**
* Test source keys for testing get and getMultiple.
*
* @var array
*/
protected $testGetSourceIds = [
'source_key_1' => [],
];
/**
* Test destination properties for testing get and getMultiple.
*
* @var array
*/
protected $testGetDestinationProperties = [
'destination_key_1' => 'destination_value_1',
'destination_key_2' => 'destination_value_2',
'@destination_key_3' => 'destination_value_3',
'shared_key_1' => 'destination_shared_value_1',
'@shared_key_2' => 'destination_shared_value_2',
'@@@@shared_key_3' => 'destination_shared_value_3',
];
/**
* The test hash.
*
......@@ -271,4 +308,146 @@ public function testMultipleDestination() {
$this->assertEquals(3, $row->getDestinationProperty('image/fid'));
}
/**
* Test getting source and destination properties.
*
* @param string $key
* The key to look up.
* @param string $expected_value
* The expected value.
*
* @dataProvider getDataProvider
* @covers ::get
*/
public function testGet($key, $expected_value) {
$row = $this->createRowWithDestinationProperties($this->testGetSourceProperties, $this->testGetSourceIds, $this->testGetDestinationProperties);
$this->assertSame($expected_value, $row->get($key));
}
/**
* Data Provider for testGet.
*
* @return array
* The keys and expected values.
*/
public function getDataProvider() {
return [
['source_key_1', 'source_value_1'],
['source_key_2', 'source_value_2'],
['@@source_key_3', 'source_value_3'],
['shared_key_1', 'source_shared_value_1'],
['@@shared_key_2', 'source_shared_value_2'],
['@@@@@@@@shared_key_3', 'source_shared_value_3'],
['@destination_key_1', 'destination_value_1'],
['@destination_key_2', 'destination_value_2'],
['@@@destination_key_3', 'destination_value_3'],
['@shared_key_1', 'destination_shared_value_1'],
['@@@shared_key_2', 'destination_shared_value_2'],
['@@@@@@@@@shared_key_3', 'destination_shared_value_3'],
['destination_key_1', NULL],
['@shared_key_2', NULL],
['@source_key_1', NULL],
['random_source_key', NULL],
['@random_destination_key', NULL],
];
}
/**
* Test getting multiple source and destination properties.
*
* @param array $keys
* An array of keys to look up.
* @param array $expected_values
* An array of expected values.
*
* @covers::getMultiple
* @dataProvider getMultipleDataProvider
*/
public function testGetMultiple(array $keys, array $expected_values) {
$row = $this->createRowWithDestinationProperties($this->testGetSourceProperties, $this->testGetSourceIds, $this->testGetDestinationProperties);
$this->assertArrayEquals(array_combine($keys, $expected_values), $row->getMultiple($keys));
}
/**
* Data Provider for testGetMultiple.
*
* @return array
* The keys and expected values.
*/
public function getMultipleDataProvider() {
return [
'Single Key' => [
'keys' => ['source_key_1'],
'values' => ['source_value_1'],
],
'All Source Keys' => [
'keys' => [
'source_key_1',
'source_key_2',
'@@source_key_3',
],
'values' => [
'source_value_1',
'source_value_2',
'source_value_3',
],
],
'All Destination Keys' => [
'keys' => [
'@destination_key_1',
'@destination_key_2',
'@@@destination_key_3',
],
'values' => [
'destination_value_1',
'destination_value_2',
'destination_value_3',
],
],
'Mix of keys including non-existant' => [
'keys' => [
'shared_key_1',
'@shared_key_1',
'@@shared_key_2',
'@@@shared_key_2',
'@@@@@@@@@shared_key_3',
'non_existant_source_key',
'@non_existant_destination_key',
],
'values' => [
'source_shared_value_1',
'destination_shared_value_1',
'source_shared_value_2',
'destination_shared_value_2',
'destination_shared_value_3',
NULL,
NULL,
],
],
];
}
/**
* Create a row and load it with destination properties.
*
* @param array $source_properties
* The source property array.
* @param array $source_ids
* The source ids array.
* @param array $destination_properties
* The destination properties to load.
* @param bool $is_stub
* Whether this row is a stub row, defaults to FALSE.
*
* @return \Drupal\migrate\Row
* The row, populated with destination properties.
*/
protected function createRowWithDestinationProperties(array $source_properties, array $source_ids, array $destination_properties, $is_stub = FALSE) {
$row = new Row($source_properties, $source_ids, $is_stub);
foreach ($destination_properties as $key => $property) {
$row->setDestinationProperty($key, $property);
}
return $row;
}
}
......@@ -16,7 +16,7 @@ class GetTest extends MigrateProcessTestCase {
*/
public function testTransformSourceString() {
$this->row->expects($this->once())
->method('getSourceProperty')
->method('get')
->with('test')
->will($this->returnValue('source_value'));
$this->plugin = new Get(['source' => 'test'], '', []);
......@@ -34,7 +34,7 @@ public function testTransformSourceArray() {
];
$this->plugin = new Get(['source' => ['test1', 'test2']], '', []);
$this->row->expects($this->exactly(2))
->method('getSourceProperty')
->method('get')
->will($this->returnCallback(function ($argument) use ($map) {
return $map[$argument];
}));
......@@ -47,8 +47,8 @@ public function testTransformSourceArray() {
*/
public function testTransformSourceStringAt() {
$this->row->expects($this->once())
->method('getSourceProperty')
->with('@test')
->method('get')
->with('@@test')
->will($this->returnValue('source_value'));
$this->plugin = new Get(['source' => '@@test'], '', []);
$value = $this->plugin->transform(NULL, $this->migrateExecutable, $this->row, 'destinationproperty');
......@@ -61,13 +61,13 @@ public function testTransformSourceStringAt() {
public function testTransformSourceArrayAt() {
$map = [
'test1' => 'source_value1',
'@test2' => 'source_value2',
'@test3' => 'source_value3',
'@@test2' => 'source_value2',
'@@test3' => 'source_value3',
'test4' => 'source_value4',
];
$this->plugin = new Get(['source' => ['test1', '@@test2', '@@test3', 'test4']], '', []);
$this->row->expects($this->exactly(4))
->method('getSourceProperty')
->method('get')
->will($this->returnCallback(function ($argument) use ($map) {
return $map[$argument];
}));
......@@ -82,7 +82,7 @@ public function testTransformSourceArrayAt() {
*/
public function testIntegerValues($source, $expected_value) {
$this->row->expects($this->atMost(2))
->method('getSourceProperty')
->method('get')
->willReturnOnConsecutiveCalls('val1', 'val2');
$this->plugin = new Get(['source' => $source], '', []);
......
......@@ -4,12 +4,10 @@
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\migrate\MigrateSkipProcessException;
use Drupal\migrate\Plugin\migrate\process\Get;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Plugin\migrate\process\MigrationLookup;
use Drupal\migrate\Plugin\MigrateDestinationInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Plugin\MigratePluginManager;
use Drupal\migrate\Plugin\MigrateSourceInterface;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\migrate\Row;
......@@ -27,7 +25,6 @@ class MigrationLookupTest extends MigrateProcessTestCase {
public function testTransformWithStubSkipping() {
$migration_plugin = $this->prophesize(MigrationInterface::class);
$migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
$process_plugin_manager = $this->prophesize(MigratePluginManager::class);
$destination_id_map = $this->prophesize(MigrateIdMapInterface::class);
$destination_migration = $this->prophesize(MigrationInterface::class);
......@@ -46,7 +43,7 @@ public function testTransformWithStubSkipping() {
$migration_plugin->id()->willReturn('actual_migration');
$destination_migration->getDestinationPlugin(TRUE)->shouldNotBeCalled();
$migration = new MigrationLookup($configuration, '', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
$migration = new MigrationLookup($configuration, '', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal());
$result = $migration->transform(1, $this->migrateExecutable, $this->row, '');
$this->assertNull($result);
}
......@@ -57,7 +54,6 @@ public function testTransformWithStubSkipping() {
public function testTransformWithStubbing() {
$migration_plugin = $this->prophesize(MigrationInterface::class);
$migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
$process_plugin_manager = $this->prophesize(MigratePluginManager::class);
$destination_id_map = $this->prophesize(MigrateIdMapInterface::class);
$destination_migration = $this->prophesize('Drupal\migrate\Plugin\Migration');
......@@ -85,7 +81,7 @@ public function testTransformWithStubbing() {
$destination_plugin->import(Argument::any())->willReturn([2]);
$destination_migration->getDestinationPlugin(TRUE)->willReturn($destination_plugin->reveal());
$migration = new MigrationLookup($configuration, '', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
$migration = new MigrationLookup($configuration, '', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal());
$result = $migration->transform(1, $this->migrateExecutable, $this->row, '');
$this->assertEquals(2, $result);
}
......@@ -96,7 +92,6 @@ public function testTransformWithStubbing() {
public function testSkipOnEmpty() {
$migration_plugin = $this->prophesize(MigrationInterface::class);
$migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
$process_plugin_manager = $this->prophesize(MigratePluginManager::class);
$configuration = [
'migration' => 'foobaz',
......@@ -104,7 +99,7 @@ public function testSkipOnEmpty() {
$migration_plugin->id()->willReturn(uniqid());
$migration_plugin_manager->createInstances(['foobaz'])
->willReturn(['foobaz' => $migration_plugin->reveal()]);
$migration = new MigrationLookup($configuration, 'migration_lookup', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
$migration = new MigrationLookup($configuration, 'migration_lookup', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal());
$this->setExpectedException(MigrateSkipProcessException::class);
$migration->transform(0, $this->migrateExecutable, $this->row, 'foo');
}
......@@ -126,7 +121,6 @@ public function testSkipOnEmpty() {
public function testSuccessfulLookup($source_id_values, $destination_id_values, $source_value, $expected_value) {
$migration_plugin = $this->prophesize(MigrationInterface::class);
$migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
$process_plugin_manager = $this->prophesize(MigratePluginManager::class);
$configuration = [
'migration' => 'foobaz',
......@@ -145,7 +139,7 @@ public function testSuccessfulLookup($source_id_values, $destination_id_values,
->loadMultiple(['foobaz'])
->willReturn([$migration_plugin->reveal()]);
$migration = new MigrationLookup($configuration, 'migration_lookup', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
$migration = new MigrationLookup($configuration, 'migration_lookup', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal());
$this->assertSame($expected_value, $migration->transform($source_value, $this->migrateExecutable, $this->row, 'foo'));
}
......@@ -209,7 +203,6 @@ public function successfulLookupDataProvider() {
public function testImportException() {
$migration_plugin = $this->prophesize(MigrationInterface::class);
$migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
$process_plugin_manager = $this->prophesize(MigratePluginManager::class);
$destination_id_map = $this->prophesize(MigrateIdMapInterface::class);
$destination_migration = $this->prophesize('Drupal\migrate\Plugin\Migration');
......@@ -238,7 +231,7 @@ public function testImportException() {
$destination_plugin->import(Argument::any())->willThrow($e);
$destination_migration->getDestinationPlugin(TRUE)->willReturn($destination_plugin->reveal());
$migration = new MigrationLookup($configuration, '', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
$migration = new MigrationLookup($configuration, '', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal());
$migration->transform(1, $this->migrateExecutable, $this->row, '');
}
......@@ -248,9 +241,8 @@ public function testImportException() {
public function testMultipleSourceIds() {
$migration_plugin = $this->prophesize(MigrationInterface::class);
$migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
$process_plugin_manager = $this->prophesize(MigratePluginManager::class);
$foobaz_migration = $this->prophesize(MigrationInterface::class);
$get_migration = $this->prophesize(Get::class);
$id_map = $this->prophesize(MigrateIdMapInterface::class);
$destination_plugin = $this->prophesize(MigrateDestinationInterface::class);
$source_plugin = $this->prophesize(MigrateSourceInterface::class);
......@@ -258,9 +250,6 @@ public function testMultipleSourceIds() {
$migration_plugin_manager->createInstances(['foobaz'])
->willReturn(['foobaz' => $foobaz_migration->reveal()]);
$process_plugin_manager->createInstance('get', ['source' => ['string_id', 'integer_id']], $migration_plugin->reveal())
->willReturn($get_migration->reveal());
$foobaz_migration->getIdMap()->willReturn($id_map->reveal());
$foobaz_migration->getDestinationPlugin(TRUE)->willReturn($destination_plugin->reveal());
$foobaz_migration->getProcess()->willReturn([]);
......@@ -268,9 +257,6 @@ public function testMultipleSourceIds() {
$foobaz_migration->id()->willReturn('foobaz');
$foobaz_migration->getSourceConfiguration()->willReturn([]);
$get_migration->transform(NULL, $this->migrateExecutable, $this->row, 'foo')
->willReturn(['example_string', 99]);
$source_plugin_ids = [
'string_id' => [
'type' => 'string',
......@@ -294,8 +280,8 @@ public function testMultipleSourceIds() {
'migration' => 'foobaz',
'source_ids' => ['foobaz' => ['string_id', 'integer_id']],
];
$migration = new MigrationLookup($configuration, 'migration', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
$result = $migration->transform(NULL, $this->migrateExecutable, $this->row, 'foo');
$migration = new MigrationLookup($configuration, 'migration', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal());
$result = $migration->transform(NULL, $this->migrateExecutable, $stub_row, 'foo');
$this->assertEquals(2, $result);
}
......
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