Issue #2853823 by Jo Fitzgerald, claudiu.cristea, Munavijayalakshmi, phenaproxima, alexpott, heddn: Explode processor is too strict regarding to the input value
parent
45d83369a3
commit
6bad867280
|
@ -22,6 +22,11 @@ use Drupal\migrate\Row;
|
|||
* returned.
|
||||
* - If the limit parameter is zero, then this is treated as 1.
|
||||
* - delimiter: The boundary string.
|
||||
* - strict: (optional) When this boolean is TRUE, the source should be strictly
|
||||
* a string. If FALSE is passed, the source value is casted to a string before
|
||||
* being split. Also, in this case, the values casting to empty strings are
|
||||
* converted to empty arrays, instead of an array with a single empty string
|
||||
* item ['']. Defaults to TRUE.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
|
@ -29,8 +34,8 @@ use Drupal\migrate\Row;
|
|||
* process:
|
||||
* bar:
|
||||
* plugin: explode
|
||||
* source: foo
|
||||
* delimiter: /
|
||||
* source: foo
|
||||
* delimiter: /
|
||||
* @endcode
|
||||
*
|
||||
* If foo is "node/1", then bar will be ['node', '1']. The PHP equivalent of
|
||||
|
@ -44,9 +49,9 @@ use Drupal\migrate\Row;
|
|||
* process:
|
||||
* bar:
|
||||
* plugin: explode
|
||||
* source: foo
|
||||
* limit: 1
|
||||
* delimiter: /
|
||||
* source: foo
|
||||
* limit: 1
|
||||
* delimiter: /
|
||||
* @endcode
|
||||
*
|
||||
* If foo is "node/1/edit", then bar will be ['node', '1/edit']. The PHP
|
||||
|
@ -56,6 +61,30 @@ use Drupal\migrate\Row;
|
|||
* $bar = explode('/', $foo, 1);
|
||||
* @endcode
|
||||
*
|
||||
* If the 'strict' configuration is set to FALSE, the input value is casted to a
|
||||
* string before being spilt:
|
||||
*
|
||||
* @code
|
||||
* process:
|
||||
* bar:
|
||||
* plugin: explode
|
||||
* source: foo
|
||||
* delimiter: /
|
||||
* strict: false
|
||||
* @endcode
|
||||
*
|
||||
* If foo is 123 (as integer), then bar will be ['123']. If foo is TRUE, then
|
||||
* bar will be ['1']. The PHP equivalent of this would be:
|
||||
*
|
||||
* @code
|
||||
* $bar = explode('/', (string) 123);
|
||||
* $bar = explode('/', (string) TRUE);
|
||||
* @endcode
|
||||
*
|
||||
* If the 'strict' configuration is set to FALSE, the source value casting to
|
||||
* an empty string are converted to an empty array. For example, with the last
|
||||
* configuration, if foo is '', NULL or FALSE, then bar will be [].
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
|
@ -68,18 +97,29 @@ class Explode extends ProcessPluginBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
if (is_string($value)) {
|
||||
if (!empty($this->configuration['delimiter'])) {
|
||||
$limit = isset($this->configuration['limit']) ? $this->configuration['limit'] : PHP_INT_MAX;
|
||||
return explode($this->configuration['delimiter'], $value, $limit);
|
||||
}
|
||||
else {
|
||||
throw new MigrateException('delimiter is empty');
|
||||
}
|
||||
if (empty($this->configuration['delimiter'])) {
|
||||
throw new MigrateException('delimiter is empty');
|
||||
}
|
||||
else {
|
||||
|
||||
$strict = array_key_exists('strict', $this->configuration) ? $this->configuration['strict'] : TRUE;
|
||||
if ($strict && !is_string($value)) {
|
||||
throw new MigrateException(sprintf('%s is not a string', var_export($value, TRUE)));
|
||||
}
|
||||
elseif (!$strict) {
|
||||
// Check if the incoming value can cast to a string.
|
||||
$original = $value;
|
||||
if (!is_string($original) && ($original != ($value = @strval($value)))) {
|
||||
throw new MigrateException(sprintf('%s cannot be casted to a string', var_export($original, TRUE)));
|
||||
}
|
||||
// Empty strings should be exploded to empty arrays.
|
||||
if ($value === '') {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
$limit = isset($this->configuration['limit']) ? $this->configuration['limit'] : PHP_INT_MAX;
|
||||
|
||||
return explode($this->configuration['delimiter'], $value, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\Tests\migrate\Unit\process;
|
||||
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\migrate\process\Explode;
|
||||
use Drupal\migrate\Plugin\migrate\process\Concat;
|
||||
|
||||
|
@ -53,23 +54,65 @@ class ExplodeTest extends MigrateProcessTestCase {
|
|||
|
||||
/**
|
||||
* Test explode fails properly on non-strings.
|
||||
*
|
||||
* @expectedException \Drupal\migrate\MigrateException
|
||||
*
|
||||
* @expectedExceptionMessage is not a string
|
||||
*/
|
||||
public function testExplodeWithNonString() {
|
||||
$this->setExpectedException(MigrateException::class, 'is not a string');
|
||||
$this->plugin->transform(['foo'], $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that explode works on non-strings but with strict set to FALSE.
|
||||
*
|
||||
* @dataProvider providerExplodeWithNonStrictAndEmptySource
|
||||
*/
|
||||
public function testExplodeWithNonStrictAndEmptySource($value, $expected) {
|
||||
$plugin = new Explode(['delimiter' => '|', 'strict' => FALSE], 'map', []);
|
||||
|
||||
$processed = $plugin->transform($value, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->assertSame($expected, $processed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for ::testExplodeWithNonStrictAndEmptySource().
|
||||
*/
|
||||
public function providerExplodeWithNonStrictAndEmptySource() {
|
||||
return [
|
||||
'normal_string' => ['a|b|c', ['a', 'b', 'c']],
|
||||
'integer_cast_to_string' => [123, ['123']],
|
||||
'zero_integer_cast_to_string' => [0, ['0']],
|
||||
'true_cast_to_string' => [TRUE, ['1']],
|
||||
'null_empty_array' => [NULL, []],
|
||||
'false_empty_array' => [FALSE, []],
|
||||
'empty_string_empty_array' => ['', []],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that explode raises an exception when the value cannot be casted to
|
||||
* string.
|
||||
*/
|
||||
public function testExplodeWithNonStrictAndNonCastable() {
|
||||
$plugin = new Explode(['delimiter' => '|', 'strict' => FALSE], 'map', []);
|
||||
$this->setExpectedException(MigrateException::class, 'cannot be casted to a string');
|
||||
$processed = $plugin->transform(['foo'], $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->assertSame(['foo'], $processed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that explode with an empty string and strict check returns a
|
||||
* non-empty array.
|
||||
*/
|
||||
public function testExplodeWithStrictAndEmptyString() {
|
||||
$plugin = new Explode(['delimiter' => '|'], 'map', []);
|
||||
$processed = $plugin->transform('', $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->assertSame([''], $processed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test explode fails with empty delimiter.
|
||||
*
|
||||
* @expectedException \Drupal\migrate\MigrateException
|
||||
*
|
||||
* @expectedExceptionMessage delimiter is empty
|
||||
*/
|
||||
public function testExplodeWithEmptyDelimiter() {
|
||||
$this->setExpectedException(MigrateException::class, 'delimiter is empty');
|
||||
$plugin = new Explode(['delimiter' => ''], 'map', []);
|
||||
$plugin->transform('foo,bar', $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue