You are here

class EntityLookup in Migrate Plus 8.4

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.3 src/Plugin/migrate/process/EntityLookup.php \Drupal\migrate_plus\Plugin\migrate\process\EntityLookup

This plugin looks for existing entities.

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

Available configuration keys:

  • access_check: (optional) Indicates if access to the entity for this user will be checked. Default is true.

@codingStandardsIgnoreStart

Example usage with minimal configuration:


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

In this example above, the access check is disabled.

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

@codingStandardsIgnoreEnd

Plugin annotation


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

Hierarchy

Expanded class hierarchy of EntityLookup

File

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

Namespace

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

  /**
   * The entity manager.
   *
   * @var \Drupal\Core\Entity\EntityManagerInterface
   */
  protected $entityManager;

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

  /**
   * The selection plugin.
   *
   * @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface
   */
  protected $selectionPluginManager;

  /**
   * The destination type.
   *
   * @var string
   */
  protected $destinationEntityType;

  /**
   * The destination bundle.
   *
   * @var string|bool
   */
  protected $destinationBundleKey;

  /**
   * The lookup value's key.
   *
   * @var string
   */
  protected $lookupValueKey;

  /**
   * The lookup bundle's key.
   *
   * @var string
   */
  protected $lookupBundleKey;

  /**
   * The lookup bundle.
   *
   * @var string
   */
  protected $lookupBundle;

  /**
   * The lookup entity type.
   *
   * @var string
   */
  protected $lookupEntityType;

  /**
   * The destination property or field.
   *
   * @var string
   */
  protected $destinationProperty;

  /**
   * The access check flag.
   *
   * @var string
   */
  protected $accessCheck = TRUE;

  /**
   * {@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]) ? NULL : $pluginIdParts[1];
    $this->destinationBundleKey = $this->destinationEntityType ? $this->entityManager
      ->getDefinition($this->destinationEntityType)
      ->getKey('bundle') : NULL;
  }

  /**
   * {@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) {

    // If the source data is an empty array, return the same.
    if (gettype($value) === 'array' && count($value) === 0) {
      return [];
    }

    // 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 (isset($this->configuration['access_check'])) {
      $this->accessCheck = $this->configuration['access_check'];
    }
    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 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(sprintf('Destination field type %s is not a recognized reference type.', $fieldConfig
              ->getType()));
        }
      }
    }

    // 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 mixed $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()
      ->accessCheck($this->accessCheck)
      ->condition($this->lookupValueKey, $value, $multiple ? 'IN' : NULL);

    // Sqlite and possibly others returns data in a non-deterministic order.
    // Make it deterministic.
    if ($multiple) {
      $query
        ->sort($this->lookupValueKey, 'DESC');
    }
    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) {
        $entity = $this->entityManager
          ->getStorage($this->lookupEntityType)
          ->load($identifier);
        $result_value = $entity instanceof ConfigEntityInterface ? $entity
          ->get($this->lookupValueKey) : $entity
          ->get($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::$accessCheck protected property The access check flag.
EntityLookup::$destinationBundleKey protected property The destination bundle.
EntityLookup::$destinationEntityType protected property The destination type.
EntityLookup::$destinationProperty protected property The destination property or field.
EntityLookup::$entityManager protected property The entity manager.
EntityLookup::$lookupBundle protected property The lookup bundle.
EntityLookup::$lookupBundleKey protected property The lookup bundle's key.
EntityLookup::$lookupEntityType protected property The lookup entity type.
EntityLookup::$lookupValueKey protected property The lookup value's key.
EntityLookup::$migration protected property The migration.
EntityLookup::$selectionPluginManager protected property The selection plugin.
EntityLookup::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create 1
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 1
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.