Commit 02102dae authored by danflanagan8's avatar danflanagan8 Committed by Lucas Hedding
Browse files

Add Gate process plugin.

parent ff73f34c
<?php
namespace Drupal\migrate_plus\Plugin\migrate\process;
use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\MigrateSkipProcessException;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
/**
* Allow a source value to pass through the gate conditionally.
*
* Imagine the source value as wanting to get through the gate.
* We provide a different source/destination field that acts as the key.
* We compare to a set of valid keys. We declare whether the key locks
* the gate or unlocks the gate.
*
* This is different from skip_on_value because in that plugin, the source
* is compared to a value. In this plugin, the source is not compared to
* anything. The source just wants to get through a gate that is operated
* by another source/destination field.
*
* Unlike skip_on_value, there is no configurable method. The method is
* essentially restricted to 'process'.
*
* The source is not modified if it passes through the gate.
*
* @MigrateProcessPlugin(
* id = "gate"
* )
*
* Available configuration keys:
* - use_as_key: source or destination field to be used as the key to the gate.
* - valid_keys: Value or array of values that are valid keys.
* - key_direction: lock or unlock.
*
* @codingStandardsIgnoreStart
*
* Examples:
*
* Migrate an email address if an opt_in field is set.
* @code
* field_email:
* plugin: gate
* source: email
* use_as_key: opt_in
* valid_keys: TRUE
* key_direction: unlock
* @endcode
*
* Colorado requires salary_range data to be displayed. Only migrate
* salary_range if state is CO. Maybe the data is sloppy and sometimes they use
* the full state name.
* @code
* field_salary_range:
* plugin: gate
* source: salary_range
* use_as_key: state_abbr
* valid_keys:
* - CO
* - Colorado
* key_direction: unlock
* @endcode
*
* While importing baseball players, don't import batting averages for
* pitchers. The position we use as the key to the gate is stored in a
* destination field, indicated by @.
* @code
* field_batting_average:
* plugin: gate
* source: batting_average
* use_as_key: @position
* valid_keys:
* - RHP
* - LHP
* key_direction: lock
* @endcode
*
* @codingStandardsIgnoreEnd
*/
class Gate extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
if (empty($this->configuration['valid_keys']) && !array_key_exists('valid_keys', $this->configuration)) {
throw new MigrateException('Gate plugin is missing valid_keys configuration.');
}
if (empty($this->configuration['use_as_key']) && !array_key_exists('use_as_key', $this->configuration)) {
throw new MigrateException('Gate plugin is missing use_as_key configuration.');
}
if (empty($this->configuration['key_direction']) && !array_key_exists('key_direction', $this->configuration)) {
throw new MigrateException('Gate plugin is missing key_direction configuration.');
}
if (!in_array($this->configuration['key_direction'], ['lock', 'unlock'], TRUE)) {
throw new MigrateException('Gate plugin only accepts the following values for key_direction: lock and unlock.');
}
$valid_keys = is_array($this->configuration['valid_keys']) ? $this->configuration['valid_keys'] : [$this->configuration['valid_keys']];
$key = $row->get($this->configuration['use_as_key']);
$key_is_valid = in_array($key, $valid_keys, TRUE);
$key_direction = $this->configuration['key_direction'];
$value_can_pass = ($key_is_valid && $key_direction == 'unlock') || (!$key_is_valid && $key_direction == 'lock');
if ($value_can_pass) {
return $value;
}
else {
if ($key_direction == 'lock') {
$message = sprintf('Processing of destination property %s was skipped: Gate was locked by property %s with value %s.', $destination_property, $this->configuration['use_as_key'], $key);
}
else {
$message = sprintf('Processing of destination property %s was skipped: Gate was not unlocked by property %s with value %s. ', $destination_property, $this->configuration['use_as_key'], $key);
}
throw new MigrateSkipProcessException($message);
}
}
}
<?php
namespace Drupal\Tests\migrate_plus\Unit\process;
use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateSkipProcessException;
use Drupal\migrate\Row;
use Drupal\migrate_plus\Plugin\migrate\process\Gate;
use Drupal\Tests\migrate\Unit\process\MigrateProcessTestCase;
/**
* Tests the gate process plugin.
*
* @group migrate
* @coversDefaultClass \Drupal\migrate_plus\Plugin\migrate\process\Gate
*/
class GateTest extends MigrateProcessTestCase {
/**
* Test Gate plugin.
*
* @dataProvider gateProvider
*/
public function testGate($row_data, $destination_data, $configuration, $message): void {
$row = new Row($row_data);
if (!empty($destination_data)) {
foreach ($destination_data as $key => $val) {
$row->setDestinationProperty($key, $val);
}
}
if (!empty($message)) {
$this->expectException(MigrateSkipProcessException::class);
$this->expectExceptionMessage($message);
}
$plugin = new Gate($configuration, 'gate', []);
$value = $row_data[$configuration['source']];
$transformed = $plugin->transform($value, $this->migrateExecutable, $row, 'destinationproperty');
if (empty($message)) {
$this->assertSame($value, $transformed);
}
}
/**
* Row and plugin configuration for tests.
*
* @return array
*/
public function gateProvider() {
return [
'Gate does not unlock' => [
[
'state_abbr' => 'MO',
'source_data' => 'Let me through!',
],
NULL,
[
'source' => 'source_data',
'use_as_key' => 'state_abbr',
'valid_keys' => 'CO',
'key_direction' => 'unlock',
],
'Processing of destination property destinationproperty was skipped: Gate was not unlocked by property state_abbr with value MO.',
],
'Gate unlocks (with valid_keys array)' => [
[
'state_abbr' => 'Colorado',
'source_data' => 'Let me through!',
],
NULL,
[
'source' => 'source_data',
'use_as_key' => 'state_abbr',
'valid_keys' => ['CO', 'Colorado'],
'key_direction' => 'unlock',
],
NULL,
],
'Gate locks' => [
[
'state_abbr' => 'CO',
'source_data' => 'Let me through!',
],
NULL,
[
'source' => 'source_data',
'use_as_key' => 'state_abbr',
'valid_keys' => 'CO',
'key_direction' => 'lock',
],
'Processing of destination property destinationproperty was skipped: Gate was locked by property state_abbr with value CO.',
],
'Gate stays unlocked' => [
[
'state_abbr' => 'MO',
'source_data' => 'Let me through!',
],
NULL,
[
'source' => 'source_data',
'use_as_key' => 'state_abbr',
'valid_keys' => 'CO',
'key_direction' => 'lock',
],
NULL,
],
'Destination prop does not unlock gate' => [
['source_data' => 'Let me through!'],
['state_abbr' => 'MO'],
[
'source' => 'source_data',
'use_as_key' => '@state_abbr',
'valid_keys' => 'CO',
'key_direction' => 'unlock',
],
'Processing of destination property destinationproperty was skipped: Gate was not unlocked by property @state_abbr with value MO.',
],
'Destination prop unlocks gate' => [
['source_data' => 'Let me through!'],
['state_abbr' => 'CO'],
[
'source' => 'source_data',
'use_as_key' => '@state_abbr',
'valid_keys' => 'CO',
'key_direction' => 'unlock',
],
NULL,
],
'Destination prop locks gate' => [
['source_data' => 'Let me through!'],
['state_abbr' => 'CO'],
[
'source' => 'source_data',
'use_as_key' => '@state_abbr',
'valid_keys' => 'CO',
'key_direction' => 'lock',
],
'Processing of destination property destinationproperty was skipped: Gate was locked by property @state_abbr with value CO.',
],
'Gate stays unlocked with destination prop' => [
['source_data' => 'Let me through!'],
['state_abbr' => 'MO'],
[
'source' => 'source_data',
'use_as_key' => '@state_abbr',
'valid_keys' => 'CO',
'key_direction' => 'lock',
],
NULL,
],
];
}
/**
* Test Gate plugin with bad configuration.
*
* @dataProvider badConfigurationProvider
*/
public function testGateBadConfigration($configuration, $message): void {
$this->expectException(MigrateException::class);
$this->expectExceptionMessage($message);
$plugin = new Gate($configuration, 'gate', []);
$plugin->transform(NULL, $this->migrateExecutable, $this->row, 'destinationproperty');
}
/**
* Provider for bad configuration.
*
* @return array
*/
public function badConfigurationProvider() {
return [
'Missing use_as_key' => [
[
'source' => 'source_data',
'valid_keys' => 'CO',
'key_direction' => 'unlock',
],
'Gate plugin is missing use_as_key configuration.',
],
'Missing valid_keys' => [
[
'source' => 'source_data',
'use_as_key' => 'state_abbr',
'key_direction' => 'unlock',
],
'Gate plugin is missing valid_keys configuration.',
],
'Missing key_direction' => [
[
'source' => 'source_data',
'use_as_key' => 'state_abbr',
'valid_keys' => 'CO',
],
'Gate plugin is missing key_direction configuration.',
],
'Invalid key_direction' => [
[
'source' => 'source_data',
'use_as_key' => 'state_abbr',
'valid_keys' => 'CO',
'key_direction' => 'open',
],
'Gate plugin only accepts the following values for key_direction: lock and unlock.',
],
];
}
}
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