media_acquiadam-8.x-1.46/src/Form/AcquiadamMigration.php
src/Form/AcquiadamMigration.php
<?php
declare(strict_types=1);
namespace Drupal\media_acquiadam\Form;
use Drupal\Core\Batch\BatchBuilder;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\media_acquiadam\Batch\MediaTypeProcessBatch;
use Drupal\media_acquiadam\Traits\MigrationTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Acquia DAM integration from a legacy to a more modern solution.
*/
class AcquiadamMigration extends ConfigFormBase {
use MigrationTrait;
/**
* Store module-wide used constant as class attribute.
*
* @var string
*/
public const MODULE_SETTINGS_NAME = 'media_acquiadam.migration_preferences';
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The entity type manager service.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The media source plugin manager service.
*
* @var \Drupal\Component\Plugin\PluginManagerInterface
*/
protected $mediaSourcePluginManager;
/**
* The migration service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The database service.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* The Drupal State Service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
$instance = parent::create($container);
$instance->moduleHandler = $container->get('module_handler');
$instance->entityTypeManager = $container->get('entity_type.manager');
$instance->mediaSourcePluginManager = $container->get('plugin.manager.media.source');
$instance->configFactory = $container->get('config.factory');
$instance->database = $container->get('database');
$instance->state = $container->get('state');
return $instance;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'media_acquiadam_migration';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [
self::MODULE_SETTINGS_NAME,
];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
// Bail out if there are no media types to migrate.
if (empty($this->getLegacyDamMediaTypes())) {
$this->messenger()->addWarning($this->t('There are no existing media types to migrate. You can safely uninstall Media: Acquia DAM.'));
unset($form['actions']);
return $form;
}
// Bail out if the `acquia_dam` module is not installed.
if (!$this->moduleHandler->moduleExists('acquia_dam')) {
$this->messenger()->addError($this->t('The migration process requires that both the source
<em>Media: Acquia DAM</em> (<code>media_acquiadam</code>) and the target <em>Acquia DAM</em>
(<code>acquia_dam</code>) modules be installed on the website. <a href=":url">Enable the missing module.</a>', [
':url' => Url::fromRoute('system.modules_list')->toString(),
]));
unset($form['actions']);
return $form;
}
// Set the appropriate page based on the stored values.
$stored_values = $this->getMigrationConfig();
if (!empty($stored_values['current_page'])) {
$form_state->set('page', $stored_values['current_page']);
}
$page = (int) $form_state->get('page');
$multistep_form = match ($page) {
1 => new AcquiadamMigrationListForm(),
2 => new AcquiadamMigrationSummaryForm(),
default => new AcquiadamMigrationMapForm(),
};
$form = $multistep_form->buildForm($form, $form_state);
// Add the actions' container.
$form['actions'] = [
'#type' => 'actions',
'#attributes' => ['style' => 'text-align: center; display: block;'],
];
// Add the "Previous" button if not on the first page.
if ($page > 0) {
$form['actions']['previous'] = [
'#type' => 'submit',
'#value' => $this->t('Previous'),
'#submit' => ['::goPrevious'],
'#button_type' => 'secondary',
];
}
// Add the "Next" button if not on the last page.
if ($page < 2) {
$form['actions']['next'] = [
'#type' => 'submit',
'#value' => $this->t('Save & Next'),
'#submit' => ['::goNext'],
'#button_type' => 'primary',
];
}
else {
$form['wrapper']['info-command'] = [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => $this->t('The migration preferences have been configured as described above. Clicking the
<em>\'Migrate\'</em> button initiates a batch process that handles the affected media types. Upon completion,
the results are reported in the logs, and the migration status is displayed.
Alternatively, you can start the migration process from the command line by running
the <code>$ drush acquiadam:migrate</code> command.'),
];
// Add the "Submit" button on the last page.
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Migrate'),
'#button_type' => 'primary',
];
// Save the configuration button.
$form['actions']['save'] = [
'#type' => 'submit',
'#value' => $this->t('Save'),
'#submit' => ['::doSave'],
'#button_type' => 'primary',
];
}
return $form;
}
/**
* Submit handler for the "Previous" button.
*
* @param array $form
* The form arrays.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state object.
*/
public function goPrevious(array &$form, FormStateInterface $form_state) {
$page = $form_state->get('page');
$current_page = $page - 1;
$stored_values = $this->getMigrationConfig();
if (!empty($stored_values['current_page'])) {
$form_state->set('page', $current_page);
$this->getConfigFactory()
->getEditable(self::MODULE_SETTINGS_NAME)
->set('stored_values.current_page', $current_page)
->save();
}
$form_state->cleanValues();
$form_state->setRebuild();
}
/**
* Submit handler for the "Next" button.
*
* @param array $form
* The form arrays.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state object.
*/
public function goNext(array &$form, FormStateInterface $form_state) {
$page = (int) $form_state->get('page');
$current_page = $page + 1;
$form_state->set('page', $current_page);
$form_state->cleanValues();
$this->storeFormState($form_state, $current_page);
$form_state->setRebuild();
}
/**
* Store form state value in custom variable.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state object.
* @param int $current_page
* The current page number.
*/
protected function storeFormState(FormStateInterface $form_state, int $current_page) {
$form_state->cleanValues();
$current_page_values = $form_state->getValues();
$stored_values = $this->getMigrationConfig();
$legacy_dam_media_types = $current_page_values['legacy_dam_media_types'] ?? [];
if (!empty($legacy_dam_media_types)) {
// Clear the 'delete' value from stored_values for modern_dam_media_types.
// This ensures that when user updates the target source plugin on the
// first page and revisits the second page, the 'delete' checkbox is again
// auto-selected based on the updated target media source plugin.
$stored_values['modern_dam_media_types'] = $this->clearDeleteFlag($stored_values['modern_dam_media_types'] ?? []);
}
$stored_values['current_page'] = $current_page;
$this->configFactory->getEditable(self::MODULE_SETTINGS_NAME)
->set('stored_values', $current_page_values + $stored_values)
->save();
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Set and run the batch.
batch_set($this->prepareMigrationBatch());
$form_state->setRedirectUrl(Url::fromRoute('media_acquiadam.migration_config'));
}
/**
* Prepare batch operations for the migration process.
*/
public static function prepareMigrationBatch(): array {
$stored_values = \Drupal::config(self::MODULE_SETTINGS_NAME)->get('stored_values');
// Create and setup batch builder.
$batch_builder = new BatchBuilder();
$batch_builder
->setTitle(t("Acquia DAM queue assets for migration is in progress"))
->setInitMessage(t("Preparing for processing media types and items"))
->setProgressMessage(t('Processing batch @current out of @total.'))
->setErrorMessage(t('An error happened during Acquia DAM queue assets for migration while processing media types and items.'))
->setFinishCallback([MediaTypeProcessBatch::class, 'finish']);
// Get media type to be deleted.
$bundle_to_delete = self::getMediaTypeDeletionList($stored_values);
// Delete media types batch action.
foreach ($bundle_to_delete as $media_type_id => $media_type_name) {
// Add operation to batch.
$batch_builder->addOperation([
MediaTypeProcessBatch::class, 'process',
], ['delete', $media_type_id, ['media_type_label' => $media_type_name]]);
}
// Update label for new media types.
foreach ($stored_values['modern_dam_media_types'] as $bundle_data) {
if ($bundle_data['delete']) {
continue;
}
$batch_builder->addOperation([
MediaTypeProcessBatch::class, 'process',
], ['update_modern_media_label', $bundle_data['media_type_id'], $bundle_data]);
}
// Update media types batch action.
foreach ($stored_values['legacy_dam_media_types'] as $bundle_data) {
if (!isset($bundle_data['sync_method'])) {
continue;
}
// Add operation to batch.
$batch_builder->addOperation([
MediaTypeProcessBatch::class, 'process',
], ['update', $bundle_data['media_type_id'], $bundle_data]);
// Add operation to copy asset data from legacy to modern table.
$batch_builder->addOperation([MediaTypeProcessBatch::class, 'copyAssetIdFromOldToNewTable'], [$bundle_data]);
}
return $batch_builder->toArray();
}
/**
* Submit handler for the "Save" button.
*
* @param array $form
* The form arrays.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state object.
*/
public function doSave(array &$form, FormStateInterface $form_state) {
$current_page = (int) $form_state->get('page');
$form_state->cleanValues();
$this->storeFormState($form_state, $current_page);
$this->messenger()->addStatus($this->t('Migration preferences have been saved.'));
}
/**
* Removes the delete key from user selected modern media types.
*
* @param array $modern_media_dam_types
* An array of user selected modern media types.
*/
private function clearDeleteFlag(array $modern_media_dam_types): array {
// Remove the 'delete' key from each modern media DAM type.
return array_map(function (array $modern_media_dam_type): array {
unset($modern_media_dam_type['delete']);
return $modern_media_dam_type;
}, $modern_media_dam_types);
}
}
