diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e0ad46e295f23de4f6927044a9cb3a6e0bc3ae06..b686610940ca2602ec3c7fbc6c7d1ca95805e827 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -65,11 +65,8 @@ variables: # Broaden test coverage. OPT_IN_TEST_PREVIOUS_MAJOR: 1 OPT_IN_TEST_MAX_PHP: 1 - OPT_IN_TEST_PREVIOUS_MINOR: 1 OPT_IN_TEST_NEXT_MINOR: 1 OPT_IN_TEST_NEXT_MAJOR: 1 - # Show more log output - _PHPUNIT_EXTRA: --verbose # Convenient, and we have no secrets. _SHOW_ENVIRONMENT_VARIABLES: 1 diff --git a/composer.json b/composer.json index 30e744da38c62c7c6a1da8b0fe11c6d85c21bced..563e44775c856af9758a58a4dd8bab193ebc6891 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "source": "https://git.drupalcode.org/project/migrate_tools" }, "license": "GPL-2.0-or-later", - "minimum-stability": "dev", + "minimum-stability": "stable", "prefer-stable": false, "config": { "preferred-install": "dist" diff --git a/migrate_tools.install b/migrate_tools.install new file mode 100644 index 0000000000000000000000000000000000000000..c8ae3ad567a3d567a19dcb9263747c0fceb160e5 --- /dev/null +++ b/migrate_tools.install @@ -0,0 +1,48 @@ +<?php + +/** + * Implements hook_schema(). + */ +function migrate_tools_schema(): array { + $schema['migrate_tools_sync_source_ids'] = [ + 'description' => 'Table storing SyncSourceIds entries for the --sync option.', + 'fields' => [ + 'id' => array( + 'description' => 'Primary Key: Unique ID.', + 'type' => 'serial', + 'not null' => TRUE, + ), + 'migration_id' => [ + 'description' => 'The migration ID.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + ], + 'source_ids' => [ + 'description' => 'Array of source IDs, in the same order as defined in \Drupal\migrate\Row::$sourceIds.', + 'type' => 'blob', + // "normal" size for "blob" is 16KB on MySQL, and 4GB or unlimited on + // other DBMS. That should more than enough for a single set of IDs. + // @see https://www.drupal.org/node/159605 + 'size' => 'normal', + 'not null' => TRUE, + 'serialize' => TRUE, + ], + ], + 'indexes' => [ + 'migration_id' => ['migration_id'], + ], + 'primary key' => ['id'], + ]; + return $schema; +} + +/** + * Adds a table in the database dedicated to SyncSourceIds entries. + */ +function migrate_tools_update_10000(): void { + $schema = migrate_tools_schema(); + foreach($schema as $tableName => $schemaDefinition) { + \Drupal::database()->schema()->createTable($tableName, $schemaDefinition); + } +} diff --git a/migrate_tools.module b/migrate_tools.module index a0c9da4552873347ffe663606c9410cb906df62b..8a9ffb5fe23cfdd1ef17b662f80e5d86a8d442d4 100644 --- a/migrate_tools.module +++ b/migrate_tools.module @@ -23,6 +23,7 @@ use Drupal\migrate_tools\Form\MigrationEditForm; use Drupal\migrate_tools\Form\MigrationGroupAddForm; use Drupal\migrate_tools\Form\MigrationGroupDeleteForm; use Drupal\migrate_tools\Form\MigrationGroupEditForm; +use Drupal\migrate_tools\MigrateTools; /** * Implements hook_entity_type_build(). @@ -55,7 +56,7 @@ function migrate_tools_entity_type_build(array &$entity_types): void { /** * Implements hook_menu_links_discovered_alter(). */ -function migrate_tools_menu_links_discovered_alter(&$links) { +function migrate_tools_menu_links_discovered_alter(&$links): void { if (\Drupal::moduleHandler()->moduleExists('migrate_plus')) { $links['migrate_tools.menu'] = [ 'title' => 'Migrations', @@ -82,19 +83,20 @@ function migrate_tools_migration_plugins_alter(array &$migrations): void { /** * Implements hook_migrate_prepare_row(). * + * @throws \Exception + * * @see \Drupal\migrate_tools\EventSubscriber\MigrationImportSync * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase::next() */ -function migrate_tools_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) { - - if (!empty($migration->syncSource)) { +function migrate_tools_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration): void { + /** @var MigrateTools $migrateTools */ + $migrateTools = \Drupal::service('migrate_tools.migrate_tools'); + // Act on migrations that have a Sync source, and that are currently in the + // phase of Syncing their IDs. + if (!empty($migration->syncSource) && $migrateTools->isMigrationSyncing($migration->getPluginId())) { // Keep track of all source rows here, as SourcePluginBase::next() might // skip some rows, and we need them all to detect missing items in source to // delete in destination. - $source_id_values = \Drupal::state()->get('migrate_tools_sync', []); - - $source_id_values[] = $row->getSourceIdValues(); - - \Drupal::state()->set('migrate_tools_sync', $source_id_values); + $migrateTools->addToSyncSourceIds($migration->getPluginId(), $row->getSourceIdValues()); } } diff --git a/migrate_tools.routing.yml b/migrate_tools.routing.yml index bfe0d1319bac2fc49c59788acd0449d80f62082b..dc569aa2e581623fda712a33d4c04fa1879ed2d4 100644 --- a/migrate_tools.routing.yml +++ b/migrate_tools.routing.yml @@ -80,20 +80,6 @@ entity.migration.process: type: entity:migration migration_group: type: entity:migration_group -entity.migration.process.run: - path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/process/run' - defaults: - _controller: '\Drupal\migrate_tools\Controller\MigrationController::run' - _title: 'Run' - _migrate_group: true - requirements: - _permission: 'administer migrations' - options: - parameters: - migration: - type: entity:migration - migration_group: - type: entity:migration_group entity.migration.destination: path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/destination' defaults: diff --git a/migrate_tools.services.yml b/migrate_tools.services.yml index 9aeebf450ac53a2445034b5c73eb18bcc812baaa..e00705d7473a970f28fe0bda7dbf111e48cb8ef7 100644 --- a/migrate_tools.services.yml +++ b/migrate_tools.services.yml @@ -19,7 +19,7 @@ services: - { name: event_subscriber } arguments: - '@event_dispatcher' - - '@state' + - '@migrate_tools.migrate_tools' plugin.manager.migrate_shared_config: class: Drupal\migrate_tools\MigrateSharedConfigPluginManager @@ -28,3 +28,7 @@ services: migrate_tools.shared_config_include_handler: class: Drupal\migrate_tools\MigrateIncludeHandler arguments: ['@plugin.manager.migrate_shared_config'] + + migrate_tools.migrate_tools: + class: Drupal\migrate_tools\MigrateTools + arguments: ['@database'] diff --git a/src/Controller/MessageController.php b/src/Controller/MessageController.php index aeaffa85d8878caa36347014def169bd1e6cdbc9..fd283428427b6cbffe2ef13f30955909b2864c2e 100644 --- a/src/Controller/MessageController.php +++ b/src/Controller/MessageController.php @@ -10,11 +10,11 @@ use Drupal\Core\Database\Connection; use Drupal\Core\Database\Query\PagerSelectExtender; use Drupal\Core\Database\Query\TableSortExtender; use Drupal\Core\StringTranslation\TranslatableMarkup; -use Drupal\migrate\Plugin\MigrateIdMapInterface; use Drupal\migrate\Plugin\MigrationInterface; use Drupal\migrate\Plugin\MigrationPluginManagerInterface; use Drupal\migrate_plus\Entity\MigrationGroupInterface; use Drupal\migrate_plus\Entity\MigrationInterface as MigratePlusMigrationInterface; +use Drupal\migrate_tools\MigrateTools; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -92,6 +92,7 @@ class MessageController extends ControllerBase { $build = []; $rows = []; $classes = static::getLogLevelClassMap(); + /** @var \Drupal\migrate\Plugin\MigrationInterface $migration_plugin */ $migration_plugin = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray()); $source_id_field_names = array_keys($migration_plugin->getSourcePlugin()->getIds()); $column_number = 1; @@ -111,6 +112,10 @@ class MessageController extends ControllerBase { 'data' => $this->t('Message'), 'field' => 'message', ]; + $header[] = [ + 'data' => $this->t('Destination ID'), + 'field' => 'destid', + ]; $header[] = [ 'data' => $this->t('Status'), 'field' => 'source_row_status', @@ -132,27 +137,38 @@ class MessageController extends ControllerBase { ->execute(); } - $status_strings = [ - MigrateIdMapInterface::STATUS_IMPORTED => $this->t('Imported'), - MigrateIdMapInterface::STATUS_NEEDS_UPDATE => $this->t('Pending'), - MigrateIdMapInterface::STATUS_IGNORED => $this->t('Ignored'), - MigrateIdMapInterface::STATUS_FAILED => $this->t('Failed'), - ]; + $level_mapping = MigrateTools::getLogLevelLabelMapping(); + $status_mapping = MigrateTools::getStatusLevelLabelMapping(); foreach ($result as $message_row) { $column_number = 1; + $data = []; foreach ($source_id_field_names as $source_id_field_name) { $column_name = 'sourceid' . $column_number++; - $row[$column_name] = $message_row->$column_name; + $data[$column_name] = $message_row->$column_name; } - $row['level'] = $message_row->level; - $row['message'] = $message_row->message; - $row['status'] = $status_strings[$message_row->source_row_status]; - $row['class'] = [ - Html::getClass('migrate-message-' . $message_row->level), - $classes[$message_row->level], + $data['level'] = $level_mapping[$message_row->level] ?: $message_row->level; + $data['message'] = $message_row->message; + $column_number = 1; + foreach ($migration_plugin->getDestinationPlugin()->getIds() as $dest_id_field_name => $dest_id_schema) { + $column_name = 'destid' . $column_number++; + $data['destid']['data'][] = $message_row->$column_name; + $data['destid']['#destination_fields'][$dest_id_field_name] = + $data['destid']['#destination_fields'][$column_name] = $message_row->$column_name; + } + $destid = array_filter($data['destid']['data']); + $data['destid']['data'] = [ + '#markup' => $destid ? implode(MigrateTools::DEFAULT_ID_LIST_DELIMITER, $data['destid']['data']) : '', + ]; + + $data['status'] = $status_mapping[$message_row->source_row_status]; + $rows[] = [ + 'class' => [ + Html::getClass('migrate-message-' . $message_row->level), + $classes[$message_row->level], + ], + 'data' => $data, ]; - $rows[] = $row; } $build['message_table'] = [ diff --git a/src/Controller/MigrationController.php b/src/Controller/MigrationController.php index 37bc7e86e9c6b09945722242e19477d93e0588b6..4ab1e5318a75666b71368abb8c2455a28ceb90c8 100644 --- a/src/Controller/MigrationController.php +++ b/src/Controller/MigrationController.php @@ -159,32 +159,6 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn return $build; } - /** - * Run a migration. - * - * @param \Drupal\migrate_plus\Entity\MigrationGroupInterface $migration_group - * The migration group. - * @param \Drupal\migrate_plus\Entity\MigrationInterface $migration - * The $migration. - * - * @return \Symfony\Component\HttpFoundation\RedirectResponse|null - * A redirect response if the batch is progressive. Else no return value. - */ - public function run(MigrationGroupInterface $migration_group, MigrationInterface $migration): ?RedirectResponse { - $migrateMessage = new MigrateMessage(); - $options = []; - - $migration_plugin = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray()); - $executable = new MigrateBatchExecutable($migration_plugin, $migrateMessage, $options); - $executable->batchImport(); - - $route_parameters = [ - 'migration_group' => $migration_group, - 'migration' => $migration->id(), - ]; - return batch_process(Url::fromRoute('entity.migration.process', $route_parameters)); - } - /** * Display process information of a migration entity. * @@ -251,15 +225,6 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn '#empty' => $this->t('No process defined.'), ]; - $build['process']['run'] = [ - '#type' => 'link', - '#title' => $this->t('Run'), - '#url' => Url::fromRoute('entity.migration.process.run', [ - 'migration_group' => $migration_group->id(), - 'migration' => $migration->id(), - ]), - ]; - return $build; } diff --git a/src/Drush/Commands/MigrateToolsCommands.php b/src/Drush/Commands/MigrateToolsCommands.php index dc4c5ac32d62702614d9cb0b1842d561d4671e99..460f2fcf1f97005fa6b08045298ba369c32d7da9 100644 --- a/src/Drush/Commands/MigrateToolsCommands.php +++ b/src/Drush/Commands/MigrateToolsCommands.php @@ -601,7 +601,7 @@ class MigrateToolsCommands extends DrushCommands { // If any rollbacks failed, throw an exception to generate exit status. if ($has_failure) { - $error_message = \dt('!name migration failed.', ['!name' => $errored_migration_id]); + $error_message = \dt('@name migration failed.', ['@name' => $errored_migration_id]); if ($options['continue-on-failure']) { $this->logger()->error($error_message); } @@ -799,6 +799,7 @@ class MigrateToolsCommands extends DrushCommands { } $table = []; + $level_mapping = MigrateTools::getLogLevelLabelMapping(); foreach ($map->getMessages() as $row) { unset($row->msgid); $array_row = (array) $row; @@ -815,8 +816,9 @@ class MigrateToolsCommands extends DrushCommands { $destination_ids[$name] = $item; } } - $array_row['source_ids'] = implode(':', $source_ids); - $array_row['destination_ids'] = implode(':', $destination_ids); + $array_row['level'] = $level_mapping[$array_row['level']]; + $array_row['source_ids'] = implode(MigrateTools::DEFAULT_ID_LIST_DELIMITER, $source_ids); + $array_row['destination_ids'] = array_filter($destination_ids) ? implode(MigrateTools::DEFAULT_ID_LIST_DELIMITER, $destination_ids) : ''; $table[] = $array_row; } if (empty($table)) { @@ -1104,12 +1106,12 @@ class MigrateToolsCommands extends DrushCommands { $executed_migrations += [$migration_id => $migration_id]; if ($count = $executable->getFailedCount()) { $error_message = \dt( - '!name Migration - !count failed.', - ['!name' => $migration_id, '!count' => $count] + '@name Migration - @count failed.', + ['@name' => $migration_id, '@count' => $count] ); } elseif ($result == MigrationInterface::RESULT_FAILED) { - $error_message = \dt('!name migration failed.', ['!name' => $migration_id]); + $error_message = \dt('@name migration failed.', ['@name' => $migration_id]); } else { $error_message = ''; diff --git a/src/EventSubscriber/MigrationImportSync.php b/src/EventSubscriber/MigrationImportSync.php index b7e5288b1912990ef2fcec9dd56c46e6d92ced8a..79cd9c4671522dc65845e2c50ce8301821f3ae69 100644 --- a/src/EventSubscriber/MigrationImportSync.php +++ b/src/EventSubscriber/MigrationImportSync.php @@ -11,6 +11,7 @@ use Drupal\migrate\Event\MigrateRollbackEvent; use Drupal\migrate\Event\MigrateRowDeleteEvent; use Drupal\migrate\Plugin\MigrationInterface; use Drupal\migrate_plus\Event\MigrateEvents as MigratePlusEvents; +use Drupal\migrate_tools\MigrateTools; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -25,26 +26,17 @@ class MigrationImportSync implements EventSubscriberInterface { * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface */ protected EventDispatcherInterface $dispatcher; - - /** - * The state key/value store. - * - * @var \Drupal\Core\State\StateInterface - */ - protected StateInterface $state; + protected MigrateTools $migrateTools; /** * MigrationImportSync constructor. * * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher * The event dispatcher. - * @param Drupal\Core\State\StateInterface $state - * The Key/Value Store to use for tracking synced source rows. */ - public function __construct(EventDispatcherInterface $dispatcher, StateInterface $state) { + public function __construct(EventDispatcherInterface $dispatcher, MigrateTools $migrateTools) { $this->dispatcher = $dispatcher; - $this->state = $state; - $this->state->set('migrate_tools_sync', []); + $this->migrateTools = $migrateTools; } /** @@ -53,6 +45,7 @@ class MigrationImportSync implements EventSubscriberInterface { public static function getSubscribedEvents(): array { $events = []; $events[MigrateEvents::PRE_IMPORT][] = ['sync']; + $events[MigrateEvents::POST_IMPORT][] = ['cleanSyncData']; return $events; } @@ -61,10 +54,18 @@ class MigrationImportSync implements EventSubscriberInterface { * * @param \Drupal\migrate\Event\MigrateImportEvent $event * The migration import event. + * + * @throws \Exception */ public function sync(MigrateImportEvent $event): void { $migration = $event->getMigration(); if (!empty($migration->syncSource)) { + $migrationId = $migration->getPluginId(); + // Clear Sync IDs for this migration before starting preparing rows. + $this->migrateTools->clearSyncSourceIds($migrationId); + // Activate the syncing state for this migration, so + // migrate_tools_migrate_prepare_row() can record all IDs. + $this->migrateTools->setMigrationSyncingState($migrationId, TRUE); // Loop through the source to register existing source ids. // @see migrate_tools_migrate_prepare_row(). @@ -76,7 +77,12 @@ class MigrationImportSync implements EventSubscriberInterface { $source->next(); } - $source_id_values = $this->state->get('migrate_tools_sync', []); + // Deactivate the syncing state for this migration, so + // migrate_tools_migrate_prepare_row() does not record any further IDs + // during the actual migration process. + $this->migrateTools->setMigrationSyncingState($migrationId, FALSE); + + $source_id_values = $this->migrateTools->getSyncSourceIds($migrationId); $id_map = $migration->getIdMap(); $id_map->rewind(); @@ -112,6 +118,18 @@ class MigrationImportSync implements EventSubscriberInterface { } } + /** + * Cleans Sync data after a migration is complete. + * + * @param \Drupal\migrate\Event\MigrateImportEvent $event + * The migration import event. + */ + public function cleanSyncData(MigrateImportEvent $event): void { + $migration = $event->getMigration(); + $migrationId = $migration->getPluginId(); + $this->migrateTools->clearSyncSourceIds($migrationId); + } + /** * Dispatches MigrateRowDeleteEvent event. * diff --git a/src/Form/MigrationExecuteForm.php b/src/Form/MigrationExecuteForm.php index 0af2e205faf43883d9863589b457756d626963c3..be6f0f1bc283091867289e5ca965a5c3834419b7 100644 --- a/src/Form/MigrationExecuteForm.php +++ b/src/Form/MigrationExecuteForm.php @@ -202,7 +202,7 @@ class MigrationExecuteForm extends FormBase { $this->messenger()->addStatus($this->t('Rollback completed', ['@id' => $migration_id])); } else { - $this->messenger()->addError($this->t('Rollback of !name migration failed.', ['!name' => $migration_id])); + $this->messenger()->addError($this->t('Rollback of @name migration failed.', ['@name' => $migration_id])); } break; diff --git a/src/MigrateTools.php b/src/MigrateTools.php index 2e1f70d024e6efdbc1437d512a7fa47206c9810f..526f3d95d01aaa1f6a66dceac0704089a878bd30 100644 --- a/src/MigrateTools.php +++ b/src/MigrateTools.php @@ -4,6 +4,10 @@ declare(strict_types=1); namespace Drupal\migrate_tools; +use Drupal\Core\Database\Connection; +use Drupal\migrate\Plugin\MigrateIdMapInterface; +use Drupal\migrate\Plugin\MigrationInterface; + /** * Utility functionality for use in migrate_tools. */ @@ -14,6 +18,39 @@ class MigrateTools { */ public const DEFAULT_ID_LIST_DELIMITER = ':'; + /** + * Maximum number of source IDs to keep in memory before flushing them + * to database. + */ + protected const MAX_BUFFERED_SYNC_SOURCE_IDS_ENTRIES = 1000; + + /** + * Sync Ids buffered in RAM before flushing them to database. + */ + protected array $bufferedSyncIdsEntries = []; + + /** + * Array keeping track of migrations being in the Syncing IDs phase. + * Structure: List of `string => bool` where the key is the migration ID and + * the value is a boolean indicating whether it is currently syncing. + */ + protected array $syncingMigrations = []; + + /** + * Connection to the database. + */ + public Connection $connection; + + /** + * MigrateTools constructor. + * + * @param Connection $connection + * Connection to the database. + */ + public function __construct(Connection $connection) { + $this->connection = $connection; + } + /** * Build the list of specific source IDs to import. * @@ -37,4 +74,150 @@ class MigrateTools { return $id_list; } + /** + * Clears all SyncSourceIds entries from the database, for given migration. + * + * @param string $migrationId + * Migration ID. + */ + public function clearSyncSourceIds(string $migrationId): void + { + $query = $this->connection->delete('migrate_tools_sync_source_ids') + ->condition('migration_id', $migrationId); + $query->execute(); + } + + /** + * Adds a SyncSourceIds entry to the database, for given migration. + * + * @param string $migrationId + * Migration ID. + * @param array $sourceIds + * A set of SyncSourceIds. Gets serialized to retain its structure. + * + * @throws \Exception + */ + public function addToSyncSourceIds(string $migrationId, array $sourceIds): void + { + $this->bufferedSyncIdsEntries[] = [ + 'migration_id' => $migrationId, + // Serialize source IDs before saving them to retain their structure. + 'source_ids' => serialize($sourceIds), + ]; + if (count($this->bufferedSyncIdsEntries) >= static::MAX_BUFFERED_SYNC_SOURCE_IDS_ENTRIES) { + $this->flushSyncSourceIdsToDatabase(); + } + } + + /** + * Flushes any pending SyncSourceIds to the database. + * + * @throws \Exception + */ + protected function flushSyncSourceIdsToDatabase(): void { + if (empty($this->bufferedSyncIdsEntries)) { + // Nothing to flush, do nothing. + return; + } + + // Batch insert all buffered pending entries. + $query = $this->connection->insert('migrate_tools_sync_source_ids') + ->fields(['migration_id', 'source_ids']); + foreach($this->bufferedSyncIdsEntries as $entry) { + $query->values($entry); + } + $query->execute(); + + // Clear buffered pending entries. + $this->bufferedSyncIdsEntries = []; + } + + /** + * Returns all SyncSourceIds from the database, for given migration. + * + * @param string $migrationId + * Migration ID. + * + * @return array + * Ids, structured as they were inserted. + * + * @throws \Exception + */ + public function getSyncSourceIds(string $migrationId): array + { + // Ensure all data was flushed to database before retrieving all of them. + $this->flushSyncSourceIdsToDatabase(); + + // Retrieve all IDs. + $serializedSourceIds = $this->connection->query( + 'SELECT source_ids FROM {migrate_tools_sync_source_ids} WHERE migration_id = :mid', + [':mid' => $migrationId], + ) + ->fetchCol(); + + // Unserialize source IDs to restore their structure. + array_walk($serializedSourceIds, static function(&$entry) { + $entry = unserialize($entry); + }); + + return $serializedSourceIds; + } + + /** + * Sets the syncing state of a migration. + * + * @param string $migrationId + * Migration ID. + * @param bool $isSyncing + * State to set. + */ + public function setMigrationSyncingState(string $migrationId, bool $isSyncing): void + { + $this->syncingMigrations[$migrationId] = $isSyncing; + } + + /** + * Returns the syncing state of a migration. + * + * @param string $migrationId + * Migration ID. + * + * @return bool + * Whether the migration is currently syncing its IDs or not. + */ + public function isMigrationSyncing(string $migrationId): bool + { + return $this->syncingMigrations[$migrationId] ?? FALSE; + } + + /** + * Returns a mapping of log levels to a human-friendly label. + * + * @return array + * An array of log level labels. + */ + public static function getLogLevelLabelMapping() { + return [ + MigrationInterface::MESSAGE_ERROR => t('Error'), + MigrationInterface::MESSAGE_WARNING => t('Warning'), + MigrationInterface::MESSAGE_NOTICE => t('Notice'), + MigrationInterface::MESSAGE_INFORMATIONAL => t('Informational'), + ]; + } + + /** + * Returns a mapping of status levels to a human-friendly label. + * + * @return array + * An array of migration status labels. + */ + public static function getStatusLevelLabelMapping() { + return [ + MigrateIdMapInterface::STATUS_IMPORTED => t('Imported'), + MigrateIdMapInterface::STATUS_NEEDS_UPDATE => t('Pending'), + MigrateIdMapInterface::STATUS_IGNORED => t('Ignored'), + MigrateIdMapInterface::STATUS_FAILED => t('Failed'), + ]; + } + } diff --git a/tests/src/Functional/DrushCommandsTest.php b/tests/src/Functional/DrushCommandsTest.php index 870d7bbe2cce21c9eb0c621c6e8ed4b12ad18ea5..9421b25e1379926294cb079bc76aebffe6f6e621 100644 --- a/tests/src/Functional/DrushCommandsTest.php +++ b/tests/src/Functional/DrushCommandsTest.php @@ -164,7 +164,7 @@ final class DrushCommandsTest extends BrowserTestBase { $this->drush('mmsg', ['fruit_terms'], ['format' => 'json']); $expected = [ [ - 'level' => '1', + 'level' => 'Error', 'message' => 'You picked a bad one.', 'source_ids' => 'Apple', 'destination_ids' => '1', @@ -174,7 +174,7 @@ final class DrushCommandsTest extends BrowserTestBase { $this->drush('mmsg', ['fruit_terms'], ['format' => 'csv']); $expected = <<<EOT "Source ID(s)","Destination ID(s)",Level,Message -Apple,1,1,"You picked a bad one." +Apple,1,Error,"You picked a bad one." EOT; $this->assertEquals($expected, $this->getOutput()); } diff --git a/tests/src/Kernel/DrushTest.php b/tests/src/Kernel/DrushTest.php index b44a6c3ad3b20fb39231b0d0786fe14ac19a2c12..8c3c4f77a37d35bf01e51f1e6272e272f174e3a0 100644 --- a/tests/src/Kernel/DrushTest.php +++ b/tests/src/Kernel/DrushTest.php @@ -77,6 +77,7 @@ namespace Drupal\Tests\migrate_tools\Kernel { $this->installEntitySchema('taxonomy_term'); $this->installEntitySchema('user'); $this->installSchema('user', ['users_data']); + $this->installSchema('migrate_tools', ['migrate_tools_sync_source_ids']); $this->migrationPluginManager = $this->container->get('plugin.manager.migration'); // Handle Drush 10 vs Drush 11 differences. $logger_class = class_exists(DrushLoggerManager::class) ? DrushLoggerManager::class : LoggerInterface::class; diff --git a/tests/src/Kernel/MigrateImportTest.php b/tests/src/Kernel/MigrateImportTest.php index 777294e8f06851da3f51592550e1921b9922caa9..28bffe07e3c7f8ca00201f829faf9dc548a21868 100644 --- a/tests/src/Kernel/MigrateImportTest.php +++ b/tests/src/Kernel/MigrateImportTest.php @@ -30,6 +30,8 @@ final class MigrateImportTest extends MigrateTestBase { 'system', ]; + protected $collectMessages = TRUE; + /** * {@inheritdoc} */ diff --git a/tests/src/Kernel/MigrateRollbackTest.php b/tests/src/Kernel/MigrateRollbackTest.php index 87fe38fe114112c8d0a3230f49ba0e09f8f7654c..f749a1c6db677fd39f73c86b94e34df4230a2f5f 100644 --- a/tests/src/Kernel/MigrateRollbackTest.php +++ b/tests/src/Kernel/MigrateRollbackTest.php @@ -29,6 +29,8 @@ final class MigrateRollbackTest extends MigrateTestBase { 'user', ]; + protected $collectMessages = TRUE; + /** * {@inheritdoc} */ diff --git a/tests/src/Unit/MigrateToolsTest.php b/tests/src/Unit/MigrateToolsTest.php index 4ffe65c9f443912496ea78b3210f99e08703f2c5..b2bbaef6888bd36d896abdf95eb2eac7c2e9d9cf 100644 --- a/tests/src/Unit/MigrateToolsTest.php +++ b/tests/src/Unit/MigrateToolsTest.php @@ -26,7 +26,7 @@ final class MigrateToolsTest extends UnitTestCase { /** * Data provider for testBuildIdList. */ - public function dataProviderIdList(): array { + public static function dataProviderIdList(): array { $cases = []; $cases[] = [ 'options' => [],