diff --git a/config/install/migrate_plus.migration_group.default.yml b/config/install/migrate_plus.migration_group.default.yml index 17105826b5a6a07457eba8b1a76c51ab2d83db11..c19fc56a20f01e959d790e2ebec936f47621b2e4 100644 --- a/config/install/migrate_plus.migration_group.default.yml +++ b/config/install/migrate_plus.migration_group.default.yml @@ -1,3 +1,4 @@ # A default group, assigned to any migrations with no explicit group. id: default label: Default +description: A container for any migrations not explicitly assigned to a group. diff --git a/config/schema/migrate_plus.schema.yml b/config/schema/migrate_plus.schema.yml index 08b47b26e4e741fcab43e20048d870ac76009e9a..af36c593ec0f6fadc5c37723ea63392a52833c9e 100644 --- a/config/schema/migrate_plus.schema.yml +++ b/config/schema/migrate_plus.schema.yml @@ -8,6 +8,12 @@ migrate_plus.migration_group.*: label: type: label label: 'Label' + description: + type: string + label: 'Description' + source_type: + type: string + label: 'Source type' module: type: string label: 'Dependent module' diff --git a/migrate_example/config/install/migrate_plus.migration_group.beer.yml b/migrate_example/config/install/migrate_plus.migration_group.beer.yml index bcc5f2b4497819d43d76c8ece8cb2fa2b7826c69..da0238f30a46d866685c379703d2dc7ca3b6515b 100644 --- a/migrate_example/config/install/migrate_plus.migration_group.beer.yml +++ b/migrate_example/config/install/migrate_plus.migration_group.beer.yml @@ -5,6 +5,12 @@ id: beer # A human-friendly label of the group, displayed in the UI. label: Beer Imports +# More information about the group. +description: A few simple beer-related imports, to demonstrate how to implement migrations. + +# Short description of the type of source, e.g. "Drupal 6" or "WordPress". +source_type: Custom tables + # Here we add any default configuration settings to be shared among all # migrations in the group. shared_configuration: diff --git a/migrate_plus.module b/migrate_plus.module index 9edd00c206641792075600908bc8a635689efdbc..aba4648710a7923398be233901ca1829c19a16cd 100644 --- a/migrate_plus.module +++ b/migrate_plus.module @@ -2,7 +2,7 @@ /** * @file - * Provides tools and enhancements for implementing and managing migrations. + * Provides enhancements for implementing and managing migrations. */ use Drupal\migrate\Entity\MigrationInterface; diff --git a/migrate_tools/migrate_tools.links.action.yml b/migrate_tools/migrate_tools.links.action.yml new file mode 100644 index 0000000000000000000000000000000000000000..2a0a9adc56b5834a4e491b0ab7f2e035c5a96811 --- /dev/null +++ b/migrate_tools/migrate_tools.links.action.yml @@ -0,0 +1,13 @@ +migrate_tools.add_action: + route_name: entity.migration_group.add_form + title: 'Add migration group' + appears_on: + - entity.migration_group.list + +migrate_tools.list_action: + route_name: entity.migration_group.list + title: 'List Migration Groups' + appears_on: + - entity.migration_group.add_form + - entity.migration_group.edit + - entity.migration_group.delete diff --git a/migrate_tools/migrate_tools.links.menu.yml b/migrate_tools/migrate_tools.links.menu.yml new file mode 100644 index 0000000000000000000000000000000000000000..d55ba56c133d03491d28dfd33827bd42cb8928db --- /dev/null +++ b/migrate_tools/migrate_tools.links.menu.yml @@ -0,0 +1,5 @@ +migrate_tools.menu: + title: Migrations + parent: system.admin_structure + description: Manage migration processes. + route_name: entity.migration_group.list diff --git a/migrate_tools/migrate_tools.module b/migrate_tools/migrate_tools.module new file mode 100644 index 0000000000000000000000000000000000000000..441343e0d6ccf0b13405f424d8d84e00436675bd --- /dev/null +++ b/migrate_tools/migrate_tools.module @@ -0,0 +1,22 @@ +<?php + +/** + * @file + * Provides tools for implementing and managing migrations. + */ + +/** + * Implements hook_entity_type_alter(). + */ +function migrate_tools_entity_type_alter(array &$entity_types) { + // Inject our UI into the general migration config entity. + /** @var \Drupal\Core\Config\Entity\ConfigEntityType[] $entity_types */ + $entity_types['migration_group'] + ->set('admin_permission', 'administer migrations') + ->setHandlerClass('list_builder', 'Drupal\migrate_tools\Controller\MigrationGroupListBuilder') + ->setFormClass('add', 'Drupal\migrate_tools\Form\MigrationGroupAddForm') + ->setFormClass('edit', 'Drupal\migrate_tools\Form\MigrationGroupEditForm') + ->setFormClass('delete', 'Drupal\migrate_tools\Form\MigrationGroupDeleteForm') + ->setLinkTemplate('edit-form', '/admin/structure/migrate/manage/{migration_group}') + ->setLinkTemplate('delete-form', '/admin/structure/migrate/manage/{migration_group}/delete'); +} diff --git a/migrate_tools/migrate_tools.permissions.yml b/migrate_tools/migrate_tools.permissions.yml new file mode 100644 index 0000000000000000000000000000000000000000..b5301e5c1f326186a48ba7f97a8aa9cee66b8343 --- /dev/null +++ b/migrate_tools/migrate_tools.permissions.yml @@ -0,0 +1,3 @@ +'administer migrations': + title: 'Administer migrations' + description: Create, edit, and manage migration processed. diff --git a/migrate_tools/migrate_tools.routing.yml b/migrate_tools/migrate_tools.routing.yml new file mode 100644 index 0000000000000000000000000000000000000000..01a8242386f18afe928fc159a85740d15ed5db23 --- /dev/null +++ b/migrate_tools/migrate_tools.routing.yml @@ -0,0 +1,35 @@ +# This is the router item for listing all entities. +entity.migration_group.list: + path: '/admin/structure/migrate' + defaults: + _entity_list: 'migration_group' + _title: 'Migrations' + requirements: + _permission: 'administer migrations' + +# This is the router item for adding our entity. +entity.migration_group.add_form: + path: '/admin/structure/migrate/add' + defaults: + _title: 'Add migration group' + _entity_form: migration_group.add + requirements: + _entity_create_access: migration_group + +# This is the router item for editing our entity. +entity.migration_group.edit_form: + path: '/admin/structure/migrate/manage/{migration_group}' + defaults: + _title: 'Edit migration group' + _entity_form: migration_group.edit + requirements: + _entity_access: migration_group.update + +# This is the router item for deleting an instance of our entity. +entity.migration_group.delete_form: + path: '/admin/structure/migrate/manage/{migration_group}/delete' + defaults: + _title: 'Delete migration group' + _entity_form: migration_group.delete + requirements: + _entity_access: migration_group.delete diff --git a/migrate_tools/src/Controller/MigrationGroupListBuilder.php b/migrate_tools/src/Controller/MigrationGroupListBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..4a00c733439d7e8745f12746d079241151f4a71b --- /dev/null +++ b/migrate_tools/src/Controller/MigrationGroupListBuilder.php @@ -0,0 +1,72 @@ +<?php +/** + * @file + * Contains Drupal\migrate_tools\Controller\MigrationGroupListBuilder. + */ + +namespace Drupal\migrate_tools\Controller; + +use Drupal\Core\Config\Entity\ConfigEntityListBuilder; +use Drupal\Core\Config\Entity\ConfigEntityInterface; +use Drupal\Core\Entity\EntityInterface; + +/** + * Provides a listing of migration group entities. + * + * @package Drupal\migrate_tools\Controller + * + * @ingroup migrate_tools + */ +class MigrationGroupListBuilder extends ConfigEntityListBuilder { + + /** + * Builds the header row for the entity listing. + * + * @return array + * A render array structure of header strings. + * + * @see Drupal\Core\Entity\EntityListController::render() + */ + public function buildHeader() { + $header['label'] = $this->t('Migration Group'); + $header['machine_name'] = $this->t('Machine Name'); + $header['description'] = $this->t('Description'); + $header['source_type'] = $this->t('Source Type'); + return $header + parent::buildHeader(); + } + + /** + * Builds a row for an entity in the entity listing. + * + * @param EntityInterface $entity + * The entity for which to build the row. + * + * @return array + * A render array of the table row for displaying the entity. + * + * @see Drupal\Core\Entity\EntityListController::render() + */ + public function buildRow(ConfigEntityInterface $entity) { + $row['label'] = $this->getLabel($entity); + $row['machine_name'] = $entity->id(); + $row['description'] = $entity->get('description'); + $row['source_type'] = $entity->get('source_type'); + + return $row + parent::buildRow($entity); + } + + /** + * Adds some descriptive text to our entity list. + * + * @return array + * Renderable array. + */ + public function render() { + $build['description'] = array( + '#markup' => $this->t("<p>Initial POC of the migration dashboard - note that management of the migrations themselves is not yet implemented, only the groups.</p>"), + ); + $build[] = parent::render(); + return $build; + } + +} diff --git a/migrate_tools/src/Form/MigrationGroupAddForm.php b/migrate_tools/src/Form/MigrationGroupAddForm.php new file mode 100644 index 0000000000000000000000000000000000000000..f6da5046e66a36078d20abcae7461de4feedfbcf --- /dev/null +++ b/migrate_tools/src/Form/MigrationGroupAddForm.php @@ -0,0 +1,42 @@ +<?php + +/** + * @file + * Contains Drupal\migrate_tools\Form\MigrationGroupAddForm. + */ + +namespace Drupal\migrate_tools\Form; + +use Drupal\Core\Form\FormStateInterface; + +/** + * Class MigrationGroupAddForm. + * + * Provides the add form for our migration_group entity. + * + * @package Drupal\migrate_tools\Form + * + * @ingroup migrate_tools + */ +class MigrationGroupAddForm extends MigrationGroupFormBase { + + /** + * Returns the actions provided by this form. + * + * For our add form, we only need to change the text of the submit button. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An array of supported actions for the current entity form. + */ + protected function actions(array $form, FormStateInterface $form_state) { + $actions = parent::actions($form, $form_state); + $actions['submit']['#value'] = $this->t('Create Migration Group'); + return $actions; + } + +} diff --git a/migrate_tools/src/Form/MigrationGroupDeleteForm.php b/migrate_tools/src/Form/MigrationGroupDeleteForm.php new file mode 100644 index 0000000000000000000000000000000000000000..6b5194b200ab0b754c150ba5b7ac8e52f908a7f6 --- /dev/null +++ b/migrate_tools/src/Form/MigrationGroupDeleteForm.php @@ -0,0 +1,76 @@ +<?php + +/** + * @file + * Contains Drupal\migrate_tools\Form\MigrationGroupDeleteForm. + */ + +namespace Drupal\migrate_tools\Form; + +use Drupal\Core\Entity\EntityConfirmFormBase; +use Drupal\Core\Url; +use Drupal\Core\Form\FormStateInterface; + +/** + * Class MigrationGroupDeleteForm. + * + * @package Drupal\migrate_tools\Form + * + * @ingroup migrate_tools + */ +class MigrationGroupDeleteForm extends EntityConfirmFormBase { + + /** + * Gathers a confirmation question. + * + * @return string + * Translated string. + */ + public function getQuestion() { + return $this->t('Are you sure you want to delete migration group %label?', array( + '%label' => $this->entity->label(), + )); + } + + /** + * Gather the confirmation text. + * + * @return string + * Translated string. + */ + public function getConfirmText() { + return $this->t('Delete Migration Group'); + } + + /** + * Gets the cancel URL. + * + * @return \Drupal\Core\Url + * The URL to go to if the user cancels the deletion. + */ + public function getCancelUrl() { + return new Url('entity.migration_group.list'); + } + + /** + * The submit handler for the confirm form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + // Delete the entity. + $this->entity->delete(); + + // Set a message that the entity was deleted. + drupal_set_message(t('Migration group %label was deleted.', array( + '%label' => $this->entity->label(), + ))); + + // Redirect the user to the list controller when complete. + $form_state->setRedirectUrl($this->getCancelUrl()); + } + +} diff --git a/migrate_tools/src/Form/MigrationGroupEditForm.php b/migrate_tools/src/Form/MigrationGroupEditForm.php new file mode 100644 index 0000000000000000000000000000000000000000..ffacb3d3ff44e43eb35111129999a5c348766da8 --- /dev/null +++ b/migrate_tools/src/Form/MigrationGroupEditForm.php @@ -0,0 +1,42 @@ +<?php + +/** + * @file + * Contains Drupal\migrate_tools\Form\MigrationGroupEditForm. + */ + +namespace Drupal\migrate_tools\Form; + +use Drupal\Core\Form\FormStateInterface; + +/** + * Class MigrationGroupEditForm + * + * Provides the edit form for our Migration Group entity. + * + * @package Drupal\migrate_tools\Form + * + * @ingroup migrate_tools + */ +class MigrationGroupEditForm extends MigrationGroupFormBase { + + /** + * Returns the actions provided by this form. + * + * For the edit form, we only need to change the text of the submit button. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An array of supported actions for the current entity form. + */ + public function actions(array $form, FormStateInterface $form_state) { + $actions = parent::actions($form, $form_state); + $actions['submit']['#value'] = t('Update Migration Group'); + return $actions; + } + +} diff --git a/migrate_tools/src/Form/MigrationGroupFormBase.php b/migrate_tools/src/Form/MigrationGroupFormBase.php new file mode 100644 index 0000000000000000000000000000000000000000..e914cf3282246893c602da97cd4f141afe750b5d --- /dev/null +++ b/migrate_tools/src/Form/MigrationGroupFormBase.php @@ -0,0 +1,189 @@ +<?php + +/** + * @file + * Contains Drupal\migrate_tools\Form\MigrationGroupFormBase. + */ + +namespace Drupal\migrate_tools\Form; + +use Drupal\Core\Entity\EntityForm; +use Drupal\Core\Entity\Query\QueryFactory; +use Drupal\Core\Form\FormStateInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\migrate_plus\Entity\MigrationGroupInterface; + +/** + * Class MigrationGroupFormBase. + * + * @package Drupal\migrate_tools\Form + * + * @ingroup migrate_tools + */ +class MigrationGroupFormBase extends EntityForm { + + /** + * @var \Drupal\Core\Entity\Query\QueryFactory + */ + protected $entityQueryFactory; + + /** + * Construct the MigrationGroupFormBase. + * + * For simple entity forms, there's no need for a constructor. Our migration group form + * base, however, requires an entity query factory to be injected into it + * from the container. We later use this query factory to build an entity + * query for the exists() method. + * + * @param \Drupal\Core\Entity\Query\QueryFactory $query_factory + * An entity query factory for the migration group entity type. + */ + public function __construct(QueryFactory $query_factory) { + $this->entityQueryFactory = $query_factory; + } + + /** + * Factory method for MigrationGroupFormBase. + */ + public static function create(ContainerInterface $container) { + return new static($container->get('entity.query')); + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::form(). + * + * Builds the entity add/edit form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * An associative array containing the current state of the form. + * + * @return array + * An associative array containing the robot add/edit form. + */ + public function buildForm(array $form, FormStateInterface $form_state) { + // Get anything we need from the base class. + $form = parent::buildForm($form, $form_state); + + /** @var MigrationGroupInterface $migration_group */ + $migration_group = $this->entity; + + // Build the form. + $form['label'] = array( + '#type' => 'textfield', + '#title' => $this->t('Label'), + '#maxlength' => 255, + '#default_value' => $migration_group->label(), + '#required' => TRUE, + ); + $form['id'] = array( + '#type' => 'machine_name', + '#title' => $this->t('Machine name'), + '#default_value' => $migration_group->id(), + '#machine_name' => array( + 'exists' => array($this, 'exists'), + 'replace_pattern' => '([^a-z0-9_]+)|(^custom$)', + 'error' => 'The machine-readable name must be unique, and can only contain lowercase letters, numbers, and underscores. Additionally, it can not be the reserved word "custom".', + ), + '#disabled' => !$migration_group->isNew(), + ); + $form['description'] = array( + '#type' => 'textfield', + '#title' => $this->t('Description'), + '#maxlength' => 255, + '#default_value' => $migration_group->get('description'), + ); + $form['source_type'] = array( + '#type' => 'textfield', + '#title' => $this->t('Source type'), + '#description' => $this->t('Type of source system the group is migrating from, for example "Drupal 6" or "WordPress 4".'), + '#maxlength' => 255, + '#default_value' => $migration_group->get('source_type'), + ); + + // Return the form. + return $form; + } + + /** + * Checks for an existing migration group. + * + * @param string|int $entity_id + * The entity ID. + * @param array $element + * The form element. + * @param FormStateInterface $form_state + * The form state. + * + * @return bool + * TRUE if this format already exists, FALSE otherwise. + */ + public function exists($entity_id, array $element, FormStateInterface $form_state) { + // Use the query factory to build a new robot entity query. + $query = $this->entityQueryFactory->get('migration_group'); + + // Query the entity ID to see if its in use. + $result = $query->condition('id', $element['#field_prefix'] . $entity_id) + ->execute(); + + // We don't need to return the ID, only if it exists or not. + return (bool) $result; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::actions(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An array of supported actions for the current entity form. + */ + protected function actions(array $form, FormStateInterface $form_state) { + // Get the basic actins from the base class. + $actions = parent::actions($form, $form_state); + + // Change the submit button text. + $actions['submit']['#value'] = $this->t('Save'); + + // Return the result. + return $actions; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + */ + public function save(array $form, FormStateInterface $form_state) { + $migration_group = $this->getEntity(); + $status = $migration_group->save(); + + // Grab the URL of the new entity. We'll use it in the message. + $url = $migration_group->urlInfo(); + + // Create an edit link. + $edit_link = $this->l(t('Edit'), $url); + + if ($status == SAVED_UPDATED) { + // If we edited an existing entity... + drupal_set_message($this->t('Migration group %label has been updated.', array('%label' => $migration_group->label()))); + $this->logger('contact')->notice('Migration group %label has been updated.', ['%label' => $migration_group->label(), 'link' => $edit_link]); + } + else { + // If we created a new entity... + drupal_set_message($this->t('Migration group %label has been added.', array('%label' => $migration_group->label()))); + $this->logger('contact')->notice('Migration group %label has been added.', ['%label' => $migration_group->label(), 'link' => $edit_link]); + } + + // Redirect the user back to the listing route after the save operation. + $form_state->setRedirect('entity.migration_group.list'); + } + +}