Issue #2845483 by heddn, holingpoon, Jo Fitzgerald, quietone, phenaproxima, claudiu.cristea: Rename Iterator process plugin and add documentation

8.4.x
Gabor Hojtsy 2017-05-25 18:20:19 +02:00
parent 3c7a7782e6
commit 8a6aad980d
8 changed files with 262 additions and 57 deletions

View File

@ -9,7 +9,7 @@ process:
vid: vid
type: type
upload:
plugin: iterator
plugin: sub_process
source: upload
process:
target_id:

View File

@ -11,7 +11,7 @@ process:
name: name
cache: cache
filters:
plugin: iterator
plugin: sub_process
source: filters
key: '@id'
process:

View File

@ -10,7 +10,7 @@ process:
cache: cache
weight: weight
filters:
plugin: iterator
plugin: sub_process
source: filters
key: '@id'
process:

View File

@ -8,7 +8,7 @@ process:
name: name
label: label
effects:
plugin: iterator
plugin: sub_process
source: effects
process:
id: name

View File

@ -2,65 +2,20 @@
namespace Drupal\migrate\Plugin\migrate\process;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
@trigger_error('The ' . __NAMESPACE__ . '\Iterator is deprecated in
Drupal 8.4.x and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPACE__ . '\SubProcess', E_USER_DEPRECATED);
/**
* This plugin iterates and processes an array.
* Iterates and processes an associative array.
*
* @link https://www.drupal.org/node/2135345 Online handbook documentation for iterator process plugin @endlink
* @deprecated in Drupal 8.4.x and will be removed in Drupal 9.0.x. Use
* \Drupal\migrate\Plugin\migrate\process\SubProcess instead.
*
* @see https://www.drupal.org/node/2880427
*
* @MigrateProcessPlugin(
* id = "iterator",
* handle_multiples = TRUE
* )
*/
class Iterator extends ProcessPluginBase {
/**
* Runs a process pipeline on each destination property per list item.
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$return = [];
if (!is_null($value)) {
foreach ($value as $key => $new_value) {
$new_row = new Row($new_value, []);
$migrate_executable->processRow($new_row, $this->configuration['process']);
$destination = $new_row->getDestination();
if (array_key_exists('key', $this->configuration)) {
$key = $this->transformKey($key, $migrate_executable, $new_row);
}
$return[$key] = $destination;
}
}
return $return;
}
/**
* Runs the process pipeline for the current key.
*
* @param string|int $key
* The current key.
* @param \Drupal\migrate\MigrateExecutableInterface $migrate_executable
* The migrate executable helper class.
* @param \Drupal\migrate\Row $row
* The current row after processing.
*
* @return mixed
* The transformed key.
*/
protected function transformKey($key, MigrateExecutableInterface $migrate_executable, Row $row) {
$process = ['key' => $this->configuration['key']];
$migrate_executable->processRow($row, $process, $key);
return $row->getDestinationProperty('key');
}
/**
* {@inheritdoc}
*/
public function multiple() {
return TRUE;
}
}
class Iterator extends SubProcess {}

View File

@ -0,0 +1,166 @@
<?php
namespace Drupal\migrate\Plugin\migrate\process;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
/**
* Runs an array of arrays through its own process pipeline.
*
* The sub_process plugin accepts an array of associative arrays and runs each
* one through its own process pipeline, producing a newly keyed associative
* array of transformed values.
*
* Available configuration keys:
* - process: the plugin(s) that will process each element of the source.
* - key: runs the process pipeline for the key to determine a new dynamic
* name.
*
* Examples:
*
* @code
* source: Array
* (
* [upload] => Array
* (
* [0] => Array
* (
* [fid] => 1
* [list] => 0
* [description] => "File number 1"
* )
* [1] => Array
* (
* [fid] => 2
* [list] => 1
* [description] => "File number 2"
* )
* )
* )
* ...
* @endcode
*
* The sub_process process plugin will take these arrays one at a time and run
* its own process over each one:
*
* @code
* process:
* upload:
* plugin: sub_process
* source: upload
* process:
* target_id:
* plugin: migration_lookup
* migration: d6_file
* source: fid
* display: list
* description: description
* @endcode
*
* In this case, each item in the upload array will be processed by the
* sub_process process plugin. The target_id will be found by looking up the
* destination value from a previous migration. The display and description
* fields will simply be mapped.
*
* In the next example, normally the array returned from sub_process will have
* its original keys. If you need to change the key, it is possible for the
* returned array to be keyed by one of the transformed values in the sub-array.
*
* @code
* source: Array
* (
* [format] => 1
* [name] => Filtered HTML
* ...
* [filters] => Array
* (
* [0] => Array
* (
* [module] => filter
* [delta] => 2
* [weight] => 0
* )
* [1] => Array
* (
* [module] => filter
* [delta] => 0
* [weight] => 1
* )
* )
* )
* ...
*
* process:
* filters:
* plugin: iterator
* source: filters
* key: "@id"
* process:
* id:
* plugin: concat
* source:
* - module
* - delta
* delimiter: _
* @endcode
*
* In the above example, the keys of the returned array would be filter_2 and
* filter_0
*
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
*
* @MigrateProcessPlugin(
* id = "sub_process",
* handle_multiples = TRUE
* )
*/
class SubProcess extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$return = [];
if (is_array($value) || $value instanceof \Traversable) {
foreach ($value as $key => $new_value) {
$new_row = new Row($new_value, []);
$migrate_executable->processRow($new_row, $this->configuration['process']);
$destination = $new_row->getDestination();
if (array_key_exists('key', $this->configuration)) {
$key = $this->transformKey($key, $migrate_executable, $new_row);
}
$return[$key] = $destination;
}
}
return $return;
}
/**
* Runs the process pipeline for the key to determine its dynamic name.
*
* @param string|int $key
* The current key.
* @param \Drupal\migrate\MigrateExecutableInterface $migrate_executable
* The migrate executable helper class.
* @param \Drupal\migrate\Row $row
* The current row after processing.
*
* @return mixed
* The transformed key.
*/
protected function transformKey($key, MigrateExecutableInterface $migrate_executable, Row $row) {
$process = ['key' => $this->configuration['key']];
$migrate_executable->processRow($row, $process, $key);
return $row->getDestinationProperty('key');
}
/**
* {@inheritdoc}
*/
public function multiple() {
return TRUE;
}
}

View File

@ -31,6 +31,8 @@ class IteratorTest extends MigrateTestCase {
/**
* Tests the iterator process plugin.
*
* @group legacy
*/
public function testIterator() {
$migration = $this->getMigration();

View File

@ -0,0 +1,82 @@
<?php
namespace Drupal\Tests\migrate\Unit\process;
use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\Plugin\migrate\process\Get;
use Drupal\migrate\Plugin\migrate\process\SubProcess;
use Drupal\migrate\Row;
use Drupal\Tests\migrate\Unit\MigrateTestCase;
/**
* Tests the sub_process process plugin.
*
* @group migrate
*/
class SubProcessTest extends MigrateTestCase {
/**
* The sub_process plugin being tested.
*
* @var \Drupal\migrate\Plugin\migrate\process\SubProcess
*/
protected $plugin;
/**
* @var array
*/
protected $migrationConfiguration = [
'id' => 'test',
];
/**
* Tests the sub_process process plugin.
*/
public function testSubProcess() {
$migration = $this->getMigration();
// Set up the properties for the sub_process.
$configuration = [
'process' => [
'foo' => 'source_foo',
'id' => 'source_id',
],
'key' => '@id',
];
$plugin = new SubProcess($configuration, 'sub_process', []);
// Manually create the plugins. Migration::getProcessPlugins does this
// normally but the plugin system is not available.
foreach ($configuration['process'] as $destination => $source) {
$sub_process_plugins[$destination][] = new Get(['source' => $source], 'get', []);
}
$migration->expects($this->at(1))
->method('getProcessPlugins')
->willReturn($sub_process_plugins);
// Set up the key plugins.
$key_plugin['key'][] = new Get(['source' => '@id'], 'get', []);
$migration->expects($this->at(2))
->method('getProcessPlugins')
->will($this->returnValue($key_plugin));
$event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$migrate_executable = new MigrateExecutable($migration, $this->getMock('Drupal\migrate\MigrateMessageInterface'), $event_dispatcher);
// The current value of the pipeline.
$current_value = [
[
'source_foo' => 'test',
'source_id' => 42,
],
];
// This is not used but the interface requires it, so create an empty row.
$row = new Row();
// After transformation, check to make sure that source_foo and source_id's
// values ended up in the proper destinations, and that the value of the
// key (@id) is the same as the destination ID (42).
$new_value = $plugin->transform($current_value, $migrate_executable, $row, 'test');
$this->assertSame(count($new_value), 1);
$this->assertSame(count($new_value[42]), 2);
$this->assertSame($new_value[42]['foo'], 'test');
$this->assertSame($new_value[42]['id'], 42);
}
}