-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
VACMS-136900: implement text field migration core logic #16227
base: main
Are you sure you want to change the base?
Changes from 9 commits
6ed1200
373b563
203af01
734809b
93adcea
023ca11
53d7a77
c6e0271
713e1a1
afc18a7
f6e0cc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
services: | ||
va_gov_live_field_migration.commands: | ||
class: \Drupal\va_gov_live_field_migration\Commands\Commands | ||
arguments: [] | ||
arguments: | ||
- '@va_gov_live_field_migration.field_provider_resolver' | ||
- '@va_gov_live_field_migration.migration_runner' | ||
tags: | ||
- { name: drush.command } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
namespace Drupal\va_gov_live_field_migration\Annotation; | ||
|
||
use Drupal\Component\Annotation\Plugin; | ||
|
||
/** | ||
* Defines the annotation object for field provider plugins. | ||
* | ||
* @see plugin_api | ||
* @see \Drupal\va_gov_live_field_migration\FieldProvider\Plugin\FieldProviderPluginInterface | ||
* @see \Drupal\va_gov_live_field_migration\FieldProvider\Plugin\FieldProviderPluginManager | ||
* | ||
* @Annotation | ||
*/ | ||
class FieldProvider extends Plugin { | ||
|
||
/** | ||
* The plugin ID. | ||
* | ||
* @var string | ||
*/ | ||
public $id; | ||
|
||
/** | ||
* The human-readable name of the field provider plugin. | ||
* | ||
* @var \Drupal\Core\Annotation\Translation | ||
*/ | ||
public $label; | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
namespace Drupal\va_gov_live_field_migration\Annotation; | ||
|
||
use Drupal\Component\Annotation\Plugin; | ||
|
||
/** | ||
* Defines the annotation object for live field migration plugins. | ||
* | ||
* @see plugin_api | ||
* @see \Drupal\va_gov_live_field_migration\Migration\Plugin\MigrationPluginInterface | ||
* @see \Drupal\va_gov_live_field_migration\Migration\Plugin\MigrationPluginManager | ||
* | ||
* @Annotation | ||
*/ | ||
class Migration extends Plugin { | ||
|
||
/** | ||
* The plugin ID. | ||
* | ||
* @var string | ||
*/ | ||
public $id; | ||
|
||
/** | ||
* The human-readable name of the migration. | ||
* | ||
* @var \Drupal\Core\Annotation\Translation | ||
*/ | ||
public $label; | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,9 @@ | |
|
||
namespace Drupal\va_gov_live_field_migration\Commands; | ||
|
||
use Drupal\va_gov_live_field_migration\FieldProvider\Resolver\ResolverInterface as FieldProviderResolverInterface; | ||
use Drupal\va_gov_live_field_migration\Migration\Runner\RunnerInterface; | ||
use Drush\Attributes as CLI; | ||
use Drush\Commands\DrushCommands; | ||
|
||
/** | ||
|
@@ -10,121 +13,117 @@ | |
class Commands extends DrushCommands { | ||
|
||
/** | ||
* Perform an operation, such as migrating, rolling back, or verifying. | ||
* The field provider resolver service. | ||
* | ||
* @param callable $operation | ||
* The operation to perform. | ||
* @var \Drupal\va_gov_live_field_migration\FieldProvider\Resolver\ResolverInterface | ||
*/ | ||
public function performOperation(callable $operation) { | ||
$startTime = microtime(TRUE); | ||
try { | ||
$operation(); | ||
} | ||
catch (\Exception $exception) { | ||
$this->output()->writeln('Error: ' . $exception->getMessage()); | ||
} | ||
finally { | ||
$elapsedTime = microtime(TRUE) - $startTime; | ||
$peakMemoryUsage = memory_get_peak_usage(); | ||
$this->output()->writeln('Elapsed time: ' . number_format($elapsedTime, 2) . ' seconds'); | ||
$this->output()->writeln('Peak memory usage: ' . number_format($peakMemoryUsage / 1024 / 1024, 2) . ' MB'); | ||
} | ||
protected $fieldProviderResolver; | ||
|
||
/** | ||
* The migration runner service. | ||
* | ||
* @var \Drupal\va_gov_live_field_migration\Migration\Runner\RunnerInterface | ||
*/ | ||
protected $migrationRunner; | ||
|
||
/** | ||
* Commands constructor. | ||
* | ||
* @param \Drupal\va_gov_live_field_migration\FieldProvider\Resolver\ResolverInterface $fieldProviderResolver | ||
* The field provider resolver service. | ||
* @param \Drupal\va_gov_live_field_migration\Migration\Runner\RunnerInterface $migrationRunner | ||
* The migration runner service. | ||
*/ | ||
public function __construct( | ||
FieldProviderResolverInterface $fieldProviderResolver, | ||
RunnerInterface $migrationRunner | ||
) { | ||
$this->fieldProviderResolver = $fieldProviderResolver; | ||
$this->migrationRunner = $migrationRunner; | ||
} | ||
|
||
/** | ||
* Migrate a specific field on a specific content type. | ||
* Migrate a specific field on a specific entity type. | ||
* | ||
* @param string $entityType | ||
* The entity type. | ||
* @param string $bundle | ||
* The entity bundle or content type. | ||
* @param string $fieldName | ||
* The field name. | ||
* | ||
* @command va-gov-live-field-migration:migrate-field | ||
* @aliases va-gov-live-field-migration-migrate-field | ||
*/ | ||
public function migrateField( | ||
#[CLI\Command(name: 'va-gov-live-field-migration:migrate', aliases: ['va-gov-live-field-migration-migrate'])] | ||
#[CLI\Argument(name: 'entityType', description: 'The entity type')] | ||
#[CLI\Argument(name: 'fieldName', description: 'The field name')] | ||
public function migrate( | ||
string $entityType, | ||
string $bundle, | ||
string $fieldName | ||
) { | ||
$this->performOperation(function () use ($entityType, $bundle, $fieldName) { | ||
$this->output()->writeln('Migrating field ' . $fieldName . ' on ' . $entityType . ' ' . $bundle); | ||
// Logic for the migration. | ||
$this->output()->writeln('Migration successful.'); | ||
}); | ||
$migration = $this->migrationRunner->getMigration($entityType, $fieldName); | ||
$this->migrationRunner->runMigration($migration, $entityType, $fieldName); | ||
} | ||
|
||
/** | ||
* Rollback a specific field on a specific content type. | ||
* Rollback a specific field on a specific entity type. | ||
* | ||
* @param string $entityType | ||
* The entity type. | ||
* @param string $bundle | ||
* The entity bundle or content type. | ||
* @param string $fieldName | ||
* The field name. | ||
* | ||
* @command va-gov-live-field-migration:rollback-field | ||
* @aliases va-gov-live-field-migration-rollback-field | ||
*/ | ||
public function rollbackField( | ||
#[CLI\Command(name: 'va-gov-live-field-migration:rollback', aliases: ['va-gov-live-field-migration-rollback'])] | ||
#[CLI\Argument(name: 'entityType', description: 'The entity type')] | ||
#[CLI\Argument(name: 'fieldName', description: 'The field name')] | ||
public function rollback( | ||
string $entityType, | ||
string $bundle, | ||
string $fieldName | ||
) { | ||
$this->performOperation(function () use ($entityType, $bundle, $fieldName) { | ||
$this->output()->writeln('Rolling back field ' . $fieldName . ' on ' . $entityType . ' ' . $bundle); | ||
// Logic for the rollback. | ||
$this->output()->writeln('Rollback successful.'); | ||
}); | ||
$migration = $this->migrationRunner->getMigration($entityType, $fieldName); | ||
$this->migrationRunner->rollbackMigration($migration, $entityType, $fieldName); | ||
} | ||
|
||
/** | ||
* Verify a migration completed successfully. | ||
* | ||
* @param string $entityType | ||
* The entity type. | ||
* @param string $bundle | ||
* The entity bundle or content type. | ||
* @param string $fieldName | ||
* The field name. | ||
* | ||
* @command va-gov-live-field-migration:verify | ||
* @aliases va-gov-live-field-migration-verify | ||
*/ | ||
#[CLI\Command(name: 'va-gov-live-field-migration:verify', aliases: ['va-gov-live-field-migration-verify'])] | ||
#[CLI\Argument(name: 'entityType', description: 'The entity type')] | ||
#[CLI\Argument(name: 'fieldName', description: 'The field name')] | ||
public function verify( | ||
string $entityType, | ||
string $bundle, | ||
string $fieldName | ||
) { | ||
$this->performOperation(function () use ($entityType, $bundle, $fieldName) { | ||
$this->output()->writeln('Verifying field ' . $fieldName . ' on ' . $entityType . ' ' . $bundle); | ||
// Logic for the verification. | ||
$this->output()->writeln('Verification successful.'); | ||
}); | ||
$migration = $this->migrationRunner->getMigration($entityType, $fieldName); | ||
$this->migrationRunner->verifyMigration($migration, $entityType, $fieldName); | ||
} | ||
|
||
/** | ||
* Find fields that haven't been migrated yet. | ||
* | ||
* @param string $entityType | ||
* The entity type. | ||
* @param string $bundle | ||
* The entity bundle or content type. | ||
* | ||
* @command va-gov-live-field-migration:find | ||
* @aliases va-gov-live-field-migration-find | ||
*/ | ||
public function find( | ||
string $entityType, | ||
string $bundle | ||
) { | ||
$this->performOperation(function () use ($entityType, $bundle) { | ||
$this->output()->writeln('Finding fields on ' . $entityType . ' ' . $bundle); | ||
// Logic for finding fields. | ||
}); | ||
#[CLI\Command(name: 'va-gov-live-field-migration:find', aliases: ['va-gov-live-field-migration-find'])] | ||
#[CLI\Option(name: 'field-provider', description: 'The field provider to use')] | ||
#[CLI\Option(name: 'entity-type', description: 'The entity type to use')] | ||
#[CLI\Option(name: 'bundle', description: 'The bundle to use')] | ||
public function find($options = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [PHP_CodeSniffer] <Drupal.Functions.MultiLineFunctionDeclaration.FirstParamSpacing> reported by reviewdog 🐶 |
||
// Default to the issue 14995 field provider. | ||
// @see https://github.com/department-of-veterans-affairs/va-gov-cms/issues/14995 | ||
'field-provider' => 'issue_14995', | ||
'entity-type' => 'node', | ||
'bundle' => NULL, | ||
]) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [PHP_CodeSniffer] <Drupal.Functions.MultiLineFunctionDeclaration.MissingTrailingComma> reported by reviewdog 🐶 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [PHP_CodeSniffer] <Drupal.Functions.MultiLineFunctionDeclaration.CloseBracketLine> reported by reviewdog 🐶 |
||
$fieldProvider = $options['field-provider']; | ||
$entityType = $options['entity-type']; | ||
$bundle = $options['bundle']; | ||
$this->output()->writeln('Finding fields with field provider "' . $fieldProvider . '" on entity type "' . $entityType . '", bundle "' . ($bundle ?: 'NULL') . '"...'); | ||
$fields = $this->fieldProviderResolver | ||
->getFieldProvider($fieldProvider) | ||
->getFields($entityType, $bundle); | ||
$this->output()->writeln('Found ' . count($fields) . ' fields.'); | ||
foreach ($fields as $field) { | ||
$this->output()->writeln($field); | ||
} | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
<?php | ||
|
||
namespace Drupal\va_gov_live_field_migration\Database; | ||
|
||
use Drupal\Core\Database\Connection; | ||
|
||
/** | ||
* A database service to abstract database operations. | ||
*/ | ||
class Database implements DatabaseInterface { | ||
|
||
/** | ||
* The database connection. | ||
* | ||
* @var \Drupal\Core\Database\Connection | ||
*/ | ||
protected $connection; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param \Drupal\Core\Database\Connection $connection | ||
* The database connection. | ||
*/ | ||
public function __construct( | ||
Connection $connection | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 [PHP_CodeSniffer] <Drupal.Functions.MultiLineFunctionDeclaration.MissingTrailingComma> reported by reviewdog 🐶 |
||
) { | ||
$this->connection = $connection; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function dropTable(string $table): void { | ||
$this->connection->schema()->dropTable($table); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function getPrimaryFieldTableName(string $entityType, string $fieldName): string { | ||
return "{$entityType}__{$fieldName}"; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function getFieldRevisionTableName(string $entityType, string $fieldName): string { | ||
return "{$entityType}__{$fieldName}"; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function getBackupTableName(string $tableName): string { | ||
// Table names are limited to 64 characters, but Drupal field tables can | ||
// be longer than that. So we need to truncate the table name. | ||
$tableName = substr($tableName, 0, 64 - strlen(self::BACKUP_TABLE_SUFFIX)); | ||
return "{$tableName}__backup"; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function createTable(string $newTable, string $existingTable): void { | ||
$this->connection->query("CREATE TABLE {$newTable} LIKE {$existingTable};"); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function copyTable(string $sourceTable, string $destinationTable, bool $preserve = FALSE): void { | ||
if (!$preserve) { | ||
$this->dropTable($destinationTable); | ||
$this->createTable($destinationTable, $sourceTable); | ||
} | ||
$this->connection->query("INSERT {$destinationTable} SELECT * FROM {$sourceTable};"); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function backupPrimaryFieldTable(string $entityType, string $fieldName, bool $preserve = FALSE): void { | ||
$primaryTable = $this->getPrimaryFieldTableName($entityType, $fieldName); | ||
$backupTable = $this->getBackupTableName($primaryTable); | ||
$this->copyTable($primaryTable, $backupTable, $preserve); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function backupFieldRevisionTable(string $entityType, string $fieldName, bool $preserve = FALSE): void { | ||
$revisionTable = $this->getFieldRevisionTableName($entityType, $fieldName); | ||
$backupTable = $this->getBackupTableName($revisionTable); | ||
$this->copyTable($revisionTable, $backupTable, $preserve); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function restorePrimaryFieldTable(string $entityType, string $fieldName, bool $preserve = FALSE): void { | ||
$primaryTable = $this->getPrimaryFieldTableName($entityType, $fieldName); | ||
$backupTable = $this->getBackupTableName($primaryTable); | ||
$this->copyTable($backupTable, $primaryTable, $preserve); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function restoreFieldRevisionTable(string $entityType, string $fieldName, bool $preserve = FALSE): void { | ||
$revisionTable = $this->getFieldRevisionTableName($entityType, $fieldName); | ||
$backupTable = $this->getBackupTableName($revisionTable); | ||
$this->copyTable($backupTable, $revisionTable, $preserve); | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 [PHP_CodeSniffer] <Drupal.Functions.MultiLineFunctionDeclaration.MissingTrailingComma> reported by reviewdog 🐶
Multi-line function declarations must have a trailing comma after the last parameter