Skip to content
Snippets Groups Projects
Commit aa3187d0 authored by git's avatar git Committed by Mike Ryan
Browse files

Issue #2642612 by heddn, edysmp, generalconsensus, mikeryan, esclapes,...

Issue #2642612 by heddn, edysmp, generalconsensus, mikeryan, esclapes, nvahalik, sime, Adita: Create Entity Lookup & Generate process Base plugins
parent d6734760
No related branches found
No related tags found
No related merge requests found
<?php
/**
* @file
* Contains Drupal\migrate_plus\Plugin\migrate\process\EntityGenerate.
*/
namespace Drupal\migrate_plus\Plugin\migrate\process;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
/**
* This plugin generates entity stubs.
*
* @MigrateProcessPlugin(
* id = "entity_generate"
* )
*
* @see EntityLookup
*
* All the configuration from the lookup plugin applies here. In it's most
* simple form, this plugin needs no configuration. If there are fields on the
* stub entity that are required or need some default value, that can be
* provided via a default_values configuration option.
*
* Example usage with default_values configuration:
* @code
* destination:
* plugin: 'entity:node'
* process:
* type:
* plugin: default_value
* default_value: page
* field_tags:
* plugin: entity_generate
* source: tags
* default_values:
* description: Stub description
* field_long_description: Stub long description
* @endcode
*/
class EntityGenerate extends EntityLookup {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrateExecutable, Row $row, $destinationProperty) {
// Creates a stub entity if one doesn't exist.
if (!($result = parent::transform($value, $migrateExecutable, $row, $destinationProperty))) {
$result = $this->generateEntity($value);
}
return $result;
}
/**
* Generates stub entity for a given value.
*
* @param string $value
* Value to use in creation of stub entity.
*
* @return int|string
* The entity id of the generated entity.
*/
protected function generateEntity($value) {
if(!empty($value)) {
$entity = $this->entityManager
->getStorage($this->lookupEntityType)
->create($this->stub($value));
$entity->save();
return $entity->id();
}
}
/**
* Fabricate a stub entity.
*
* This is intended to be extended by implementing classes to provide for more
* dynamic default values, rather than just static ones.
*
* @param $value
* Value to use in creation of stub entity.
*
* @return array
* The stub entity.
*/
protected function stub($value) {
$stub = [$this->lookupValueKey => $value];
if ($this->lookupBundleKey) {
$stub[$this->lookupBundleKey] = $this->lookupBundle;
}
// Gather any static default values for properties/fields.
if (isset($this->configuration['default_values']) && is_array($this->configuration['default_values'])) {
foreach ($this->configuration['default_values'] as $key => $value) {
$stub[$key] = $value;
}
}
return $stub;
}
}
<?php
/**
* @file
* Contains Drupal\migrate_plus\Plugin\migrate\process\EntityGenerate.
*/
namespace Drupal\migrate_plus\Plugin\migrate\process;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* 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:
* @code
* destination:
* plugin: 'entity:node'
* process:
* type:
* plugin: default_value
* default_value: page
* field_tags:
* plugin: entity_lookup
* source: tags
* @endcode
*
* Example usage with full configuration:
* @code
* field_tags:
* plugin: entity_lookup
* source: tags
* value_key: name
* bundle_key: vid
* bundle: tags
* entity_type: taxonomy_term
* ignore_case: true
* @endcode
*/
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) {
$this->determineLookupProperties($destinationProperty);
$this->destinationProperty = $this->configuration['destination_field'];
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);
if ($fieldConfig->getType() != 'entity_reference') {
throw new MigrateException('The entity_lookup plugin found no entity reference field.');
}
if (empty($this->lookupBundle)) {
$handlerSettings = $fieldConfig->getSetting('handler_settings');
$bundles = array_filter((array) $handlerSettings['target_bundles']);
if (count($bundles) == 1) {
$this->lookupBundle = reset($bundles);
}
// This was added in 8.1.x is not supported in 8.0.x.
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');
}
}
// 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;
}
if ($multiple && !empty($this->destinationProperty)) {
array_walk($results, function (&$value) {
$value = [$this->destinationProperty => $value];
});
return array_values($results);
}
// By default do a case-sensitive comparison.
if (!$ignoreCase) {
// Returns the entity's identifier.
foreach ($results as $identifier) {
if ($value === $this->entityManager->getStorage($this->lookupEntityType)->load($identifier)->{$this->lookupValueKey}->value) {
return $identifier;
}
}
}
return reset($results);
}
}
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