Commit 0dccc720 authored by Dan Flanagan's avatar Dan Flanagan Committed by Dan Flanagan
Browse files

Issue #3319154 by danflanagan8: Add migrate_condition plugin that does a migrate lookup

parent bc417827
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ Migrate Condition plugins
* greater_than
* has_element ("helper" condition to change handling of arrays)
* in_array
* in_migrate_map
* is_null
* is_stub
* isset
+139 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\migrate_conditions\Plugin\migrate_conditions\condition;

use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\MigrateLookupInterface;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\migrate\Row;
use Drupal\migrate_conditions\Plugin\ConditionBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides an 'in_migrate_map' condition.
 *
 * This functions similarly to the migration_lookup process plugin with a
 * couple notable differences. First, this is a migrate_condition plugin, so
 * it returns a boolean rather than destination ids. Second, this plugin will
 * never create stubs and as such there is not a no_stub option. Third, the
 * treatment of skipped rows is configurable through the include_skipped
 * property.
 *
 * Available configuration keys:
 * - migration: The migration id or array of migration ids against which to do
 *   a lookup.
 * - include_skipped: (optional) If TRUE, a source is considered to be in the
 *   map even the row has been skipped and the destination ids are null.
 *   Defaults to FALSE.
 * - negate: (optional) Whether the 'in_migrate_map' condition should be
 *   negated. Defaults to FALSE. You can also negate the 'in_migrate_map'
 *   plugin by using 'not:in_migrate_map' as the plugin id.
 *
 * Examples:
 *
 * Skip the row if a value is in a certain migrate map.
 *
 * @code
 * process:
 *   _skip_if_in_other_migration:
 *     plugin: skip_on_condition
 *     method: row
 *     source: my_source_value
 *     condition:
 *       plugin: in_migrate_map
 *       migrate: some_other_migration
 * @endcode
 *
 * or equivalently
 *
 * @code
 * process:
 *   _skip_if_in_other_migration:
 *     plugin: skip_on_condition
 *     method: row
 *     source: my_source_value
 *     condition: in_migrate_map(some_other_migration)
 * @endcode
 *
 * @MigrateConditionsConditionPlugin(
 *   id = "in_migrate_map",
 *   requires = {"migration"},
 *   parens = "migration"
 * )
 */
class InMigrateMap extends ConditionBase implements ContainerFactoryPluginInterface {

  /**
   * The migrate lookup service.
   *
   * @var \Drupal\migrate\MigrateLookupInterface
   */
  protected $migrateLookup;

  /**
   * InMigrateMap constructor.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin ID.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param Drupal\migrate\MigrateLookupInterface $migrate_lookup
   *   The migrate lookup service.
   * @param Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager
   *   The migration plugin manager.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrateLookupInterface $migrate_lookup, MigrationPluginManagerInterface $migration_plugin_manager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->configuration['include_skipped'] = $configuration['include_skipped'] ?? FALSE;
    $this->configuration['migration'] = (array) $configuration['migration'];
    foreach ($this->configuration['migration']  as $migration_id) {
      $migration = $migration_plugin_manager->createInstance($migration_id);
      if (empty($migration)) {
        throw new \InvalidArgumentException('The migration configured for in_migrate_map could not be loaded: ' . $migration_id);
      }
    }
    $this->migrateLookup = $migrate_lookup;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('migrate.lookup'),
      $container->get('plugin.manager.migration')
    );
  }

  /**
   * {@inheritdoc}
   */
  protected function doEvaluate($source, Row $row) {
    $lookup = $this->migrateLookup->lookup($this->configuration['migration'], (array) $source);
    // If the source was not found, an empty array is returned.
    if (empty($lookup)) {
      return FALSE;
    }
    // If the source was found but the row was skipped, the lookup
    // will be an array of arrays containing at least one NULL id.
    if ($this->configuration['include_skipped'] === TRUE) {
      return TRUE;
    }
    else {
      foreach ($lookup as $ids) {
        foreach ($ids as $id) {
          if (is_null($id)) {
            return FALSE;
          }
        }
      }
      return TRUE;
    }
  }

}
+7 −0
Original line number Diff line number Diff line
name: 'Migreate Conditions Test Migrations'
type: module
description: 'Provides test migrations to test migrate_conditions.'
package: Testing
version: VERSION
dependencies:
  - migrate_conditions:migrate_conditions
+53 −0
Original line number Diff line number Diff line
id: in_migrate_map_test
label: "InMigrateMap Test"
source:
  plugin: embedded_data
  data_rows:
    - id: 17
      lookup: 25
    - id: 25
      lookup: 17
    - id: 33
      lookup: 33
    - id: 13
      lookup: 123
    - id: 44
      lookup: 13
  ids:
    id:
      type: integer
process:
  # This skip is so we can show what happens when a row is in the map but skipped.
  _skip_13:
    plugin: skip_on_condition
    method: row
    condition: equals(13)
    source: id
  found:
    plugin: evaluate_condition
    source: lookup
    condition:
      plugin: in_migrate_map
      migration: in_migrate_map_test
  not_found:
    plugin: evaluate_condition
    source: lookup
    condition: not:in_migrate_map(in_migrate_map_test)
  found_include_skipped:
    plugin: evaluate_condition
    source: lookup
    condition:
      plugin: in_migrate_map
      migration: in_migrate_map_test
      include_skipped: true
  title:
    plugin: concat
    delimiter: '-'
    source:
      - id
      - '@found'
      - '@not_found'
      - '@found_include_skipped'
destination:
  plugin: entity:node
  default_bundle: node_lookup
+77 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\migrate_conditions\Kernel\condition;

use Drupal\KernelTests\KernelTestBase;
use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate_conditions\Plugin\migrate_conditions\condition\InMigrateMap;
use Drupal\node\Entity\Node;
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;

/**
 * Tests the in_migrate_map condition plugin.
 *
 * @group migrate_conditions
 */
class InMigrateMapTest extends KernelTestBase {
  use ContentTypeCreationTrait;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'system',
    'node',
    'field',
    'user',
    'text',
    'migrate',
    'migrate_conditions',
    'migrate_conditions_test_migrations',
  ];

  /**
   * {@inheritdoc}
   */
  public function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('node');
    $this->installEntitySchema('user');
    $this->installConfig(['node', 'user']);
    $this->createContentType(['type' => 'node_lookup']);
  }

  /**
   * Tests validation in constructor.
   */
  public function testConstructor() {
    $configuration = [];
    $plugin_definition = \Drupal::service('plugin.manager.migrate_conditions.condition')->getDefinition('in_migrate_map');
    $lookup = \Drupal::service('migrate.lookup');
    $manager = \Drupal::service('plugin.manager.migration');
    $this->expectException(\InvalidArgumentException::class);
    $this->expectExceptionMessage('The migration configuration is required when using the in_migrate_map condition.');
    $condition = new InMigrateMap($configuration, 'in_migrate_map', $plugin_definition, $lookup, $manager);
  }

  /**
   * Tests in_migrate_map condition plugin.
   */
  public function testInMigrateMap() {
    $manager = \Drupal::service('plugin.manager.migration');
    $migration = $manager->createInstance('in_migrate_map_test');
    $executable = new MigrateExecutable($migration);
    $result = $executable->import();
    $this->assertSame(MigrationInterface::RESULT_COMPLETED, $result);
    $expected = '17--1-';
    $this->assertEquals($expected, Node::load(1)->label());
    $expected = '25-1--1';
    $this->assertEquals($expected, Node::load(2)->label());
    $expected = '33--1-';
    $this->assertEquals($expected, Node::load(3)->label());
    $expected = '44--1-1';
    $this->assertEquals($expected, Node::load(4)->label());
  }

}
Loading