You are here

class EntityLookup in Migrate Plus 8.3

Same name and namespace in other branches
  1. 8.5 src/Plugin/migrate/process/EntityLookup.php \Drupal\migrate_plus\Plugin\migrate\process\EntityLookup
  2. 8.2 src/Plugin/migrate/process/EntityLookup.php \Drupal\migrate_plus\Plugin\migrate\process\EntityLookup
  3. 8.4 src/Plugin/migrate/process/EntityLookup.php \Drupal\migrate_plus\Plugin\migrate\process\EntityLookup

This plugin looks for existing entities.

@MigrateProcessPlugin( id = "entity_lookup", handle_multiples = TRUE )

In its most simple form, this plugin needs no configuration. However, if the lookup properties cannot be determined through introspection, define them via configuration.

Example usage with minimal configuration:


destination:
  plugin: 'entity:node'
process:
  type:
    plugin: default_value
    default_value: page
  field_tags:
    plugin: entity_lookup
    source: tags

Example usage with full configuration:


  field_tags:
    plugin: entity_lookup
    source: tags
    value_key: name
    bundle_key: vid
    bundle: tags
    entity_type: taxonomy_term
    ignore_case: true

Hierarchy

Expanded class hierarchy of EntityLookup

File

src/Plugin/migrate/process/EntityLookup.php, line 52

Namespace

Drupal\migrate_plus\Plugin\migrate\process
View source
class EntityLookup extends ProcessPluginBase implements ContainerFactoryPluginInterface {

  /** @var \Drupal\Core\Entity\EntityManagerInterface */
  protected $entityManager;

  /** @var \Drupal\migrate\Plugin\MigrationInterface */
  protected $migration;

  /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface */
  protected $selectionPluginManager;

  /** @var string */
  protected $destinationEntityType;

  /** @var string|bool */
  protected $destinationBundleKey;

  /** @var string */
  protected $lookupValueKey;

  /** @var string */
  protected $lookupBundleKey;

  /** @var string */
  protected $lookupBundle;

  /** @var string */
  protected $lookupEntityType;

  /** @var string */
  protected $destinationProperty;

  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $pluginId, $pluginDefinition, MigrationInterface $migration, EntityManagerInterface $entityManager, SelectionPluginManagerInterface $selectionPluginManager) {
    parent::__construct($configuration, $pluginId, $pluginDefinition);
    $this->migration = $migration;
    $this->entityManager = $entityManager;
    $this->selectionPluginManager = $selectionPluginManager;
    $pluginIdParts = explode(':', $this->migration
      ->getDestinationPlugin()
      ->getPluginId());
    $this->destinationEntityType = empty($pluginIdParts[1]) ?: $pluginIdParts[1];
    $this->destinationBundleKey = !$this->destinationEntityType ?: $this->entityManager
      ->getDefinition($this->destinationEntityType)
      ->getKey('bundle');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition, MigrationInterface $migration = NULL) {
    return new static($configuration, $pluginId, $pluginDefinition, $migration, $container
      ->get('entity.manager'), $container
      ->get('plugin.manager.entity_reference_selection'));
  }

  /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrateExecutable, Row $row, $destinationProperty) {

    // In case of subfields ('field_reference/target_id'), extract the field
    // name only.
    $parts = explode('/', $destinationProperty);
    $destinationProperty = reset($parts);
    $this
      ->determineLookupProperties($destinationProperty);
    $this->destinationProperty = isset($this->configuration['destination_field']) ? $this->configuration['destination_field'] : NULL;
    return $this
      ->query($value);
  }

  /**
   * Determine the lookup properties from config or target field configuration.
   *
   * @param string $destinationProperty
   *   The destination property currently worked on. This is only used together
   *   with the $row above.
   */
  protected function determineLookupProperties($destinationProperty) {
    if (!empty($this->configuration['value_key'])) {
      $this->lookupValueKey = $this->configuration['value_key'];
    }
    if (!empty($this->configuration['bundle_key'])) {
      $this->lookupBundleKey = $this->configuration['bundle_key'];
    }
    if (!empty($this->configuration['bundle'])) {
      $this->lookupBundle = $this->configuration['bundle'];
    }
    if (!empty($this->configuration['entity_type'])) {
      $this->lookupEntityType = $this->configuration['entity_type'];
    }
    if (empty($this->lookupValueKey) || empty($this->lookupBundleKey) || empty($this->lookupBundle) || empty($this->lookupEntityType)) {

      // See if we can introspect the lookup properties from the destination field.
      if (!empty($this->migration
        ->getProcess()[$this->destinationBundleKey][0]['default_value'])) {
        $destinationEntityBundle = $this->migration
          ->getProcess()[$this->destinationBundleKey][0]['default_value'];
        $fieldConfig = $this->entityManager
          ->getFieldDefinitions($this->destinationEntityType, $destinationEntityBundle)[$destinationProperty]
          ->getConfig($destinationEntityBundle);
        switch ($fieldConfig
          ->getType()) {
          case 'entity_reference':
            if (empty($this->lookupBundle)) {
              $handlerSettings = $fieldConfig
                ->getSetting('handler_settings');
              $bundles = array_filter((array) $handlerSettings['target_bundles']);
              if (count($bundles) == 1) {
                $this->lookupBundle = reset($bundles);
              }
              elseif (!empty($handlerSettings['auto_create']) && !empty($handlerSettings['auto_create_bundle'])) {
                $this->lookupBundle = reset($handlerSettings['auto_create_bundle']);
              }
            }

            // Make an assumption that if the selection handler can target more than
            // one type of entity that we will use the first entity type.
            $this->lookupEntityType = $this->lookupEntityType ?: reset($this->selectionPluginManager
              ->createInstance($fieldConfig
              ->getSetting('handler'))
              ->getPluginDefinition()['entity_types']);
            $this->lookupValueKey = $this->lookupValueKey ?: $this->entityManager
              ->getDefinition($this->lookupEntityType)
              ->getKey('label');
            $this->lookupBundleKey = $this->lookupBundleKey ?: $this->entityManager
              ->getDefinition($this->lookupEntityType)
              ->getKey('bundle');
            break;
          case 'file':
          case 'image':
            $this->lookupEntityType = 'file';
            $this->lookupValueKey = $this->lookupValueKey ?: 'uri';
            break;
          default:
            throw new MigrateException('Destination field type ' . $fieldConfig
              ->getType() . 'is not a recognized reference type.');
        }
      }
    }

    // If there aren't enough lookup properties available by now, then bail.
    if (empty($this->lookupValueKey)) {
      throw new MigrateException('The entity_lookup plugin requires a value_key, none located.');
    }
    if (!empty($this->lookupBundleKey) && empty($this->lookupBundle)) {
      throw new MigrateException('The entity_lookup plugin found no bundle but destination entity requires one.');
    }
    if (empty($this->lookupEntityType)) {
      throw new MigrateException('The entity_lookup plugin requires a entity_type, none located.');
    }
  }

  /**
   * Checks for the existence of some value.
   *
   * @param $value
   * The value to query.
   *
   * @return mixed|null
   *   Entity id if the queried entity exists. Otherwise NULL.
   */
  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
    // outcome.
    $ignoreCase = !empty($this->configuration['ignore_case']) ?: FALSE;
    $multiple = is_array($value);
    $query = $this->entityManager
      ->getStorage($this->lookupEntityType)
      ->getQuery()
      ->condition($this->lookupValueKey, $value, $multiple ? 'IN' : NULL);
    if ($this->lookupBundleKey) {
      $query
        ->condition($this->lookupBundleKey, $this->lookupBundle);
    }
    $results = $query
      ->execute();
    if (empty($results)) {
      return NULL;
    }

    // By default do a case-sensitive comparison.
    if (!$ignoreCase) {

      // Returns the entity's identifier.
      foreach ($results as $k => $identifier) {
        $result_value = $this->entityManager
          ->getStorage($this->lookupEntityType)
          ->load($identifier)->{$this->lookupValueKey}->value;
        if ($multiple && !in_array($result_value, $value, TRUE) || !$multiple && $result_value !== $value) {
          unset($results[$k]);
        }
      }
    }
    if ($multiple && !empty($this->destinationProperty)) {
      array_walk($results, function (&$value) {
        $value = [
          $this->destinationProperty => $value,
        ];
      });
    }
    return $multiple ? array_values($results) : reset($results);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
EntityLookup::$destinationBundleKey protected property @var string|bool
EntityLookup::$destinationEntityType protected property @var string
EntityLookup::$destinationProperty protected property @var string
EntityLookup::$entityManager protected property @var \Drupal\Core\Entity\EntityManagerInterface
EntityLookup::$lookupBundle protected property @var string
EntityLookup::$lookupBundleKey protected property @var string
EntityLookup::$lookupEntityType protected property @var string
EntityLookup::$lookupValueKey protected property @var string
EntityLookup::$migration protected property @var \Drupal\migrate\Plugin\MigrationInterface
EntityLookup::$selectionPluginManager protected property @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface
EntityLookup::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
EntityLookup::determineLookupProperties protected function Determine the lookup properties from config or target field configuration.
EntityLookup::query protected function Checks for the existence of some value.
EntityLookup::transform public function Performs the associated process. Overrides ProcessPluginBase::transform 1
EntityLookup::__construct public function Constructs a \Drupal\Component\Plugin\PluginBase object. Overrides PluginBase::__construct
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
ProcessPluginBase::multiple public function Indicates whether the returned value requires multiple handling. Overrides MigrateProcessInterface::multiple 3
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.