View source
<?php
namespace Drupal\migrate_tools;
use Drupal\migrate\Event\MigrateEvents;
use Drupal\migrate\Event\MigrateImportEvent;
use Drupal\migrate\Event\MigrateMapDeleteEvent;
use Drupal\migrate\Event\MigrateMapSaveEvent;
use Drupal\migrate\Event\MigratePreRowSaveEvent;
use Drupal\migrate\Event\MigrateRollbackEvent;
use Drupal\migrate\Event\MigrateRowDeleteEvent;
use Drupal\migrate\MigrateExecutable as MigrateExecutableBase;
use Drupal\migrate\MigrateMessageInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate_plus\Event\MigrateEvents as MigratePlusEvents;
use Drupal\migrate_plus\Event\MigratePrepareRowEvent;
class MigrateExecutable extends MigrateExecutableBase {
protected $saveCounters = [
MigrateIdMapInterface::STATUS_FAILED => 0,
MigrateIdMapInterface::STATUS_IGNORED => 0,
MigrateIdMapInterface::STATUS_IMPORTED => 0,
MigrateIdMapInterface::STATUS_NEEDS_UPDATE => 0,
];
protected $itemLimitCounter = 0;
protected $deleteCounter = 0;
protected $itemLimit = 0;
protected $feedback = 0;
protected $idlist = [];
protected $counter = 0;
protected $preExistingItem = FALSE;
protected $listeners = [];
public function __construct(MigrationInterface $migration, MigrateMessageInterface $message, array $options = []) {
parent::__construct($migration, $message);
if (isset($options['limit'])) {
$this->itemLimit = $options['limit'];
}
if (isset($options['feedback'])) {
$this->feedback = $options['feedback'];
}
if (isset($options['sync'])) {
$this->migration
->set('syncSource', $options['sync']);
}
$this->idlist = MigrateTools::buildIdList($options);
$this->listeners[MigrateEvents::MAP_SAVE] = [
$this,
'onMapSave',
];
$this->listeners[MigrateEvents::MAP_DELETE] = [
$this,
'onMapDelete',
];
$this->listeners[MigrateEvents::POST_IMPORT] = [
$this,
'onPostImport',
];
$this->listeners[MigrateEvents::POST_ROLLBACK] = [
$this,
'onPostRollback',
];
$this->listeners[MigrateEvents::PRE_ROW_SAVE] = [
$this,
'onPreRowSave',
];
$this->listeners[MigrateEvents::POST_ROW_DELETE] = [
$this,
'onPostRowDelete',
];
$this->listeners[MigratePlusEvents::PREPARE_ROW] = [
$this,
'onPrepareRow',
];
foreach ($this->listeners as $event => $listener) {
$this
->getEventDispatcher()
->addListener($event, $listener);
}
}
public function onMapSave(MigrateMapSaveEvent $event) {
if ($event
->getMap()
->getQualifiedMapTableName() == $this->migration
->getIdMap()
->getQualifiedMapTableName()) {
$fields = $event
->getFields();
$this->itemLimitCounter++;
if ($fields['source_row_status'] == MigrateIdMapInterface::STATUS_IMPORTED && $this->preExistingItem) {
$this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE]++;
}
else {
$this->saveCounters[$fields['source_row_status']]++;
}
}
}
public function onMapDelete(MigrateMapDeleteEvent $event) {
$this->deleteCounter++;
}
public function getCreatedCount() {
return $this->saveCounters[MigrateIdMapInterface::STATUS_IMPORTED];
}
public function getUpdatedCount() {
return $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE];
}
public function getIgnoredCount() {
return $this->saveCounters[MigrateIdMapInterface::STATUS_IGNORED];
}
public function getFailedCount() {
return $this->saveCounters[MigrateIdMapInterface::STATUS_FAILED];
}
public function getProcessedCount() {
return $this->saveCounters[MigrateIdMapInterface::STATUS_IMPORTED] + $this->saveCounters[MigrateIdMapInterface::STATUS_NEEDS_UPDATE] + $this->saveCounters[MigrateIdMapInterface::STATUS_IGNORED] + $this->saveCounters[MigrateIdMapInterface::STATUS_FAILED];
}
public function getRollbackCount() {
return $this->deleteCounter;
}
protected function resetCounters() {
foreach ($this->saveCounters as $status => $count) {
$this->saveCounters[$status] = 0;
}
$this->deleteCounter = 0;
}
public function onPostImport(MigrateImportEvent $event) {
$migrate_last_imported_store = \Drupal::keyValue('migrate_last_imported');
$migrate_last_imported_store
->set($event
->getMigration()
->id(), round(\Drupal::time()
->getCurrentMicroTime() * 1000));
$this
->progressMessage();
$this
->removeListeners();
}
protected function removeListeners() {
foreach ($this->listeners as $event => $listener) {
if ($event !== MigrateEvents::POST_IMPORT && $event !== MigrateEvents::POST_ROLLBACK) {
$this
->getEventDispatcher()
->removeListener($event, $listener);
}
}
}
protected function progressMessage($done = TRUE) {
$processed = $this
->getProcessedCount();
if ($done) {
$singular_message = "Processed 1 item (@created created, @updated updated, @failures failed, @ignored ignored) - done with '@name'";
$plural_message = "Processed @numitems items (@created created, @updated updated, @failures failed, @ignored ignored) - done with '@name'";
}
else {
$singular_message = "Processed 1 item (@created created, @updated updated, @failures failed, @ignored ignored) - continuing with '@name'";
$plural_message = "Processed @numitems items (@created created, @updated updated, @failures failed, @ignored ignored) - continuing with '@name'";
}
$this->message
->display(\Drupal::translation()
->formatPlural($processed, $singular_message, $plural_message, [
'@numitems' => $processed,
'@created' => $this
->getCreatedCount(),
'@updated' => $this
->getUpdatedCount(),
'@failures' => $this
->getFailedCount(),
'@ignored' => $this
->getIgnoredCount(),
'@name' => $this->migration
->id(),
]));
}
public function onPostRollback(MigrateRollbackEvent $event) {
$migrate_last_imported_store = \Drupal::keyValue('migrate_last_imported');
$migrate_last_imported_store
->set($event
->getMigration()
->id(), FALSE);
$this
->rollbackMessage();
if (empty($event
->getMigration()->syncSource)) {
$this
->removeListeners();
}
}
protected function rollbackMessage($done = TRUE) {
$rolled_back = $this
->getRollbackCount();
if ($done) {
$singular_message = "Rolled back 1 item - done with '@name'";
$plural_message = "Rolled back @numitems items - done with '@name'";
}
else {
$singular_message = "Rolled back 1 item - continuing with '@name'";
$plural_message = "Rolled back @numitems items - continuing with '@name'";
}
$this->message
->display(\Drupal::translation()
->formatPlural($rolled_back, $singular_message, $plural_message, [
'@numitems' => $rolled_back,
'@name' => $this->migration
->id(),
]));
}
public function onPreRowSave(MigratePreRowSaveEvent $event) {
$id_map = $event
->getRow()
->getIdMap();
if (!empty($id_map['destid1'])) {
$this->preExistingItem = TRUE;
}
else {
$this->preExistingItem = FALSE;
}
}
public function onPostRowDelete(MigrateRowDeleteEvent $event) {
if ($this->feedback && $this->deleteCounter && $this->deleteCounter % $this->feedback == 0) {
$this
->rollbackMessage(FALSE);
$this
->resetCounters();
}
}
public function onPrepareRow(MigratePrepareRowEvent $event) {
if ($this->feedback && $this->counter && $this->counter % $this->feedback == 0) {
$this
->progressMessage(FALSE);
$this
->resetCounters();
}
$this->counter++;
if ($this->itemLimit && $this->itemLimitCounter + 1 >= $this->itemLimit) {
$event
->getMigration()
->interruptMigration(MigrationInterface::RESULT_COMPLETED);
}
}
protected function getSource() {
return new SourceFilter(parent::getSource(), $this->idlist);
}
protected function getIdMap() {
return new IdMapFilter(parent::getIdMap(), $this->idlist);
}
}