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 }
|