Skip to content

Commit

Permalink
Inject migration plugin manager (#4980)
Browse files Browse the repository at this point in the history
* Inject migration plugin manager.

* Strict typing & tidy-up

* PHPCS

* Don't pass the event name anymore

* Fix PHP 8.1 deprecation notices

* Prevent float convert PHP8 deprecation notice
  • Loading branch information
claudiu-cristea committed Jan 4, 2022
1 parent 7597f92 commit 852db7b
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 143 deletions.
2 changes: 1 addition & 1 deletion src/Drupal/Commands/core/EntityCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ protected function getQuery(string $entity_type, ?string $ids, array $options):
{
$storage = $this->entityTypeManager->getStorage($entity_type);
$query = $storage->getQuery();
if ($ids = StringUtils::csvToArray($ids)) {
if ($ids = StringUtils::csvToArray((string) $ids)) {
$idKey = $this->entityTypeManager->getDefinition($entity_type)->getKey('id');
$query = $query->condition($idKey, $ids, 'IN');
} elseif ($options['bundle'] || $options['exclude']) {
Expand Down
126 changes: 54 additions & 72 deletions src/Drupal/Commands/core/MigrateRunnerCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

namespace Drush\Drupal\Commands\core;

use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
use Drupal\Component\Plugin\Exception\PluginException;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\CommandError;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Core\Datetime\DateFormatter;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\MigrateMessageInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
Expand All @@ -29,31 +29,23 @@ class MigrateRunnerCommands extends DrushCommands
{
/**
* Migration plugin manager service.
*
* @var MigrationPluginManagerInterface
*/
protected $migrationPluginManager;
protected ?MigrationPluginManagerInterface $migrationPluginManager;

/**
* Date formatter service.
*
* @var DateFormatter
*/
protected $dateFormatter;
protected DateFormatter $dateFormatter;

/**
* The key-value store service.
*
* @var KeyValueStoreInterface
*/
protected $keyValue;
protected KeyValueStoreInterface $keyValue;

/**
* Migrate message service.
*
* @var MigrateMessageInterface
*/
protected $migrateMessage;
protected MigrateMessageInterface $migrateMessage;

/**
* Constructs a new class instance.
Expand All @@ -62,12 +54,15 @@ class MigrateRunnerCommands extends DrushCommands
* Date formatter service.
* @param KeyValueFactoryInterface $keyValueFactory
* The key-value factory service.
* @param MigrationPluginManagerInterface|null $migrationPluginManager
* The migration plugin manager service.
*/
public function __construct(DateFormatter $dateFormatter, KeyValueFactoryInterface $keyValueFactory)
public function __construct(DateFormatter $dateFormatter, KeyValueFactoryInterface $keyValueFactory, ?MigrationPluginManagerInterface $migrationPluginManager = null)
{
parent::__construct();
$this->dateFormatter = $dateFormatter;
$this->keyValue = $keyValueFactory->get('migrate_last_imported');
$this->migrationPluginManager = $migrationPluginManager;
}

/**
Expand Down Expand Up @@ -230,13 +225,13 @@ protected function getMigrationSourceRowsCount(MigrationInterface $migration): ?
}

/**
* Returns the number or items that needs update.
* Returns the number of items that needs update.
*
* @param MigrationInterface $migration
* The migration plugin instance.
*
* @return int|null
* The number or items that needs update.
* The number of items that needs update.
*/
protected function getMigrationNeedingUpdateCount(MigrationInterface $migration): int
{
Expand Down Expand Up @@ -297,7 +292,7 @@ protected function getMigrationImportedCount(MigrationInterface $migration): ?in
protected function getMigrationLastImportedTime(MigrationInterface $migration): string
{
if ($lastImported = $this->keyValue->get($migration->id(), '')) {
$lastImported = $this->dateFormatter->format($lastImported / 1000, 'custom', 'Y-m-d H:i:s');
$lastImported = $this->dateFormatter->format(round($lastImported / 1000), 'custom', 'Y-m-d H:i:s');
}
return $lastImported;
}
Expand Down Expand Up @@ -436,7 +431,7 @@ protected function executeMigration(MigrationInterface $migration, string $migra
// Remove already executed migrations.
$dependencies = array_diff($dependencies, $executedMigrations);
if ($dependencies) {
$requiredMigrations = $this->getMigrationPluginManager()->createInstances($dependencies);
$requiredMigrations = $this->migrationPluginManager->createInstances($dependencies);
array_walk($requiredMigrations, [static::class, __FUNCTION__], $userData);
}
}
Expand Down Expand Up @@ -546,11 +541,13 @@ public function rollback(?string $migrationIds = null, array $options = ['all' =
* @validate-module-enabled migrate
* @validate-migration-id
* @version 10.4
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
public function stop(string $migrationId): void
{
/** @var MigrationInterface $migration */
$migration = $this->getMigrationPluginManager()->createInstance($migrationId);
$migration = $this->migrationPluginManager->createInstance($migrationId);
switch ($migration->getStatus()) {
case MigrationInterface::STATUS_IDLE:
$this->logger()->warning(dt('Migration @id is idle', ['@id' => $migrationId]));
Expand Down Expand Up @@ -583,11 +580,13 @@ public function stop(string $migrationId): void
* @validate-module-enabled migrate
* @validate-migration-id
* @version 10.4
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
public function resetStatus(string $migrationId): void
{
/** @var MigrationInterface $migration */
$migration = $this->getMigrationPluginManager()->createInstance($migrationId);
$migration = $this->migrationPluginManager->createInstance($migrationId);
$status = $migration->getStatus();
if ($status == MigrationInterface::STATUS_IDLE) {
$this->logger()->warning(dt('Migration @id is already Idle', ['@id' => $migrationId]));
Expand All @@ -605,16 +604,20 @@ public function resetStatus(string $migrationId): void
* @param string $migrationId
* The ID of the migration.
*
* @option idlist Comma-separated list of IDs to import. As an ID may have more than one column, concatenate the columns with the colon ':' separator.
* @option idlist Comma-separated list of IDs to import. As an ID may have
* more than one column, concatenate the columns with the colon ':'
* separator.
*
* @usage migrate:messages article
* Show all messages for the <info>article</info> migration
* @usage migrate:messages article --idlist=5
* Show messages related to article record with source ID 5.
* @usage migrate:messages node_revision --idlist=1:2,2:3,3:5
* Show messages related to node revision records with source IDs [1,2], [2,3], and [3,5].
* Show messages related to node revision records with source IDs [1,2],
* [2,3], and [3,5].
* @usage migrate:messages custom_node_revision --idlist=1:"r:1",2:"r:3"
* Show messages related to node revision records with source IDs [1,"r:1"], and [2,"r:3"].
* Show messages related to node revision records with source IDs
* [1,"r:1"], and [2,"r:3"].
*
* @aliases mmsg,migrate-messages
*
Expand All @@ -634,11 +637,13 @@ public function resetStatus(string $migrationId): void
*
* @return RowsOfFields
* Migration messages status formatted as table.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
public function messages(string $migrationId, array $options = ['idlist' => self::REQ]): RowsOfFields
{
/** @var MigrationInterface $migration */
$migration = $this->getMigrationPluginManager()->createInstance($migrationId);
$migration = $this->migrationPluginManager->createInstance($migrationId);
$idMap = $migration->getIdMap();
$sourceIdKeys = $this->getSourceIdKeys($idMap);
$table = [];
Expand All @@ -648,28 +653,25 @@ public function messages(string $migrationId, array $options = ['idlist' => self
return new RowsOfFields($table);
}
if (!empty($options['idlist'])) {
// There is not way to retreive a filtered set of messages from an
// ID map on Drupal core, right now.
// Even if using \Drush\Drupal\Migrate\MigrateIdMapFilter does the
// right thing filtering the data on the ID map, sadly its
// getMessages() method does not take it into account the iterator,
// and retrieves data directly, e.g. at SQL ID map plugin.
// On the other side Drupal core's
// \Drupal\migrate\Plugin\MigrateIdMapInterface only allows to
// filter by one source IDs set, and not by multiple, on
// getMessages().
// For now, go over known IDs passed directly, one at a time a
// work-around, at the cost of more queries in the usual SQL ID map,
// which is likely OK for its use, to show only few source IDs
// messages.
// There is no way to retrieve a filtered set of messages from an ID
// map on Drupal core, right now. Even if using
// \Drush\Drupal\Migrate\MigrateIdMapFilter does the right thing
// filtering the data on the ID map, sadly its getMessages() method
// does not take it into account the iterator, and retrieves data
// directly, e.g. at SQL ID map plugin. On the other side Drupal
// core's \Drupal\migrate\Plugin\MigrateIdMapInterface only allows
// to filter by one source IDs set, and not by multiple, on
// getMessages(). For now, go over known IDs passed directly, one at
// a time a workaround, at the cost of more queries in the usual SQL
// ID map, which is likely OK for its use, to show only few source
// IDs messages.
foreach (MigrateUtils::parseIdList($options['idlist']) as $sourceIdValues) {
foreach ($idMap->getMessages($sourceIdValues) as $row) {
$table[] = $this->preprocessMessageRow($row, $sourceIdKeys);
}
}
return new RowsOfFields($table);
}
$table = [];
foreach ($idMap->getMessages() as $row) {
$table[] = $this->preprocessMessageRow($row, $sourceIdKeys);
}
Expand Down Expand Up @@ -699,10 +701,10 @@ protected function preprocessMessageRow(\StdClass $row, array $sourceIdKeys): ar
}
$sourceIds = $destinationIds = [];
foreach ($row as $key => $value) {
if (substr($key, 0, 4) === 'src_') {
if (str_starts_with($key, 'src_')) {
$sourceIds[$key] = $value;
}
if (substr($key, 0, 5) === 'dest_') {
if (str_starts_with($key, 'dest_')) {
$destinationIds[$key] = $value;
}
}
Expand Down Expand Up @@ -737,11 +739,13 @@ protected function preprocessMessageRow(\StdClass $row, array $sourceIdKeys): ar
*
* @return RowsOfFields
* Source fields of the given migration.
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
public function fieldsSource(string $migrationId): RowsOfFields
{
/** @var MigrationInterface $migration */
$migration = $this->getMigrationPluginManager()->createInstance($migrationId);
$migration = $this->migrationPluginManager->createInstance($migrationId);
$source = $migration->getSourcePlugin();
$table = [];
foreach ($source->fields() as $machineName => $description) {
Expand Down Expand Up @@ -770,7 +774,7 @@ public function fieldsSource(string $migrationId): RowsOfFields
protected function getMigrationList(?string $migrationIds, ?string $tags): array
{
$migrationIds = StringUtils::csvToArray((string) $migrationIds);
$migrations = $this->getMigrationPluginManager()->createInstances($migrationIds);
$migrations = $this->migrationPluginManager->createInstances($migrationIds);

// Check for invalid migration IDs.
if ($invalidMigrations = array_diff_key(array_flip($migrationIds), $migrations)) {
Expand All @@ -784,7 +788,7 @@ protected function getMigrationList(?string $migrationIds, ?string $tags): array
$sourcePlugin->checkRequirements();
}
} catch (RequirementsException $exception) {
$this->logger()->debug("Migration '{$migrationId}' is skipped as its source plugin has missed requirements: " . $exception->getRequirementsString());
$this->logger()->debug("Migration '$migrationId' is skipped as its source plugin has missed requirements: {$exception->getRequirementsString()}");
unset($migrations[$migrationId]);
}
}
Expand All @@ -798,7 +802,7 @@ protected function getMigrationList(?string $migrationIds, ?string $tags): array

$list = [];
foreach ($migrations as $migrationId => $migration) {
$migrationTags = (array)$migration->getMigrationTags();
$migrationTags = $migration->getMigrationTags();
$commonTags = array_intersect($tags, $migrationTags);
if (!$commonTags) {
// Skip if migration is not tagged with any of the passed tags.
Expand Down Expand Up @@ -827,29 +831,6 @@ protected function getMigrateMessage(): MigrateMessageInterface
return $this->migrateMessage;
}

/**
* Returns the migration plugin manager service.
*
* @return MigrationPluginManagerInterface
* The migration plugin manager service.
*
* @todo This service cannot be injected as the 'migrate' module might not
* be enabled and will throw the following exception:
* > Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
* > The service "migrate_runner.commands" has a dependency on a
* > non-existent service "plugin.manager.migration".
* Unfortunately, we cannot avoid the class instantiation, via an
* annotation (as @validate-module-enabled for methods), if a specific
* module is not installed. Open a followup to tackle this issue.
*/
protected function getMigrationPluginManager(): MigrationPluginManagerInterface
{
if (!isset($this->migrationPluginManager)) {
$this->migrationPluginManager = \Drupal::service('plugin.manager.migration');
}
return $this->migrationPluginManager;
}

/**
* Get the source ID keys.
*
Expand All @@ -869,7 +850,7 @@ protected function getSourceIdKeys(MigrateIdMapInterface $idMap): array
$idMap->rewind();
$columns = $idMap->currentSource();
$sourceIdKeys = array_map(static function ($id) {
return "src_{$id}";
return "src_$id";
}, array_keys($columns));
return array_combine($sourceIdKeys, $sourceIdKeys);
}
Expand All @@ -886,12 +867,13 @@ protected function getSourceIdKeys(MigrateIdMapInterface $idMap): array
*
* @return CommandError|null
*/
public function validateMigrationId(CommandData $commandData)
public function validateMigrationId(CommandData $commandData): ?CommandError
{
$argName = $commandData->annotationData()->get('validate-migration-id') ?: 'migrationId';
$migrationId = $commandData->input()->getArgument($argName);
if (!$this->getMigrationPluginManager()->hasDefinition($migrationId)) {
if (!$this->migrationPluginManager->hasDefinition($migrationId)) {
return new CommandError(dt('Migration "@id" does not exist', ['@id' => $migrationId]));
}
return null;
}
}
2 changes: 1 addition & 1 deletion src/Drupal/Commands/core/drush.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ services:
- { name: drush.command }
migrate_runner.commands:
class: Drush\Drupal\Commands\core\MigrateRunnerCommands
arguments: ['@date.formatter', '@keyvalue']
arguments: ['@date.formatter', '@keyvalue', '@?plugin.manager.migration']
tags:
- { name: drush.command }
queue.commands:
Expand Down

0 comments on commit 852db7b

Please sign in to comment.