comparison modules/contrib/migrate_tools/src/MigrateExecutable.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
1 <?php
2
3 /**
4 * @file
5 * Contains \Drupal\migrate_tools\MigrateExecutable.
6 */
7
8 namespace Drupal\migrate_tools;
9
10 use Drupal\migrate\Event\MigratePreRowSaveEvent;
11 use Drupal\migrate\Event\MigrateRollbackEvent;
12 use Drupal\migrate\Event\MigrateRowDeleteEvent;
13 use Drupal\migrate\MigrateExecutable as MigrateExecutableBase;
14 use Drupal\migrate\MigrateMessageInterface;
15 use Drupal\migrate\Plugin\MigrationInterface;
16 use Drupal\migrate\MigrateSkipRowException;
17 use Drupal\migrate\Plugin\MigrateIdMapInterface;
18 use Drupal\migrate\Event\MigrateEvents;
19 use Drupal\migrate_plus\Event\MigrateEvents as MigratePlusEvents;
20 use Drupal\migrate\Event\MigrateMapSaveEvent;
21 use Drupal\migrate\Event\MigrateMapDeleteEvent;
22 use Drupal\migrate\Event\MigrateImportEvent;
23 use Drupal\migrate_plus\Event\MigratePrepareRowEvent;
24
25 class MigrateExecutable extends MigrateExecutableBase {
26
27 /**
28 * Counters of map statuses.
29 *
30 * @var array
31 * Set of counters, keyed by MigrateIdMapInterface::STATUS_* constant.
32 */
33 protected $saveCounters = array(
34 MigrateIdMapInterface::STATUS_FAILED => 0,
35 MigrateIdMapInterface::STATUS_IGNORED => 0,
36 MigrateIdMapInterface::STATUS_IMPORTED => 0,
37 MigrateIdMapInterface::STATUS_NEEDS_UPDATE => 0,
38 );
39
40 /**
41 * Counter of map deletions.
42 *
43 * @var int
44 */
45 protected $deleteCounter = 0;
46
47 /**
48 * Maximum number of items to process in this migration. 0 indicates no limit
49 * is to be applied.
50 *
51 * @var int
52 */
53 protected $itemLimit = 0;
54
55 /**
56 * Frequency (in items) at which progress messages should be emitted.
57 *
58 * @var int
59 */
60 protected $feedback = 0;
61
62 /**
63 * List of specific source IDs to import.
64 *
65 * @var array
66 */
67 protected $idlist = [];
68
69 /**
70 * Count of number of items processed so far in this migration.
71 * @var int
72 */
73 protected $counter = 0;
74
75 /**
76 * Whether the destination item exists before saving.
77 *
78 * @var bool
79 */
80 protected $preExistingItem = FALSE;
81
82 /**
83 * List of event listeners we have registered.
84 *
85 * @var array
86 */
87 protected $listeners = [];
88
89 /**
90 * {@inheritdoc}
91 */
92 public function __construct(MigrationInterface $migration, MigrateMessageInterface $message, array $options = []) {
93 parent::__construct($migration, $message);
94 if (isset($options['limit'])) {
95 $this->itemLimit = $options['limit'];
96 }
97 if (isset($options['feedback'])) {
98 $this->feedback = $options['feedback'];
99 }
100 if (isset($options['idlist'])) {
101 $this->idlist = explode(',', $options['idlist']);
102 }
103
104 $this->listeners[MigrateEvents::MAP_SAVE] = [$this, 'onMapSave'];
105 $this->listeners[MigrateEvents::MAP_DELETE] = [$this, 'onMapDelete'];
106 $this->listeners[MigrateEvents::POST_IMPORT] = [$this, 'onPostImport'];
107 $this->listeners[MigrateEvents::POST_ROLLBACK] = [$this, 'onPostRollback'];
108 $this->listeners[MigrateEvents::PRE_ROW_SAVE] = [$this, 'onPreRowSave'];
109 $this->listeners[MigrateEvents::POST_ROW_DELETE] = [$this, 'onPostRowDelete'];
110 $this->listeners[MigratePlusEvents::PREPARE_ROW] = [$this, 'onPrepareRow'];
111 foreach ($this->listeners as $event => $listener) {
112 \Drupal::service('event_dispatcher')->addListener($event, $listener);
113 }
114 }
115
116 /**
117 * Count up any map save events.
118 *
119 * @param \Drupal\migrate\Event\MigrateMapSaveEvent $event
120 * The map event.
121 */
122 public function onMapSave(MigrateMapSaveEvent $event) {
123 // Only count saves for this migration.
124 if ($event->getMap()->getQualifiedMapTableName() == $this->migration->getIdMap()->getQualifiedMapTableName()) {
125 $fields = $event->getFields();
126 // Distinguish between creation and update.
127 if ($fields['source_row_status'] == MigrateIdMapInterface::STATUS_IMPORTED &&
128 $this->preExistingItem
129 ) {
130 $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE]++;
131 }
132 else {
133 $this->saveCounters[$fields['source_row_status']]++;
134 }
135 }
136 }
137
138 /**
139 * Count up any rollback events.
140 *
141 * @param \Drupal\migrate\Event\MigrateMapDeleteEvent $event
142 * The map event.
143 */
144 public function onMapDelete(MigrateMapDeleteEvent $event) {
145 $this->deleteCounter++;
146 }
147
148 /**
149 * Return the number of items created.
150 *
151 * @return int
152 */
153 public function getCreatedCount() {
154 return $this->saveCounters[MigrateIdMapInterface::STATUS_IMPORTED];
155 }
156
157 /**
158 * Return the number of items updated.
159 *
160 * @return int
161 */
162 public function getUpdatedCount() {
163 return $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE];
164 }
165
166 /**
167 * Return the number of items ignored.
168 *
169 * @return int
170 */
171 public function getIgnoredCount() {
172 return $this->saveCounters[MigrateIdMapInterface::STATUS_IGNORED];
173 }
174
175 /**
176 * Return the number of items that failed.
177 *
178 * @return int
179 */
180 public function getFailedCount() {
181 return $this->saveCounters[MigrateIdMapInterface::STATUS_FAILED];
182 }
183
184 /**
185 * Return the total number of items processed. Note that STATUS_NEEDS_UPDATE
186 * is not counted, since this is typically set on stubs created as side
187 * effects, not on the primary item being imported.
188 *
189 * @return int
190 */
191 public function getProcessedCount() {
192 return $this->saveCounters[MigrateIdMapInterface::STATUS_IMPORTED] +
193 $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE] +
194 $this->saveCounters[MigrateIdMapInterface::STATUS_IGNORED] +
195 $this->saveCounters[MigrateIdMapInterface::STATUS_FAILED];
196 }
197
198 /**
199 * Return the number of items rolled back.
200 *
201 * @return int
202 */
203 public function getRollbackCount() {
204 return $this->deleteCounter;
205 }
206
207 /**
208 * Reset all the per-status counters to 0.
209 */
210 protected function resetCounters() {
211 foreach ($this->saveCounters as $status => $count) {
212 $this->saveCounters[$status] = 0;
213 }
214 $this->deleteCounter = 0;
215 }
216
217 /**
218 * React to migration completion.
219 *
220 * @param \Drupal\migrate\Event\MigrateImportEvent $event
221 * The map event.
222 */
223 public function onPostImport(MigrateImportEvent $event) {
224 $migrate_last_imported_store = \Drupal::keyValue('migrate_last_imported');
225 $migrate_last_imported_store->set($event->getMigration()->id(), round(microtime(TRUE) * 1000));
226 $this->progressMessage();
227 $this->removeListeners();
228 }
229
230 /**
231 * Clean up all our event listeners.
232 */
233 protected function removeListeners() {
234 foreach ($this->listeners as $event => $listener) {
235 \Drupal::service('event_dispatcher')->removeListener($event, $listener);
236 }
237 }
238
239 /**
240 * Emit information on what we've done since the last feedback (or the
241 * beginning of this migration).
242 *
243 * @param bool $done
244 */
245 protected function progressMessage($done = TRUE) {
246 $processed = $this->getProcessedCount();
247 if ($done) {
248 $singular_message = "Processed 1 item (@created created, @updated updated, @failures failed, @ignored ignored) - done with '@name'";
249 $plural_message = "Processed @numitems items (@created created, @updated updated, @failures failed, @ignored ignored) - done with '@name'";
250 }
251 else {
252 $singular_message = "Processed 1 item (@created created, @updated updated, @failures failed, @ignored ignored) - continuing with '@name'";
253 $plural_message = "Processed @numitems items (@created created, @updated updated, @failures failed, @ignored ignored) - continuing with '@name'";
254 }
255 $this->message->display(\Drupal::translation()->formatPlural($processed,
256 $singular_message, $plural_message,
257 array('@numitems' => $processed,
258 '@created' => $this->getCreatedCount(),
259 '@updated' => $this->getUpdatedCount(),
260 '@failures' => $this->getFailedCount(),
261 '@ignored' => $this->getIgnoredCount(),
262 '@name' => $this->migration->id())));
263 }
264
265 /**
266 * React to rollback completion.
267 *
268 * @param \Drupal\migrate\Event\MigrateRollbackEvent $event
269 * The map event.
270 */
271 public function onPostRollback(MigrateRollbackEvent $event) {
272 $this->rollbackMessage();
273 $this->removeListeners();
274 }
275
276 /**
277 * Emit information on what we've done since the last feedback (or the
278 * beginning of this migration).
279 *
280 * @param bool $done
281 */
282 protected function rollbackMessage($done = TRUE) {
283 $rolled_back = $this->getRollbackCount();
284 if ($done) {
285 $singular_message = "Rolled back 1 item - done with '@name'";
286 $plural_message = "Rolled back @numitems items - done with '@name'";
287 }
288 else {
289 $singular_message = "Rolled back 1 item - continuing with '@name'";
290 $plural_message = "Rolled back @numitems items - continuing with '@name'";
291 }
292 $this->message->display(\Drupal::translation()->formatPlural($rolled_back,
293 $singular_message, $plural_message,
294 array('@numitems' => $rolled_back,
295 '@name' => $this->migration->id())));
296 }
297
298 /**
299 * React to an item about to be imported.
300 *
301 * @param \Drupal\migrate\Event\MigratePreRowSaveEvent $event
302 * The pre-save event.
303 */
304 public function onPreRowSave(MigratePreRowSaveEvent $event) {
305 $id_map = $event->getRow()->getIdMap();
306 if (!empty($id_map['destid1'])) {
307 $this->preExistingItem = TRUE;
308 }
309 else {
310 $this->preExistingItem = FALSE;
311 }
312 }
313
314 /**
315 * React to item rollback.
316 *
317 * @param \Drupal\migrate\Event\MigrateRowDeleteEvent $event
318 * The post-save event.
319 */
320 public function onPostRowDelete(MigrateRowDeleteEvent $event) {
321 if ($this->feedback && ($this->deleteCounter) && $this->deleteCounter % $this->feedback == 0) {
322 $this->rollbackMessage(FALSE);
323 $this->resetCounters();
324 }
325 }
326
327 /**
328 * React to a new row.
329 *
330 * @param \Drupal\migrate_plus\Event\MigratePrepareRowEvent $event
331 * The prepare-row event.
332 *
333 * @throws \Drupal\migrate\MigrateSkipRowException
334 *
335 */
336 public function onPrepareRow(MigratePrepareRowEvent $event) {
337 if ($this->idlist) {
338 $row = $event->getRow();
339 $source_id = $row->getSourceIdValues();
340 if (!in_array(reset($source_id), $this->idlist)) {
341 throw new MigrateSkipRowException(NULL, FALSE);
342 }
343 }
344 if ($this->feedback && ($this->counter) && $this->counter % $this->feedback == 0) {
345 $this->progressMessage(FALSE);
346 $this->resetCounters();
347 }
348 $this->counter++;
349 if ($this->itemLimit && $this->counter >= $this->itemLimit) {
350 $event->getMigration()->interruptMigration(MigrationInterface::RESULT_COMPLETED);
351 }
352
353 }
354
355 }