diff --git a/migrate_ui.routing.yml b/migrate_ui.routing.yml index 133ee2f..f173811 100644 --- a/migrate_ui.routing.yml +++ b/migrate_ui.routing.yml @@ -45,3 +45,11 @@ entity.migration.delete_form: _title: 'Delete migration' requirements: _entity_access: 'migration.delete' + +entity.migration.launch_form: + path: '/admin/config/migrate/migrations/launch/{migration}' + defaults: + _entity_form: 'migration.launch-form' + _title: 'Launch migration' + requirements: + _entity_access: 'migration.launch' \ No newline at end of file diff --git a/src/Form/LaunchMigrationForm.php b/src/Form/LaunchMigrationForm.php new file mode 100644 index 0000000..4d29014 --- /dev/null +++ b/src/Form/LaunchMigrationForm.php @@ -0,0 +1,283 @@ +destinationField = $destination_field; + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function form(array $form, FormStateInterface $form_state) { + $form = parent::form($form, $form_state); + + $form['operations'] = $this->migrateUiMigrateOperations(); + + return $form; + } + + + + /** + * Get Operations. + */ + private function migrateUiMigrateOperations() { + // Build the 'Update options' form. + $operations = array( + '#type' => 'fieldset', + '#title' => t('Operations'), + ); + + $options = array( + '' => t('Please select'), + 'import_immediate' => t('Import immediately'), + 'import_background' => t('Import in background'), + 'rollback_immediate' => t('Rollback immediately'), + 'rollback_background' => t('Rollback in background'), + ); + + $options += array( + 'stop' => t('Stop'), + 'reset' => t('Reset'), + 'deregister' => t('Remove migration settings'), + ); + $operations['operation'] = array( + '#type' => 'select', + '#title' => t('Operation'), + '#title_display' => 'invisible', + '#options' => $options, + ); + $operations['submit'] = array( + '#type' => 'submit', + '#value' => t('Execute'), + '#validate' => array('migrate_ui_migrate_validate'), + '#submit' => array('migrate_ui_migrate_submit'), + ); + $operations['description'] = array( + '#prefix' => '

', + '#markup' => t( + 'Choose an operation to run on all selections above: +

' + ), + '#postfix' => '

', + ); + + $operations['options'] = array( + '#type' => 'fieldset', + '#title' => t('Options'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + $operations['options']['update'] = array( + '#type' => 'checkbox', + '#title' => t('Update'), + '#description' => t('Check this box to update all previously-imported content + in addition to importing new content. Leave unchecked to only import + new content'), + ); + $operations['options']['force'] = array( + '#type' => 'checkbox', + '#title' => t('Ignore dependencies'), + '#description' => t('Check this box to ignore dependencies when running imports + - all tasks will run whether or not their dependent tasks have + completed.'), + ); + $operations['options']['limit'] = array( + '#tree' => TRUE, + '#type' => 'fieldset', + '#attributes' => array('class' => array('container-inline')), + 'value' => array( + '#type' => 'textfield', + '#title' => t('Limit to:'), + '#size' => 10, + ), + 'unit' => array( + '#type' => 'select', + '#options' => array( + 'items' => t('items'), + 'seconds' => t('seconds'), + ), + '#description' => t('Set a limit of how many items to process for + each migration task, or how long each should run.'), + ), + ); + + return $operations; + } + + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) { + + if (empty($form_state->getValue('operation'))) { + $form_state->setErrorByName('operation', $this->t('Please select an operation.')); + return; + } + + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + + $operation = $form_state->getValue('operation'); + + $limit = $form_state->getValue('limit'); + + if ($form_state->getValue('update')) { + $update = $form_state->getValue('update'); + } + else { + $update = 0; + } + if ($form_state->getValue('force')) { + $force = $form_state->getValue('force'); + } + else { + $force = 0; + } + + $migration_name = \Drupal::routeMatch()->getParameter('migration'); + $machine_name = $migration_name->id(); + + $operations = array(); + + $drush_arguments = array(); + if ($machine_name) { + //TODO $migration = Migration::getInstance($machine_name); + //TODO if ($migration) { + switch ($operation) { + case 'import_immediate': + // Update (if necessary) once, before starting + if ($update && method_exists($migration, 'prepareUpdate')) { + //TODO $migration->prepareUpdate(); + } + $operations[] = array('migrate_ui_batch', array('import', $machine_name, $limit, $force)); + break; + case 'rollback_immediate': + $operations[] = array('migrate_ui_batch', array('rollback', $machine_name, $limit, $force)); + break; + case 'import_background': + case 'rollback_background': + $drush_arguments[] = $machine_name; + break; + case 'stop': + //$migration->stopProcess(); + break; + case 'reset': + //$migration->resetStatus(); + break; + case 'deregister': + //migrate_ui_deregister_migration($machine_name); + break; + //TODO} + } + } + + // Only immediate rollback and import operations will need to go through Batch API. + if (count($operations) > 0) { + + $batch = array( + 'operations' => $operations, + 'title' => t('Import processing'), + 'file' => drupal_get_path('module', 'migrate_ui') . '/migrate_ui.pages.inc', + 'init_message' => t('Starting import process'), + 'progress_message' => t(''), + 'error_message' => t('An error occurred. Some or all of the import processing has failed.'), + 'finished' => 'migrate_ui_batch_finish', + ); + batch_set($batch); + + } + elseif (count($drush_arguments) > 0) { + kint('la'); + trim(variable_get('migrate_drush_path', '')); + // Check that $drush_path works. See migrate_ui_configure_form(). + if (!is_executable($drush_path)) { + $message = t('To enable running operations in the background with drush, (which is recommended), some configuration must be done on the server. See the documentation on drupal.org.', + array( + '@drush' => 'http://drupal.org/project/drush', + '@recommended' => 'http://drupal.org/node/1806824', + '@config' => 'http://drupal.org/node/1958170', + '@dorg' => 'http://drupal.org/', + ) + ); + drupal_set_message($message); + return; + } + $uri = $GLOBALS['base_url']; + $uid = $GLOBALS['user']->uid; + if ($operation == 'import_background') { + $command = 'mi'; + $log_suffix = '.import.log'; + } + else { + $command = 'mr'; + $log_suffix = '.rollback.log'; + } + $migrations = implode(',', $drush_arguments); + $drush_command = "$drush_path $command $migrations --user=$uid --uri=$uri " . + '--root=' . DRUPAL_ROOT; + if ($force) { + $drush_command .= ' --force'; + } + if ($update) { + $drush_command .= ' --update'; + } + if (variable_get('migrate_drush_mail', 0)) { + $drush_command .= ' --notify'; + } + if (!empty($limit['value'])) { + $limit = $limit['value'] . ' ' . $limit['unit']; + $drush_command .= " --limit=\"$limit\""; + } + $log_file = drupal_realpath('temporary://' . $drush_arguments[0] . $log_suffix); + $drush_command .= " >$log_file 2>&1 &"; + exec($drush_command, $output, $status); + if (variable_get('migrate_drush_mail', 0)) { + drupal_set_message('Your operation is running in the background. You will receive an email message when it is complete.'); + } + else { + drupal_set_message('Your operation is running in the background. You may '. + 'refresh the dashboard page to check on its progress.'); + } + } + } + +} diff --git a/src/MigrationListBuilder.php b/src/MigrationListBuilder.php index ad23ee8..0b0ee43 100644 --- a/src/MigrationListBuilder.php +++ b/src/MigrationListBuilder.php @@ -59,6 +59,8 @@ class MigrationListBuilder extends ConfigEntityListBuilder { $row['destination'] = $this->t('Destination name'); $row['tags'] = $this->t('Tags'); $row['operations'] = $this->t('Operations'); + $row['import'] = $this->t('Import'); + return $row; } @@ -72,6 +74,15 @@ class MigrationListBuilder extends ConfigEntityListBuilder { $row['destination']['data'] = $entity->getDestinationPlugin()->getPluginId(); $row['tags']['data'] = implode(', ', $entity->get('migration_tags') ?: []); $row['operations']['data'] = $this->buildOperations($entity); + $row['import']['data'] = array( + '#type' => 'dropbutton', + '#links' => array( + 'simple_form' => array( + 'title' => $this->t('Launch'), + 'url' => Url::fromRoute('entity.migration.launch_form', array('migration' => $entity->get('id'))), + ), + ), + ); return $row; }