annotate modules/contrib/migrate_plus/src/Plugin/migrate/process/EntityLookup.php @ 7:848c88cfe644

More layout
author Chris Cannam
date Fri, 05 Jan 2018 13:59:44 +0000
parents 4c8ae668cc8c
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /**
Chris@0 4 * @file
Chris@0 5 * Contains Drupal\migrate_plus\Plugin\migrate\process\EntityGenerate.
Chris@0 6 */
Chris@0 7
Chris@0 8 namespace Drupal\migrate_plus\Plugin\migrate\process;
Chris@0 9
Chris@0 10 use Drupal\Core\Entity\EntityManagerInterface;
Chris@0 11 use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface;
Chris@0 12 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
Chris@0 13 use Drupal\migrate\Plugin\MigrationInterface;
Chris@0 14 use Drupal\migrate\MigrateException;
Chris@0 15 use Drupal\migrate\MigrateExecutableInterface;
Chris@0 16 use Drupal\migrate\ProcessPluginBase;
Chris@0 17 use Drupal\migrate\Row;
Chris@0 18 use Symfony\Component\DependencyInjection\ContainerInterface;
Chris@0 19
Chris@0 20 /**
Chris@0 21 * This plugin looks for existing entities.
Chris@0 22 *
Chris@0 23 * @MigrateProcessPlugin(
Chris@0 24 * id = "entity_lookup",
Chris@0 25 * handle_multiples = TRUE
Chris@0 26 * )
Chris@0 27 *
Chris@0 28 * In its most simple form, this plugin needs no configuration. However, if the
Chris@0 29 * lookup properties cannot be determined through introspection, define them via
Chris@0 30 * configuration.
Chris@0 31 *
Chris@0 32 * Example usage with minimal configuration:
Chris@0 33 * @code
Chris@0 34 * destination:
Chris@0 35 * plugin: 'entity:node'
Chris@0 36 * process:
Chris@0 37 * type:
Chris@0 38 * plugin: default_value
Chris@0 39 * default_value: page
Chris@0 40 * field_tags:
Chris@0 41 * plugin: entity_lookup
Chris@0 42 * source: tags
Chris@0 43 * @endcode
Chris@0 44 *
Chris@0 45 * Example usage with full configuration:
Chris@0 46 * @code
Chris@0 47 * field_tags:
Chris@0 48 * plugin: entity_lookup
Chris@0 49 * source: tags
Chris@0 50 * value_key: name
Chris@0 51 * bundle_key: vid
Chris@0 52 * bundle: tags
Chris@0 53 * entity_type: taxonomy_term
Chris@0 54 * ignore_case: true
Chris@0 55 * @endcode
Chris@0 56 */
Chris@0 57 class EntityLookup extends ProcessPluginBase implements ContainerFactoryPluginInterface {
Chris@0 58
Chris@0 59 /** @var \Drupal\Core\Entity\EntityManagerInterface */
Chris@0 60 protected $entityManager;
Chris@0 61
Chris@0 62 /** @var \Drupal\migrate\Plugin\MigrationInterface */
Chris@0 63 protected $migration;
Chris@0 64
Chris@0 65 /** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface */
Chris@0 66 protected $selectionPluginManager;
Chris@0 67
Chris@0 68 /** @var string */
Chris@0 69 protected $destinationEntityType;
Chris@0 70
Chris@0 71 /** @var string|bool */
Chris@0 72 protected $destinationBundleKey;
Chris@0 73
Chris@0 74 /** @var string */
Chris@0 75 protected $lookupValueKey;
Chris@0 76
Chris@0 77 /** @var string */
Chris@0 78 protected $lookupBundleKey;
Chris@0 79
Chris@0 80 /** @var string */
Chris@0 81 protected $lookupBundle;
Chris@0 82
Chris@0 83 /** @var string */
Chris@0 84 protected $lookupEntityType;
Chris@0 85
Chris@0 86 /** @var string */
Chris@0 87 protected $destinationProperty;
Chris@0 88
Chris@0 89 /**
Chris@0 90 * {@inheritdoc}
Chris@0 91 */
Chris@0 92 public function __construct(array $configuration, $pluginId, $pluginDefinition, MigrationInterface $migration, EntityManagerInterface $entityManager, SelectionPluginManagerInterface $selectionPluginManager) {
Chris@0 93 parent::__construct($configuration, $pluginId, $pluginDefinition);
Chris@0 94 $this->migration = $migration;
Chris@0 95 $this->entityManager = $entityManager;
Chris@0 96 $this->selectionPluginManager = $selectionPluginManager;
Chris@0 97 $pluginIdParts = explode(':', $this->migration->getDestinationPlugin()->getPluginId());
Chris@0 98 $this->destinationEntityType = empty($pluginIdParts[1]) ?: $pluginIdParts[1];
Chris@0 99 $this->destinationBundleKey = !$this->destinationEntityType ?: $this->entityManager->getDefinition($this->destinationEntityType)->getKey('bundle');
Chris@0 100 }
Chris@0 101
Chris@0 102 /**
Chris@0 103 * {@inheritdoc}
Chris@0 104 */
Chris@0 105 public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition, MigrationInterface $migration = NULL) {
Chris@0 106 return new static(
Chris@0 107 $configuration,
Chris@0 108 $pluginId,
Chris@0 109 $pluginDefinition,
Chris@0 110 $migration,
Chris@0 111 $container->get('entity.manager'),
Chris@0 112 $container->get('plugin.manager.entity_reference_selection')
Chris@0 113 );
Chris@0 114 }
Chris@0 115
Chris@0 116 /**
Chris@0 117 * {@inheritdoc}
Chris@0 118 */
Chris@0 119 public function transform($value, MigrateExecutableInterface $migrateExecutable, Row $row, $destinationProperty) {
Chris@0 120 $this->determineLookupProperties($destinationProperty);
Chris@0 121
Chris@0 122 $this->destinationProperty = $this->configuration['destination_field'];
Chris@0 123
Chris@0 124 return $this->query($value);
Chris@0 125 }
Chris@0 126
Chris@0 127 /**
Chris@0 128 * Determine the lookup properties from config or target field configuration.
Chris@0 129 *
Chris@0 130 * @param string $destinationProperty
Chris@0 131 * The destination property currently worked on. This is only used together
Chris@0 132 * with the $row above.
Chris@0 133 */
Chris@0 134 protected function determineLookupProperties($destinationProperty) {
Chris@0 135 if (!empty($this->configuration['value_key'])) {
Chris@0 136 $this->lookupValueKey = $this->configuration['value_key'];
Chris@0 137 }
Chris@0 138 if (!empty($this->configuration['bundle_key'])) {
Chris@0 139 $this->lookupBundleKey = $this->configuration['bundle_key'];
Chris@0 140 }
Chris@0 141 if (!empty($this->configuration['bundle'])) {
Chris@0 142 $this->lookupBundle = $this->configuration['bundle'];
Chris@0 143 }
Chris@0 144 if (!empty($this->configuration['entity_type'])) {
Chris@0 145 $this->lookupEntityType = $this->configuration['entity_type'];
Chris@0 146 }
Chris@0 147
Chris@0 148 if (empty($this->lookupValueKey) || empty($this->lookupBundleKey) || empty($this->lookupBundle) || empty($this->lookupEntityType)) {
Chris@0 149 // See if we can introspect the lookup properties from the destination field.
Chris@0 150 if (!empty($this->migration->getProcess()[$this->destinationBundleKey][0]['default_value'])) {
Chris@0 151 $destinationEntityBundle = $this->migration->getProcess()[$this->destinationBundleKey][0]['default_value'];
Chris@0 152 $fieldConfig = $this->entityManager->getFieldDefinitions($this->destinationEntityType, $destinationEntityBundle)[$destinationProperty]->getConfig($destinationEntityBundle);
Chris@0 153 if ($fieldConfig->getType() != 'entity_reference') {
Chris@0 154 throw new MigrateException('The entity_lookup plugin found no entity reference field.');
Chris@0 155 }
Chris@0 156
Chris@0 157 if (empty($this->lookupBundle)) {
Chris@0 158 $handlerSettings = $fieldConfig->getSetting('handler_settings');
Chris@0 159 $bundles = array_filter((array) $handlerSettings['target_bundles']);
Chris@0 160 if (count($bundles) == 1) {
Chris@0 161 $this->lookupBundle = reset($bundles);
Chris@0 162 }
Chris@0 163 // This was added in 8.1.x is not supported in 8.0.x.
Chris@0 164 elseif (!empty($handlerSettings['auto_create']) && !empty($handlerSettings['auto_create_bundle'])) {
Chris@0 165 $this->lookupBundle = reset($handlerSettings['auto_create_bundle']);
Chris@0 166 }
Chris@0 167 }
Chris@0 168
Chris@0 169 // Make an assumption that if the selection handler can target more than
Chris@0 170 // one type of entity that we will use the first entity type.
Chris@0 171 $this->lookupEntityType = $this->lookupEntityType ?: reset($this->selectionPluginManager->createInstance($fieldConfig->getSetting('handler'))->getPluginDefinition()['entity_types']);
Chris@0 172 $this->lookupValueKey = $this->lookupValueKey ?: $this->entityManager->getDefinition($this->lookupEntityType)->getKey('label');
Chris@0 173 $this->lookupBundleKey = $this->lookupBundleKey ?: $this->entityManager->getDefinition($this->lookupEntityType)->getKey('bundle');
Chris@0 174 }
Chris@0 175 }
Chris@0 176
Chris@0 177 // If there aren't enough lookup properties available by now, then bail.
Chris@0 178 if (empty($this->lookupValueKey)) {
Chris@0 179 throw new MigrateException('The entity_lookup plugin requires a value_key, none located.');
Chris@0 180 }
Chris@0 181 if (!empty($this->lookupBundleKey) && empty($this->lookupBundle)) {
Chris@0 182 throw new MigrateException('The entity_lookup plugin found no bundle but destination entity requires one.');
Chris@0 183 }
Chris@0 184 if (empty($this->lookupEntityType)) {
Chris@0 185 throw new MigrateException('The entity_lookup plugin requires a entity_type, none located.');
Chris@0 186 }
Chris@0 187 }
Chris@0 188
Chris@0 189 /**
Chris@0 190 * Checks for the existence of some value.
Chris@0 191 *
Chris@0 192 * @param $value
Chris@0 193 * The value to query.
Chris@0 194 *
Chris@0 195 * @return mixed|null
Chris@0 196 * Entity id if the queried entity exists. Otherwise NULL.
Chris@0 197 */
Chris@0 198 protected function query($value) {
Chris@0 199 // Entity queries typically are case-insensitive. Therefore, we need to
Chris@0 200 // handle case sensitive filtering as a post-query step. By default, it
Chris@0 201 // filters case insensitive. Change to true if that is not the desired
Chris@0 202 // outcome.
Chris@0 203 $ignoreCase = !empty($this->configuration['ignore_case']) ?: FALSE;
Chris@0 204
Chris@0 205 $multiple = is_array($value);
Chris@0 206
Chris@0 207 $query = $this->entityManager->getStorage($this->lookupEntityType)
Chris@0 208 ->getQuery()
Chris@0 209 ->condition($this->lookupValueKey, $value, $multiple ? 'IN' : NULL);
Chris@0 210
Chris@0 211 if ($this->lookupBundleKey) {
Chris@0 212 $query->condition($this->lookupBundleKey, $this->lookupBundle);
Chris@0 213 }
Chris@0 214 $results = $query->execute();
Chris@0 215
Chris@0 216 if (empty($results)) {
Chris@0 217 return NULL;
Chris@0 218 }
Chris@0 219
Chris@0 220 if ($multiple && !empty($this->destinationProperty)) {
Chris@0 221 array_walk($results, function (&$value) {
Chris@0 222 $value = [$this->destinationProperty => $value];
Chris@0 223 });
Chris@0 224
Chris@0 225 return array_values($results);
Chris@0 226 }
Chris@0 227
Chris@0 228 // By default do a case-sensitive comparison.
Chris@0 229 if (!$ignoreCase) {
Chris@0 230 // Returns the entity's identifier.
Chris@0 231 foreach ($results as $identifier) {
Chris@0 232 if ($value === $this->entityManager->getStorage($this->lookupEntityType)->load($identifier)->{$this->lookupValueKey}->value) {
Chris@0 233 return $identifier;
Chris@0 234 }
Chris@0 235 }
Chris@0 236 }
Chris@0 237
Chris@0 238 return reset($results);
Chris@0 239 }
Chris@0 240
Chris@0 241 }