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;
* - entity_reference: The entity label key.
* - file: 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
* being queried.
* - bundle: (optional) The value to query for the bundle.
* - access_check: (optional) Indicates if access to the entity for this user
* will be checked. Default is true.
* - 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
* value is an array, the result array's items will be themselves arrays of
* the form [destination_field => ENTITY_ID].
......@@ -70,10 +74,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* bundle: tags
* entity_type: taxonomy_term
* ignore_case: true
* operator: STARTS_WITH
* @endcode
*
* @codingStandardsIgnoreEnd
*
* @see \Drupal\Core\Entity\Query\QueryInterface::condition()
*
* @MigrateProcessPlugin(
* id = "entity_lookup",
* handle_multiples = TRUE
......@@ -220,17 +227,22 @@ class EntityLookup extends ProcessPluginBase implements ContainerFactoryPluginIn
*/
protected function query($value) {
// Entity queries typically are case-insensitive. Therefore, we need to
// handle case sensitive filtering as a post-query step. By default, it
// filters case insensitive. Change to true if that is not the desired
// handle case-sensitive filtering as a post-query step. By default, it
// filters case-insensitive. Change to true if that is not the desired
// outcome.
$ignoreCase = !empty($this->configuration['ignore_case']) ?: FALSE;
$operator = !empty($this->configuration['operator']) ? $this->configuration['operator'] : '=';
$multiple = is_array($value);
// Apply correct operator for multiple values.
if ($multiple && $operator === '=') {
$operator = 'IN';
}
$query = $this->entityTypeManager->getStorage($this->lookupEntityType)
->getQuery()
->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.
// Make it deterministic.
if ($multiple) {
......@@ -246,8 +258,8 @@ class EntityLookup extends ProcessPluginBase implements ContainerFactoryPluginIn
return NULL;
}
// By default do a case-sensitive comparison.
if (!$ignoreCase) {
// Do a case-sensitive comparison only for strict operators.
if (!$ignoreCase && in_array($operator, ['=', 'IN'], TRUE)) {
// Returns the entity's identifier.
foreach ($results as $k => $identifier) {
$entity = $this->entityTypeManager->getStorage($this->lookupEntityType)->load($identifier);
......
......@@ -5,10 +5,8 @@ declare(strict_types = 1);
namespace Drupal\Tests\migrate_plus\Kernel\Plugin\migrate\process;
use Drupal\KernelTests\KernelTestBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Plugin\MigrateDestinationInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\Tests\user\Traits\UserCreationTrait;
/**
......@@ -20,6 +18,7 @@ use Drupal\Tests\user\Traits\UserCreationTrait;
final class EntityLookupTest extends KernelTestBase {
use UserCreationTrait;
use NodeCreationTrait;
/**
* The migrate executable mock object.
......@@ -36,6 +35,7 @@ final class EntityLookupTest extends KernelTestBase {
'migrate',
'user',
'system',
'node',
'filter',
];
......@@ -46,11 +46,22 @@ final class EntityLookupTest extends KernelTestBase {
parent::setUp();
$this->installSchema('system', ['sequences']);
$this->installEntitySchema('user');
$this->installEntitySchema('node');
$this->installConfig(['filter']);
$this->migrateExecutable = $this->getMockBuilder('Drupal\migrate\MigrateExecutable')
->disableOriginalConstructor()
->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 {
* @covers ::transform
*/
public function testLookupEntityWithoutBundles(): void {
$migration = \Drupal::service('plugin.manager.migration')
->createStubMigration([
'id' => 'test',
'source' => [],
'process' => [],
'destination' => [
'plugin' => 'entity:user',
],
]);
// Create a user.
$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 = [
'entity_type' => 'user',
'value_key' => 'name',
];
$plugin = \Drupal::service('plugin.manager.migrate.process')
->createInstance('entity_lookup', $configuration, $migration);
$executable = $this->prophesize(MigrateExecutableInterface::class)->reveal();
$row = new Row();
// 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);
// 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);
}
......@@ -113,4 +128,63 @@ final class EntityLookupTest extends KernelTestBase {
$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