Skip to content
Snippets Groups Projects
Commit dae1881a authored by Ivan Doroshenko's avatar Ivan Doroshenko Committed by Ivan Doroshenko
Browse files

Issue #3121204 by Matroskeen, rodrigoaguilera: Add ability to choose the...

Issue #3121204 by Matroskeen, rodrigoaguilera: Add ability to choose the operator when performing an entity lookup
parent 3c615f73
No related branches found
No related tags found
1 merge request!8Issue #3229479: Entity_lookup taxonomy_term restricted by VID
...@@ -32,13 +32,17 @@ use Symfony\Component\DependencyInjection\ContainerInterface; ...@@ -32,13 +32,17 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* - entity_reference: The entity label key. * - entity_reference: The entity label key.
* - file: The uri field. * - file: The uri field.
* - image: The uri field. * - image: The uri field.
* - operator: (optional) The comparison operator supported by entity query:
* See \Drupal\Core\Entity\Query\QueryInterface::condition() for available
* values. Defaults to '=' for scalar values and 'IN' for arrays.
* - bundle_key: (optional) The name of the bundle field on the entity type * - bundle_key: (optional) The name of the bundle field on the entity type
* being queried. * being queried.
* - bundle: (optional) The value to query for the bundle. * - bundle: (optional) The value to query for the bundle.
* - access_check: (optional) Indicates if access to the entity for this user * - access_check: (optional) Indicates if access to the entity for this user
* will be checked. Default is true. * will be checked. Default is true.
* - ignore_case: (optional) Whether to ignore case in the query. Defaults to * - ignore_case: (optional) Whether to ignore case in the query. Defaults to
* true. * false, meaning the query is case-sensitive by default. Works only with
* strict operators: '=' and 'IN'.
* - destination_field: (optional) If specified, and if the plugin's source * - destination_field: (optional) If specified, and if the plugin's source
* value is an array, the result array's items will be themselves arrays of * value is an array, the result array's items will be themselves arrays of
* the form [destination_field => ENTITY_ID]. * the form [destination_field => ENTITY_ID].
...@@ -70,10 +74,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface; ...@@ -70,10 +74,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* bundle: tags * bundle: tags
* entity_type: taxonomy_term * entity_type: taxonomy_term
* ignore_case: true * ignore_case: true
* operator: STARTS_WITH
* @endcode * @endcode
* *
* @codingStandardsIgnoreEnd * @codingStandardsIgnoreEnd
* *
* @see \Drupal\Core\Entity\Query\QueryInterface::condition()
*
* @MigrateProcessPlugin( * @MigrateProcessPlugin(
* id = "entity_lookup", * id = "entity_lookup",
* handle_multiples = TRUE * handle_multiples = TRUE
...@@ -220,17 +227,22 @@ class EntityLookup extends ProcessPluginBase implements ContainerFactoryPluginIn ...@@ -220,17 +227,22 @@ class EntityLookup extends ProcessPluginBase implements ContainerFactoryPluginIn
*/ */
protected function query($value) { protected function query($value) {
// Entity queries typically are case-insensitive. Therefore, we need to // Entity queries typically are case-insensitive. Therefore, we need to
// handle case sensitive filtering as a post-query step. By default, it // handle case-sensitive filtering as a post-query step. By default, it
// filters case insensitive. Change to true if that is not the desired // filters case-insensitive. Change to true if that is not the desired
// outcome. // outcome.
$ignoreCase = !empty($this->configuration['ignore_case']) ?: FALSE; $ignoreCase = !empty($this->configuration['ignore_case']) ?: FALSE;
$operator = !empty($this->configuration['operator']) ? $this->configuration['operator'] : '=';
$multiple = is_array($value); $multiple = is_array($value);
// Apply correct operator for multiple values.
if ($multiple && $operator === '=') {
$operator = 'IN';
}
$query = $this->entityTypeManager->getStorage($this->lookupEntityType) $query = $this->entityTypeManager->getStorage($this->lookupEntityType)
->getQuery() ->getQuery()
->accessCheck($this->accessCheck) ->accessCheck($this->accessCheck)
->condition($this->lookupValueKey, $value, $multiple ? 'IN' : NULL); ->condition($this->lookupValueKey, $value, $operator);
// Sqlite and possibly others returns data in a non-deterministic order. // Sqlite and possibly others returns data in a non-deterministic order.
// Make it deterministic. // Make it deterministic.
if ($multiple) { if ($multiple) {
...@@ -246,8 +258,8 @@ class EntityLookup extends ProcessPluginBase implements ContainerFactoryPluginIn ...@@ -246,8 +258,8 @@ class EntityLookup extends ProcessPluginBase implements ContainerFactoryPluginIn
return NULL; return NULL;
} }
// By default do a case-sensitive comparison. // Do a case-sensitive comparison only for strict operators.
if (!$ignoreCase) { if (!$ignoreCase && in_array($operator, ['=', 'IN'], TRUE)) {
// Returns the entity's identifier. // Returns the entity's identifier.
foreach ($results as $k => $identifier) { foreach ($results as $k => $identifier) {
$entity = $this->entityTypeManager->getStorage($this->lookupEntityType)->load($identifier); $entity = $this->entityTypeManager->getStorage($this->lookupEntityType)->load($identifier);
......
...@@ -5,10 +5,8 @@ declare(strict_types = 1); ...@@ -5,10 +5,8 @@ declare(strict_types = 1);
namespace Drupal\Tests\migrate_plus\Kernel\Plugin\migrate\process; namespace Drupal\Tests\migrate_plus\Kernel\Plugin\migrate\process;
use Drupal\KernelTests\KernelTestBase; use Drupal\KernelTests\KernelTestBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Plugin\MigrateDestinationInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row; use Drupal\migrate\Row;
use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\Tests\user\Traits\UserCreationTrait; use Drupal\Tests\user\Traits\UserCreationTrait;
/** /**
...@@ -20,6 +18,7 @@ use Drupal\Tests\user\Traits\UserCreationTrait; ...@@ -20,6 +18,7 @@ use Drupal\Tests\user\Traits\UserCreationTrait;
final class EntityLookupTest extends KernelTestBase { final class EntityLookupTest extends KernelTestBase {
use UserCreationTrait; use UserCreationTrait;
use NodeCreationTrait;
/** /**
* The migrate executable mock object. * The migrate executable mock object.
...@@ -36,6 +35,7 @@ final class EntityLookupTest extends KernelTestBase { ...@@ -36,6 +35,7 @@ final class EntityLookupTest extends KernelTestBase {
'migrate', 'migrate',
'user', 'user',
'system', 'system',
'node',
'filter', 'filter',
]; ];
...@@ -46,11 +46,22 @@ final class EntityLookupTest extends KernelTestBase { ...@@ -46,11 +46,22 @@ final class EntityLookupTest extends KernelTestBase {
parent::setUp(); parent::setUp();
$this->installSchema('system', ['sequences']); $this->installSchema('system', ['sequences']);
$this->installEntitySchema('user'); $this->installEntitySchema('user');
$this->installEntitySchema('node');
$this->installConfig(['filter']); $this->installConfig(['filter']);
$this->migrateExecutable = $this->getMockBuilder('Drupal\migrate\MigrateExecutable') $this->migrateExecutable = $this->getMockBuilder('Drupal\migrate\MigrateExecutable')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
$test_nodes = [
['title' => 'foo 1'],
['title' => 'foo 2'],
['title' => 'bar 1'],
];
foreach ($test_nodes as $test_node) {
$this->createNode($test_node);
}
} }
/** /**
...@@ -62,29 +73,33 @@ final class EntityLookupTest extends KernelTestBase { ...@@ -62,29 +73,33 @@ final class EntityLookupTest extends KernelTestBase {
* @covers ::transform * @covers ::transform
*/ */
public function testLookupEntityWithoutBundles(): void { public function testLookupEntityWithoutBundles(): void {
$migration = \Drupal::service('plugin.manager.migration')
->createStubMigration([
'id' => 'test',
'source' => [],
'process' => [],
'destination' => [
'plugin' => 'entity:user',
],
]);
// Create a user. // Create a user.
$known_user = $this->createUser([], 'lucuma'); $known_user = $this->createUser([], 'lucuma');
// Setup test migration objects.
$migration_prophecy = $this->prophesize(MigrationInterface::class);
$migrate_destination_prophecy = $this->prophesize(MigrateDestinationInterface::class);
$migrate_destination_prophecy->getPluginId()->willReturn('user');
$migrate_destination = $migrate_destination_prophecy->reveal();
$migration_prophecy->getDestinationPlugin()->willReturn($migrate_destination);
$migration_prophecy->getProcess()->willReturn([]);
$migration = $migration_prophecy->reveal();
$configuration = [ $configuration = [
'entity_type' => 'user', 'entity_type' => 'user',
'value_key' => 'name', 'value_key' => 'name',
]; ];
$plugin = \Drupal::service('plugin.manager.migrate.process') $plugin = \Drupal::service('plugin.manager.migrate.process')
->createInstance('entity_lookup', $configuration, $migration); ->createInstance('entity_lookup', $configuration, $migration);
$executable = $this->prophesize(MigrateExecutableInterface::class)->reveal();
$row = new Row(); $row = new Row();
// Check the known user is found. // Check the known user is found.
$value = $plugin->transform('lucuma', $executable, $row, 'name'); $value = $plugin->transform('lucuma', $this->migrateExecutable, $row, 'name');
$this->assertSame($known_user->id(), $value); $this->assertSame($known_user->id(), $value);
// Check an unknown user is not found. // Check an unknown user is not found.
$value = $plugin->transform('orange', $executable, $row, 'name'); $value = $plugin->transform('orange', $this->migrateExecutable, $row, 'name');
$this->assertNull($value); $this->assertNull($value);
} }
...@@ -113,4 +128,63 @@ final class EntityLookupTest extends KernelTestBase { ...@@ -113,4 +128,63 @@ final class EntityLookupTest extends KernelTestBase {
$this->assertEquals('plain_text', $value); $this->assertEquals('plain_text', $value);
} }
/**
* Tests lookup with different operators.
*
* @covers ::transform
* @dataProvider providerTestLookupOperators
*/
public function testLookupOperators($configuration, $lookup_value, $expected_value): void {
$migration = \Drupal::service('plugin.manager.migration')
->createStubMigration([
'id' => 'test',
'source' => [],
'process' => [],
'destination' => [
'plugin' => 'entity:node',
],
]);
$plugin = \Drupal::service('plugin.manager.migrate.process')
->createInstance('entity_lookup', $configuration, $migration);
$value = $plugin->transform($lookup_value, $this->migrateExecutable, new Row(), 'destination_property');
$this->assertEquals($expected_value, $value);
}
/**
* Data provider for testLookupOperators test.
*
* @return array[]
* The test cases.
*/
public function providerTestLookupOperators(): array {
return [
'Default operator' => [
[
'entity_type' => 'node',
'value_key' => 'title',
],
'foo 1',
'1',
],
'Multiple values' => [
[
'entity_type' => 'node',
'value_key' => 'title',
],
['foo 1', 'foo 2'],
['2', '1'],
],
'Starts with' => [
[
'entity_type' => 'node',
'value_key' => 'title',
'operator' => 'STARTS_WITH',
],
'bar',
'3',
],
];
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment