updated contrib modules : migrate_tools, migrate_plus, piwik -> matomo, color_field, config_filter, admin_toolbar

This commit is contained in:
2018-09-12 14:41:53 +02:00
parent b01aa458f8
commit 4caa864a8f
176 changed files with 8874 additions and 1500 deletions
@@ -1,23 +1,27 @@
{
"name": "drupal/migrate_tools",
"description": "Tools to assist in developing and running migrations.",
"type": "drupal-module",
"homepage": "http://drupal.org/project/migrate_tools",
"support": {
"issues": "http://drupal.org/project/migrate_tools",
"irc": "irc://irc.freenode.org/drupal-migrate",
"source": "http://cgit.drupalcode.org/migrate_tools"
},
"license": "GPL-2.0+",
"require-dev": {
"drupal/coder": "^8"
},
"minimum-stability": "dev",
"extra": {
"drush": {
"services": {
"drush.services.yml": "^9"
}
"name": "drupal/migrate_tools",
"description": "Tools to assist in developing and running migrations.",
"type": "drupal-module",
"homepage": "http://drupal.org/project/migrate_tools",
"support": {
"issues": "http://drupal.org/project/migrate_tools",
"irc": "irc://irc.freenode.org/drupal-migrate",
"source": "http://cgit.drupalcode.org/migrate_tools"
},
"license": "GPL-2.0+",
"require": {
"drupal/migrate_plus": "^4"
},
"require-dev": {
"drupal/coder": "^8",
"drupal/migrate_source_csv": "^2.2"
},
"minimum-stability": "dev",
"extra": {
"drush": {
"services": {
"drush.services.yml": "^9"
}
}
}
}
@@ -6,9 +6,11 @@ package: Migration
dependencies:
- drupal:migrate (>=8.3)
- migrate_plus:migrate_plus
test_dependencies:
- migrate_source_csv:migrate_source_csv (>=8.x-2.2)
# Information added by Drupal.org packaging script on 2018-02-23
version: '8.x-4.0-beta3'
# Information added by Drupal.org packaging script on 2018-08-27
version: '8.x-4.0'
core: '8.x'
project: 'migrate_tools'
datestamp: 1519400307
datestamp: 1535380087
@@ -39,3 +39,15 @@ entity.migration.delete_form:
base_route: entity.migration.overview
title: Delete
weight: 10
entity.migration.overview_general_edit:
title: Overview
route_name: entity.migration.edit_form
parent_id: entity.migration.edit_form
entity.migration.overview_source_edit:
title: Source
route_name: migrate_tools.source_csv
parent_id: entity.migration.edit_form
weight: 1
@@ -28,3 +28,31 @@ function migrate_tools_entity_type_build(array &$entity_types) {
->setLinkTemplate('edit-form', '/admin/structure/migrate/manage/{migration_group}')
->setLinkTemplate('delete-form', '/admin/structure/migrate/manage/{migration_group}/delete');
}
/**
* Implements hook_migration_plugins_alter().
*/
function migrate_tools_migration_plugins_alter(array &$migrations) {
/** @var \Drupal\Core\TempStore\PrivateTempStoreFactory $store */
$tempStoreFactory = \Drupal::service('tempstore.private');
$store = $tempStoreFactory->get('migrate_tools');
// TODO: remove work-around after
// https://www.drupal.org/project/drupal/issues/2860341 is fixed.
if (!\Drupal::request()->hasSession()) {
$session = \Drupal::service('session');
\Drupal::request()->setSession($session);
$session->start();
}
// Get the list of changed migrations.
$migrationsChanged = $store->get('migrations_changed');
if (isset($store) && (is_array($migrationsChanged))) {
// Alter the source column names for each changed migration.
foreach ($migrationsChanged as $id) {
$data = $store->get($id);
if (isset($data['changed'])) {
$migrations[$id]['source']['column_names'] = $data['changed'];
}
}
}
}
@@ -58,67 +58,140 @@ entity.migration.overview:
defaults:
_controller: '\Drupal\migrate_tools\Controller\MigrationController::overview'
_title: 'Migration overview'
_migrate_group: true
requirements:
_permission: 'administer migrations'
options:
parameters:
migration:
type: entity:migration
migration_group:
type: entity:migration_group
entity.migration.source:
path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/source'
defaults:
_controller: '\Drupal\migrate_tools\Controller\MigrationController::source'
_title: 'Source'
_migrate_group: true
requirements:
_permission: 'administer migrations'
options:
parameters:
migration:
type: entity:migration
migration_group:
type: entity:migration_group
entity.migration.process:
path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/process'
defaults:
_controller: '\Drupal\migrate_tools\Controller\MigrationController::process'
_title: 'Process'
_migrate_group: true
requirements:
_permission: 'administer migrations'
options:
parameters:
migration:
type: entity:migration
migration_group:
type: entity:migration_group
entity.migration.process.run:
path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/process/run'
defaults:
_controller: '\Drupal\migrate_tools\Controller\MigrationController::run'
_title: 'Run'
_migrate_group: true
requirements:
_permission: 'administer migrations'
options:
parameters:
migration:
type: entity:migration
migration_group:
type: entity:migration_group
entity.migration.destination:
path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/destination'
defaults:
_controller: '\Drupal\migrate_tools\Controller\MigrationController::destination'
_title: 'Destination'
_migrate_group: true
requirements:
_permission: 'administer migrations'
options:
parameters:
migration:
type: entity:migration
migration_group:
type: entity:migration_group
# This is the router item for editing our migration entity.
entity.migration.edit_form:
path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/edit'
defaults:
_title: 'Edit migration'
_entity_form: migration.edit
_migrate_group: true
requirements:
_entity_access: migration.update
options:
parameters:
migration:
type: entity:migration
migration_group:
type: entity:migration_group
# This is the router item for deleting an instance of our migration entity.
entity.migration.delete_form:
path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/delete'
defaults:
_title: 'Delete migration'
_entity_form: migration.delete
_migrate_group: true
requirements:
_entity_access: migration.delete
options:
parameters:
migration:
type: entity:migration
migration_group:
type: entity:migration_group
migrate_tools.messages:
path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/messages'
defaults:
_controller: '\Drupal\migrate_tools\Controller\MessageController::overview'
_title: 'Messages'
_migrate_group: true
requirements:
_permission: 'administer migrations'
options:
parameters:
migration:
type: entity:migration
migration_group:
type: entity:migration_group
migrate_tools.execute:
path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/execute'
defaults:
_form: '\Drupal\migrate_tools\Form\MigrationExecuteForm'
_title: 'Execute migration'
_migrate_group: true
requirements:
_permission: 'administer migrations'
options:
parameters:
migration:
type: entity:migration
migration_group:
type: entity:migration_group
migrate_tools.source_csv:
path: '/admin/structure/migrate/manage/{migration_group}/migrations/{migration}/source/edit'
defaults:
_form: 'Drupal\migrate_tools\Form\SourceCsvForm'
_migrate_group: true
requirements:
_permission: 'administer migrations'
_custom_access: 'Drupal\migrate_tools\Form\SourceCsvForm::access'
options:
parameters:
migration:
type: entity:migration
migration_group:
type: entity:migration_group
@@ -3,3 +3,7 @@ services:
class: Drupal\Core\Logger\LoggerChannel
factory: logger.factory:get
arguments: ['migrate_tools']
route_processor.migrate_group:
class: Drupal\migrate_tools\Routing\RouteProcessor
tags:
- { name: route_processor_outbound }
@@ -67,12 +67,7 @@ class MigrateToolsCommands extends DrushCommands {
* @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $keyValue
* Key-value store service.
*/
public function __construct(
MigrationPluginManager $migrationPluginManager,
DateFormatter $dateFormatter,
EntityTypeManagerInterface $entityTypeManager,
KeyValueFactoryInterface $keyValue
) {
public function __construct(MigrationPluginManager $migrationPluginManager, DateFormatter $dateFormatter, EntityTypeManagerInterface $entityTypeManager, KeyValueFactoryInterface $keyValue) {
parent::__construct();
$this->migrationPluginManager = $migrationPluginManager;
$this->dateFormatter = $dateFormatter;
@@ -123,14 +118,7 @@ class MigrateToolsCommands extends DrushCommands {
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
* Migrations status formatted as table.
*/
public function status(
$migration_names = '',
array $options = [
'group' => NULL,
'tag' => NULL,
'names-only' => NULL,
]
) {
public function status($migration_names = '', array $options = ['group' => NULL, 'tag' => NULL, 'names-only' => NULL]) {
$names_only = $options['names-only'];
$migrations = $this->migrationsList($migration_names, $options);
@@ -271,20 +259,7 @@ class MigrateToolsCommands extends DrushCommands {
* @throws \Exception
* If there are not enough parameters to the command.
*/
public function import(
$migration_names = '',
array $options = [
'all' => NULL,
'group' => NULL,
'tag' => NULL,
'limit' => NULL,
'feedback' => NULL,
'idlist' => NULL,
'update' => NULL,
'force' => NULL,
'execute-dependencies' => NULL,
]
) {
public function import($migration_names = '', array $options = ['all' => NULL, 'group' => NULL, 'tag' => NULL, 'limit' => NULL, 'feedback' => NULL, 'idlist' => NULL, 'update' => NULL, 'force' => NULL, 'execute-dependencies' => NULL]) {
$group_names = $options['group'];
$tag_names = $options['tag'];
$all = $options['all'];
@@ -293,7 +268,7 @@ class MigrateToolsCommands extends DrushCommands {
throw new \Exception(dt('You must specify --all, --group, --tag or one or more migration names separated by commas'));
}
foreach (['limit', 'feedback', 'idlist', 'update', 'force'] as $option) {
foreach (['limit', 'feedback', 'idlist', 'update', 'force', 'execute-dependencies'] as $option) {
if ($options[$option]) {
$additional_options[$option] = $options[$option];
}
@@ -346,15 +321,7 @@ class MigrateToolsCommands extends DrushCommands {
* @throws \Exception
* If there are not enough parameters to the command.
*/
public function rollback(
$migration_names = '',
array $options = [
'all' => NULL,
'group' => NULL,
'tag' => NULL,
'feedback' => NULL,
]
) {
public function rollback($migration_names = '', array $options = ['all' => NULL, 'group' => NULL, 'tag' => NULL, 'feedback' => NULL]) {
$group_names = $options['group'];
$tag_names = $options['tag'];
$all = $options['all'];
@@ -496,52 +463,47 @@ class MigrateToolsCommands extends DrushCommands {
* @validate-module-enabled migrate_tools
*
* @aliases mmsg,migrate-messages
*
* @field-labels
* source_ids_hash: Source IDs Hash
* level: Level
* message: Message
* @default-fields source_ids_hash,level,message
*
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
* Source fields of the given migration formatted as a table.
*/
public function messages($migration_id, array $options = ['csv' => NULL]) {
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$migration = $this->migrationPluginManager->createInstance(
$migration_id
);
if ($migration) {
$map = $migration->getIdMap();
$first = TRUE;
$table = [];
foreach ($map->getMessageIterator() as $row) {
unset($row->msgid);
if ($first) {
// @todo: Ideally, replace sourceid* with source key names. Or, should
// getMessageIterator() do that?
foreach ($row as $column => $value) {
$table[0][] = $column;
}
$first = FALSE;
}
$table[] = (array) $row;
}
if (empty($table)) {
$this->logger()->notice(dt('No messages for this migration'));
}
else {
if ($options['csv']) {
foreach ($table as $row) {
fputcsv(STDOUT, $row);
}
}
else {
$widths = [];
foreach ($table[0] as $header) {
$widths[] = strlen($header) + 1;
}
drush_print_table($table);
}
}
}
else {
if (!$migration) {
$this->logger()->error(
dt('Migration @id does not exist', ['@id' => $migration_id])
);
return NULL;
}
$map = $migration->getIdMap();
$table = [];
foreach ($map->getMessageIterator() as $row) {
unset($row->msgid);
$table[] = (array) $row;
}
if (empty($table)) {
$this->logger()->notice(dt('No messages for this migration'));
return NULL;
}
if ($options['csv']) {
fputcsv(STDOUT, array_keys($table[0]));
foreach ($table as $row) {
fputcsv(STDOUT, $row);
}
return NULL;
}
return new RowsOfFields($table);
}
/**
@@ -558,6 +520,14 @@ class MigrateToolsCommands extends DrushCommands {
* @validate-module-enabled migrate_tools
*
* @aliases mfs, migrate-fields-source
*
* @field-labels
* machine_name: Machine Name
* description: Description
* @default-fields machine_name,description
*
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
* Source fields of the given migration formatted as a table.
*/
public function fieldsSource($migration_id) {
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
@@ -568,9 +538,12 @@ class MigrateToolsCommands extends DrushCommands {
$source = $migration->getSourcePlugin();
$table = [];
foreach ($source->fields() as $machine_name => $description) {
$table[] = [strip_tags($description), $machine_name];
$table[] = [
'machine_name' => $machine_name,
'description' => strip_tags($description),
];
}
drush_print_table($table);
return new RowsOfFields($table);
}
else {
$this->logger()->error(
@@ -690,17 +663,23 @@ class MigrateToolsCommands extends DrushCommands {
* @throws \Exception
* If some migrations failed during execution.
*/
protected function executeMigration(
MigrationInterface $migration,
$migration_id,
array $options = []
) {
protected function executeMigration(MigrationInterface $migration, $migration_id, array $options = []) {
// Keep track of all migrations run during this command so the same
// migration is not run multiple times.
static $executed_migrations = [];
if (isset($options['execute-dependencies'])) {
if ($required_IDS = $migration->get('requirements')) {
$required_migrations = $migration->get('requirements');
$required_migrations = array_filter($required_migrations, function ($value) use ($executed_migrations) {
return !isset($executed_migrations[$value]);
});
if (!empty($required_migrations)) {
$manager = $this->migrationPluginManager;
$required_migrations = $manager->createInstances($required_IDS);
$required_migrations = $manager->createInstances($required_migrations);
$dependency_options = array_merge($options, ['is_dependency' => TRUE]);
array_walk($required_migrations, __FUNCTION__, $dependency_options);
array_walk($required_migrations, [$this, __FUNCTION__], $dependency_options);
$executed_migrations += $required_migrations;
}
}
if (!empty($options['force'])) {
@@ -712,6 +691,7 @@ class MigrateToolsCommands extends DrushCommands {
$executable = new MigrateExecutable($migration, $this->getMigrateMessage(), $options);
// drush_op() provides --simulate support.
drush_op([$executable, 'import']);
$executed_migrations += [$migration_id => $migration_id];
if ($count = $executable->getFailedCount()) {
// Nudge Drush to use a non-zero exit code.
throw new \Exception(
@@ -7,6 +7,8 @@ use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Connection;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\migrate_plus\Entity\MigrationGroupInterface;
use Drupal\migrate_plus\Entity\MigrationInterface as MigratePlusMigrationInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -71,21 +73,19 @@ class MessageController extends ControllerBase {
*
* Messages are truncated at 56 chars.
*
* @param string $migration_group
* Machine name of the migration's group.
*
* @param string $migration
* Machine name of the migration.
* @param \Drupal\migrate_plus\Entity\MigrationGroupInterface $migration_group
* The migration group.
* @param \Drupal\migrate_plus\Entity\MigrationInterface $migration
* The $migration.
*
* @return array
* A render array as expected by drupal_render().
*/
public function overview($migration_group, $migration) {
public function overview(MigrationGroupInterface $migration_group, MigratePlusMigrationInterface $migration) {
$rows = [];
$classes = static::getLogLevelClassMap();
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$migration = $this->migrationPluginManager->createInstance($migration);
$source_id_field_names = array_keys($migration->getSourcePlugin()->getIds());
$migration_plugin = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray());
$source_id_field_names = array_keys($migration_plugin->getSourcePlugin()->getIds());
$column_number = 1;
foreach ($source_id_field_names as $source_id_field_name) {
$header[] = [
@@ -104,8 +104,8 @@ class MessageController extends ControllerBase {
'field' => 'message',
];
$message_table = $migration->getIdMap()->messageTableName();
$map_table = $migration->getIdMap()->mapTableName();
$message_table = $migration_plugin->getIdMap()->messageTableName();
$map_table = $migration_plugin->getIdMap()->mapTableName();
$query = $this->database->select($message_table, 'msg')
->extend('\Drupal\Core\Database\Query\PagerSelectExtender')
->extend('\Drupal\Core\Database\Query\TableSortExtender');
@@ -8,6 +8,8 @@ use Drupal\Component\Utility\Html;
use Drupal\Core\Routing\CurrentRouteMatch;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\migrate_plus\Entity\MigrationGroupInterface;
use Drupal\migrate_plus\Entity\MigrationInterface;
use Drupal\migrate_tools\MigrateBatchExecutable;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Url;
@@ -58,19 +60,15 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
/**
* Displays an overview of a migration entity.
*
* @param string $migration_group
* Machine name of the migration's group.
* @param string $migration
* Machine name of the migration.
* @param \Drupal\migrate_plus\Entity\MigrationGroupInterface $migration_group
* The migration group.
* @param \Drupal\migrate_plus\Entity\MigrationInterface $migration
* The $migration.
*
* @return array
* A render array as expected by drupal_render().
*/
public function overview($migration_group, $migration) {
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$migration = $this->migrationPluginManager->createInstance($migration);
public function overview(MigrationGroupInterface $migration_group, MigrationInterface $migration) {
$build['overview'] = [
'#type' => 'fieldset',
'#title' => $this->t('Overview'),
@@ -78,7 +76,7 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
$build['overview']['group'] = [
'#title' => $this->t('Group:'),
'#markup' => Xss::filterAdmin($migration_group),
'#markup' => Xss::filterAdmin($migration_group->label()),
'#type' => 'item',
];
@@ -87,8 +85,8 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
'#markup' => Xss::filterAdmin($migration->label()),
'#type' => 'item',
];
$migration_dependencies = $migration->getMigrationDependencies();
$migration_plugin = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray());
$migration_dependencies = $migration_plugin->getMigrationDependencies();
if (!empty($migration_dependencies['required'])) {
$build['overview']['dependencies'] = [
'#title' => $this->t('Migration Dependencies') ,
@@ -110,19 +108,15 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
/**
* Display source information of a migration entity.
*
* @param string $migration_group
* Machine name of the migration's group.
* @param string $migration
* Machine name of the migration.
* @param \Drupal\migrate_plus\Entity\MigrationGroupInterface $migration_group
* The migration group.
* @param \Drupal\migrate_plus\Entity\MigrationInterface $migration
* The $migration.
*
* @return array
* A render array as expected by drupal_render().
*/
public function source($migration_group, $migration) {
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$migration = $this->migrationPluginManager->createInstance($migration);
public function source(MigrationGroupInterface $migration_group, MigrationInterface $migration) {
// Source field information.
$build['source'] = [
'#type' => 'fieldset',
@@ -133,8 +127,8 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
'id' => 'migration-detail-source',
],
];
$source = $migration->getSourcePlugin();
$migration_plugin = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray());
$source = $migration_plugin->getSourcePlugin();
$build['source']['query'] = [
'#type' => 'item',
'#title' => $this->t('Query'),
@@ -142,7 +136,7 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
];
$header = [$this->t('Machine name'), $this->t('Description')];
$rows = [];
foreach ($source->fields($migration) as $machine_name => $description) {
foreach ($source->fields($migration_plugin) as $machine_name => $description) {
$rows[] = [
['data' => Html::escape($machine_name)],
['data' => Xss::filterAdmin($description)],
@@ -162,22 +156,20 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
/**
* Run a migration.
*
* @param string $migration_group
* Machine name of the migration's group.
* @param string $migration
* Machine name of the migration.
* @param \Drupal\migrate_plus\Entity\MigrationGroupInterface $migration_group
* The migration group.
* @param \Drupal\migrate_plus\Entity\MigrationInterface $migration
* The $migration.
*
* @return array
* A render array as expected by drupal_render().
*/
public function run($migration_group, $migration) {
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$migration = $this->migrationPluginManager->createInstance($migration);
public function run(MigrationGroupInterface $migration_group, MigrationInterface $migration) {
$migrateMessage = new MigrateMessage();
$options = [];
$executable = new MigrateBatchExecutable($migration, $migrateMessage, $options);
$migration_plugin = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray());
$executable = new MigrateBatchExecutable($migration_plugin, $migrateMessage, $options);
$executable->batchImport();
$migration_group = $this->currentRouteMatch->getParameter('migration_group');
@@ -191,18 +183,16 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
/**
* Display process information of a migration entity.
*
* @param string $migration_group
* Machine name of the migration's group.
* @param string $migration
* Machine name of the migration.
* @param \Drupal\migrate_plus\Entity\MigrationGroupInterface $migration_group
* The migration group.
* @param \Drupal\migrate_plus\Entity\MigrationInterface $migration
* The $migration.
*
* @return array
* A render array as expected by drupal_render().
*/
public function process($migration_group, $migration) {
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$migration = $this->migrationPluginManager->createInstance($migration);
public function process(MigrationGroupInterface $migration_group, MigrationInterface $migration) {
$migration_plugin = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray());
// Process information.
$build['process'] = [
@@ -217,7 +207,7 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
$this->t('Default'),
];
$rows = [];
foreach ($migration->getProcess() as $destination_id => $process_line) {
foreach ($migration_plugin->getProcess() as $destination_id => $process_line) {
$row = [];
$row[] = ['data' => Html::escape($destination_id)];
if (isset($process_line[0]['source'])) {
@@ -251,7 +241,7 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
$build['process']['run'] = [
'#type' => 'link',
'#title' => $this->t('Run'),
'#url' => Url::fromRoute('entity.migration.process.run', ['migration_group' => $migration_group, 'migration' => $migration->id()]),
'#url' => Url::fromRoute('entity.migration.process.run', ['migration_group' => $migration_group->id(), 'migration' => $migration->id()]),
];
return $build;
@@ -260,17 +250,16 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
/**
* Displays destination information of a migration entity.
*
* @param string $migration_group
* Machine name of the migration's group.
* @param string $migration
* Machine name of the migration.
* @param \Drupal\migrate_plus\Entity\MigrationGroupInterface $migration_group
* The migration group.
* @param \Drupal\migrate_plus\Entity\MigrationInterface $migration
* The $migration.
*
* @return array
* A render array as expected by drupal_render().
*/
public function destination($migration_group, $migration) {
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$migration = $this->migrationPluginManager->createInstance($migration);
public function destination(MigrationGroupInterface $migration_group, MigrationInterface $migration) {
$migration_plugin = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray());
// Destination field information.
$build['destination'] = [
@@ -282,7 +271,7 @@ class MigrationController extends ControllerBase implements ContainerInjectionIn
'id' => 'migration-detail-destination',
],
];
$destination = $migration->getDestinationPlugin();
$destination = $migration_plugin->getDestinationPlugin();
$build['destination']['type'] = [
'#type' => 'item',
'#title' => $this->t('Type'),
@@ -161,7 +161,7 @@ class MigrationListBuilder extends ConfigEntityListBuilder implements EntityHand
$row['status'] = $migration->getStatusLabel();
}
catch (PluginException $e) {
$this->logger->warning('Migration entity id %id is malformed', ['%id' => $migration_entity->id()]);
$this->logger->warning('Migration entity id %id is malformed: %orig', ['%id' => $migration_entity->id(), '%orig' => $e->getMessage()]);
return NULL;
}
@@ -60,7 +60,6 @@ class MigrationExecuteForm extends FormBase {
return $form;
}
/**
* Get Operations.
*/
@@ -124,7 +123,6 @@ class MigrationExecuteForm extends FormBase {
return $form;
}
/**
* {@inheritdoc}
*/
@@ -162,12 +160,10 @@ class MigrationExecuteForm extends FormBase {
$force = 0;
}
$migration_name = \Drupal::routeMatch()->getParameter('migration');
if ($migration_name) {
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$migration = $this->migrationPluginManager->createInstance($migration_name);
$migration = \Drupal::routeMatch()->getParameter('migration');
if ($migration) {
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration_plugin */
$migration_plugin = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray());
$migrateMessage = new MigrateMessage();
switch ($operation) {
@@ -179,7 +175,7 @@ class MigrationExecuteForm extends FormBase {
'force' => $force,
];
$executable = new MigrateBatchExecutable($migration, $migrateMessage, $options);
$executable = new MigrateBatchExecutable($migration_plugin, $migrateMessage, $options);
$executable->batchImport();
break;
@@ -192,20 +188,20 @@ class MigrationExecuteForm extends FormBase {
'force' => $force,
];
$executable = new MigrateBatchExecutable($migration, $migrateMessage, $options);
$executable = new MigrateBatchExecutable($migration_plugin, $migrateMessage, $options);
$executable->rollback();
break;
case 'stop':
$migration->interruptMigration(MigrationInterface::RESULT_STOPPED);
$migration_plugin->interruptMigration(MigrationInterface::RESULT_STOPPED);
break;
case 'reset':
$migration->setStatus(MigrationInterface::STATUS_IDLE);
$migration_plugin->setStatus(MigrationInterface::STATUS_IDLE);
break;
@@ -0,0 +1,453 @@
<?php
namespace Drupal\migrate_tools\Form;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\Core\TempStore\TempStoreException;
use Drupal\Core\Url;
use Drupal\migrate_plus\Entity\MigrationInterface;
use Drupal\migrate_source_csv\Plugin\migrate\source\CSV;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
/**
* Provides an edit form for CSV source plugin column_names configuration.
*
* This means you can tell the migration which columns your data is in and no
* longer edit the CSV to fit the column order set in the migration or edit the
* migration yml itself.
*
* Changes made to the column configuration, or aliases, are stored in the
* private migrate_toools private store keyed by the migration plugin id. The
* data stored for each migrations consists of two arrays, the 'original' column
* aliases and the 'updated' column aliases.
*
* An addtional list of all changed migration id is kept in the store, in the
* key 'migrations_changed'
*
* Private Store Usage:
* migrations_changed: An array of the ids of the migrations that have been
* changed:
* [migration_id]: The original and changed values for this column assignments
*
* Format of the source configuration saved in the store.
* @code
* migration_id
* original
* column_index1
* property 1 => label 1
* column_index2
* property 2 => label 2
* updated
* column_index1
* property 2 => label 2
* column_index2
* property 1 => label 1
* @endcode
*
* Example source configuration.
* @code
* custom_migration
* original
* 2
* title => title
* 3
* body => foo
* updated
* 8
* title => new_title
* 9
* body => new_body
* @endcode
*/
class SourceCsvForm extends FormBase {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* Plugin manager for migration plugins.
*
* @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
*/
protected $migrationPluginManager;
/**
* The messenger service.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* Temporary store for column assignment changes.
*
* @var \Drupal\Core\TempStore\PrivateTempStoreFactory
*/
protected $store;
/**
* The file object that reads the CSV file.
*
* @var \SplFileObject
*/
protected $file = NULL;
/**
* The migration being examined.
*
* @var \Drupal\migrate\Plugin\MigrationInterface
*/
protected $migration;
/**
* The migration plugin id.
*
* @var string
*/
protected $id;
/**
* The array of columns names from the CSV source plugin.
*
* @var array
*/
protected $columnNames;
/**
* An array of options for the column select form field..
*
* @var array
*/
protected $options;
/**
* An array of modified and original column_name source plugin configuration.
*
* @var array
*/
protected $sourceConfiguration;
/**
* Constructs new SourceCsvForm object.
*
* @param \Drupal\Core\Database\Connection $connection
* The database connection.
* @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager
* The plugin manager for config entity-based migrations.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger service.
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $private_store
* The private store.
*/
public function __construct(Connection $connection, MigrationPluginManagerInterface $migration_plugin_manager, MessengerInterface $messenger, PrivateTempStoreFactory $private_store) {
$this->connection = $connection;
$this->migrationPluginManager = $migration_plugin_manager;
$this->messenger = $messenger;
$this->store = $private_store->get('migrate_tools');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database'),
$container->get('plugin.manager.migration'),
$container->get('messenger'),
$container->get('tempstore.private')
);
}
/**
* A custom access check.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account.
* @param \Drupal\migrate_plus\Entity\MigrationInterface $migration
* The $migration.
*
* @return \Drupal\Core\Access\AccessResult
* Allowed or forbidden, neutral if tempstore is empty.
*/
public function access(AccountInterface $account, MigrationInterface $migration) {
try {
$this->migration = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray());
}
catch (PluginException $e) {
return AccessResult::forbidden();
}
if ($this->migration) {
if ($source = $this->migration->getSourcePlugin()) {
if (is_a($source, CSV::class)) {
return AccessResult::allowed();
}
}
}
return AccessResult::forbidden();
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, MigrationInterface $migration = NULL) {
try {
// @TODO: remove this horrible config work around after
// https://www.drupal.org/project/drupal/issues/2986665 is fixed.
$this->migration = $this->migrationPluginManager->createInstance($migration->id(), $migration->toArray());
/** @var \Drupal\migrate_source_csv\Plugin\migrate\source\CSV $source */
$source = $this->migration->getSourcePlugin();
$source->setConfiguration($migration->toArray()['source']);
}
catch (PluginException $e) {
return AccessResult::forbidden();
}
// Get the source file after the properties are initialized.
$source->initializeIterator();
$this->file = $source->getFile();
// Set the input field options to the header row values or, if there are
// no such values, use an indexed array.
if ($this->file->getHeaderRowCount() > 0) {
$this->options = $this->getHeaderColumnNames();
}
else {
for ($i = 0; $i < $this->getFileColumnCount(); $i++) {
$this->options[$i] = $i;
}
}
// Set the store key to the migration id.
$this->id = $this->migration->getPluginId();
// Get the column names from the file or from the store, if updated
// values are in the store.
$this->sourceConfiguration = $this->store->get($this->id);
if (isset($this->sourceConfiguration['changed'])) {
if ($config = $this->sourceConfiguration['changed']) {
$this->columnNames = $config;
}
}
else {
// Get the calculated column names. This is either the header rows or
// the configuration column_name value.
$this->columnNames = $this->file->getColumnNames();
if (!isset($this->sourceConfiguration['original'])) {
// Save as the original values.
$this->sourceConfiguration['original'] = $this->columnNames;
$this->store->set($this->id, $this->sourceConfiguration);
}
}
$form['#title'] = $this->t('Column Aliases');
$form['heading'] = [
'#type' => 'item',
'#title' => $this->t(':label', [':label' => $this->migration->label()]),
'#description' => '<p>' . $this->t('You can change the columns to be used by this migration for each source property.') . '</p>',
];
// Create a form field for each column in this migration.
foreach ($this->columnNames as $index => $data) {
$property_name = key($data);
$default_value = $index;
$label = $this->getLabel($this->sourceConfiguration['original'], $property_name);
$description = $this->t('Select the column where the data for <em>:label</em>, property <em>:property</em>, will be found.', [
':label' => $label,
':property' => $property_name,
]);
$form['aliases'][$property_name] = [
'#type' => 'select',
'#title' => $label,
'#description' => $description,
'#options' => $this->options,
'#default_value' => $default_value,
];
}
$form['actions'] = ['#type' => 'actions'];
$form['actions']['submit'] = [
'#type' => 'submit',
'#button_type' => 'primary',
'#value' => $this->t('Submit'),
];
$form['actions']['cancel'] = [
'#type' => 'submit',
'#value' => $this->t('Cancel'),
'#submit' => ['::cancel'],
'#limit_validation_errors' => [],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Display an error message if two properties have the same source column.
$values = [];
foreach ($this->columnNames as $index => $data) {
$property_name = key($data);
$value = $form_state->getValue($property_name);
if (in_array($value, $values)) {
$form_state->setErrorByName($property_name, $this->t('Source properties can not share the same source column.'));
}
$values[] = $value;
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Create a new column_names configuration.
$new_column_names = [];
foreach ($this->columnNames as $index => $data) {
// Keep the property name as it is used in the process pipeline.
$property_name = key($data);
// Get the new column number from the form alias field for this property.
$new_index = $form_state->getValue($property_name);
// Get the new label from the options array.
$new_label = $this->options[$new_index];
// Save using the new column number and new label.
$new_column_names[$new_index] = [$property_name => $new_label];
}
// Update the file columns.
$this->file->setColumnNames($new_column_names);
// Save as updated in the store.
$this->sourceConfiguration['changed'] = $new_column_names;
$this->store->set($this->id, $this->sourceConfiguration);
$changed = ($this->store->get('migrations_changed')) ? $this->store->get('migrations_changed') : [];
if (!in_array($this->id, $changed)) {
$changed[] = $this->id;
$this->store->set('migrations_changed', $changed);
}
}
/**
* Form submission handler for the 'cancel' action.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function cancel(array $form, FormStateInterface $form_state) {
// Restore the file columns to the original settings.
$this->file->setColumnNames($this->sourceConfiguration['original']);
// Remove this migration from the store.
try {
$this->store->delete($this->id);
}
catch (TempStoreException $e) {
$this->messenger->addError($e->getMessage());
}
$migrationsChanged = $this->store->get('migrations_changed');
unset($migrationsChanged[$this->id]);
try {
$this->store->set('migrations_changed', $migrationsChanged);
}
catch (TempStoreException $e) {
$this->messenger->addError($e->getMessage());
}
$form_state->setRedirect('entity.migration_group.list');
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'migrate_tools_source_csv';
}
/**
* {@inheritdoc}
*/
public function getQuestion() {}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return new Url('entity.migration_group.list');
}
/**
* Returns the header row.
*
* Use a new file handle so that CSVFileObject::current() is not executed.
*
* @return array
* The header row.
*/
public function getHeaderColumnNames() {
$row = [];
$fname = $this->file->getPathname();
$handle = fopen($fname, 'r');
if ($handle) {
fseek($handle, $this->file->getHeaderRowCount() - 1);
$row = fgetcsv($handle);
fclose($handle);
}
return $row;
}
/**
* Returns the count of fields in the header row.
*
* Use a new file handle so that CSVFileObject::current() is not executed.
*
* @return int
* The number of fields in the header row.
*/
public function getFileColumnCount() {
$count = 0;
$fname = $this->file->getPathname();
$handle = fopen($fname, 'r');
if ($handle) {
$row = fgetcsv($handle);
$count = count($row);
fclose($handle);
}
return $count;
}
/**
* Gets the label for a given property from a column_names array.
*
* @param array $column_names
* An array of column_names.
* @param string $property_name
* The property name to find a label for.
*
* @return string
* The label for this property.
*/
protected function getLabel(array $column_names, $property_name) {
$label = '';
foreach ($column_names as $column) {
foreach ($column as $key => $value) {
if ($key === $property_name) {
$label = $value;
break;
}
}
}
return $label;
}
}
@@ -35,6 +35,13 @@ class MigrateExecutable extends MigrateExecutableBase {
MigrateIdMapInterface::STATUS_NEEDS_UPDATE => 0,
];
/**
* Counter of map saves, used to detect the item limit threshold.
*
* @var int
*/
protected $itemLimitCounter = 0;
/**
* Counter of map deletions.
*
@@ -128,6 +135,7 @@ class MigrateExecutable extends MigrateExecutableBase {
// Only count saves for this migration.
if ($event->getMap()->getQualifiedMapTableName() == $this->migration->getIdMap()->getQualifiedMapTableName()) {
$fields = $event->getFields();
$this->itemLimitCounter++;
// Distinguish between creation and update.
if ($fields['source_row_status'] == MigrateIdMapInterface::STATUS_IMPORTED &&
$this->preExistingItem
@@ -378,7 +386,7 @@ class MigrateExecutable extends MigrateExecutableBase {
$this->resetCounters();
}
$this->counter++;
if ($this->itemLimit && ($this->getProcessedCount() + 1) >= $this->itemLimit) {
if ($this->itemLimit && ($this->itemLimitCounter + 1) >= $this->itemLimit) {
$event->getMigration()->interruptMigration(MigrationInterface::RESULT_COMPLETED);
}
@@ -0,0 +1,27 @@
<?php
namespace Drupal\migrate_tools\Routing;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\RouteProcessor\OutboundRouteProcessorInterface;
use Symfony\Component\Routing\Route;
/**
* Route processor to expand migrate_group.
*/
class RouteProcessor implements OutboundRouteProcessorInterface {
/**
* {@inheritdoc}
*/
public function processOutbound($route_name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) {
if ($route->hasDefault('_migrate_group')) {
if ($migration = \Drupal::entityTypeManager()->getStorage('migration')->load($parameters['migration'])) {
if ($group = $migration->get('migration_group')) {
$parameters['migration_group'] = $group;
}
}
}
}
}
@@ -0,0 +1,33 @@
langcode: en
status: true
dependencies: { }
id: csv_source_test
label: Test edit of column aliases for CSV source plugin
class: null
field_plugin_method: null
cck_plugin_method: null
migration_tags: { }
migration_group: csv_test
source:
plugin: csv
path: 'public://test.csv'
header_row_count: 1
enclosure: '"'
keys:
- vid
column_names:
0:
vid: 'Vocabulary Id'
1:
name: 'Name'
2:
description: 'Description'
process:
vid: vid
name: name
description: description
destination:
plugin: entity:taxonomy_vocabulary
migration_dependencies:
required: { }
optional: { }
@@ -0,0 +1,4 @@
id: csv_test
label: CSV source plugin edit test
description: Test editting of source plugin via the UI
source_type: CSV
@@ -0,0 +1,15 @@
type: module
name: CSV Source edit test
description: 'Test editing of source plugin via the UI.'
package: Testing
# core: 8.x
dependencies:
- drupal:migrate (>=8.3)
- migrate_plus:migrate_plus
- migrate_plus:migrate_source_csv
# Information added by Drupal.org packaging script on 2018-08-27
version: '8.x-4.0'
core: '8.x'
project: 'migrate_tools'
datestamp: 1535380087
@@ -7,8 +7,8 @@ dependencies:
- drupal:migrate (>=8.3)
- migrate_plus:migrate_plus
# Information added by Drupal.org packaging script on 2018-02-23
version: '8.x-4.0-beta3'
# Information added by Drupal.org packaging script on 2018-08-27
version: '8.x-4.0'
core: '8.x'
project: 'migrate_tools'
datestamp: 1519400307
datestamp: 1535380087
@@ -0,0 +1,241 @@
<?php
namespace Drupal\Tests\migrate_tools\Functional;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\taxonomy\VocabularyInterface;
/**
* Test the CSV column alias edit form.
*
* @requires module migrate_source_csv
*
* @group migrate_tools
*/
class SourceCsvFormTest extends BrowserTestBase {
/**
* Temporary store for column assignment changes.
*
* @var \Drupal\Core\TempStore\PrivateTempStoreFactory
*/
protected $store;
/**
* {@inheritdoc}
*/
protected static $modules = [
'taxonomy',
'migrate',
'migrate_plus',
'migrate_tools',
'migrate_source_csv',
'csv_source_test',
];
/**
* {@inheritdoc}
*/
protected $profile = 'testing';
/**
* The migration group for the test migration.
*
* @var string
*/
protected $group;
/**
* The test migration id.
*
* @var string
*/
protected $migration;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Log in as user 1. Migrations in the UI can only be performed as user 1.
$this->drupalLogin($this->rootUser);
// Setup the file system so we create the source CSV.
$this->container->get('stream_wrapper_manager')->registerWrapper('public', PublicStream::class, StreamWrapperInterface::NORMAL);
$fs = \Drupal::service('file_system');
$fs->mkdir('public://sites/default/files', NULL, TRUE);
// The source data for this test.
$source_data = <<<'EOD'
vid,name,description,hierarchy,weight
tags,Tags,Use tags to group articles,0,0
forums,Sujet de discussion,Forum navigation vocabulary,1,0
test_vocabulary,Test Vocabulary,This is the vocabulary description,1,0
genre,Genre,Genre description,1,0
EOD;
// Write the data to the filepath given in the test migration.
file_put_contents('public://test.csv', $source_data);
// Get the store.
$tempStoreFactory = \Drupal::service('tempstore.private');
$this->store = $tempStoreFactory->get('migrate_tools');
// Select the group and migration to test.
$this->group = 'csv_test';
$this->migration = 'csv_source_test';
}
/**
* Tests the form to edit CSV column aliases.
*
* @throws \Behat\Mink\Exception\ExpectationException
*/
public function testSourceCsvForm() {
// Define the paths to be used.
$executeUrlPath = "/admin/structure/migrate/manage/{$this->group}/migrations/{$this->migration}/execute";
$editUrlPath = "/admin/structure/migrate/manage/{$this->group}/migrations/{$this->migration}/source/edit";
// Assert the test migration is listed.
$this->drupalGet("/admin/structure/migrate/manage/{$this->group}/migrations");
$session = $this->assertSession();
$session->responseContains('Test edit of column aliases for CSV source plugin');
// Proceed to the edit page.
$this->drupalGet($editUrlPath);
$session->responseContains('You can change the columns to be used by this migration for each source property.');
// Test that there are 3 select fields available which match the number of
// properties in the process pipeline.
$this->assertTrue($session->optionExists('edit-vid', 'vid')
->isSelected());
$this->assertTrue($session->optionExists('edit-name', 'name')
->isSelected());
$this->assertTrue($session->optionExists('edit-description', 'description')
->isSelected());
$session->responseNotContains('edit-hierarchy');
$session->responseNotContains('edit-weight');
// Test that all 5 columns in the CSV source are available as options on
// one of the select fields.
$this->assertTrue($session->optionExists('edit-description', 'vid'));
$this->assertTrue($session->optionExists('edit-description', 'name'));
$this->assertTrue($session->optionExists('edit-description', 'description'));
$this->assertTrue($session->optionExists('edit-description', 'hierarchy'));
$this->assertTrue($session->optionExists('edit-description', 'weight'));
// Test that two aliases can not be the same.
$edit = [
'edit-vid' => 2,
'edit-name' => 1,
'edit-description' => 1,
];
$this->drupalPostForm($editUrlPath, $edit, t('Submit'));
$session->responseContains('Source properties can not share the same source column.');
$this->assertTrue($session->optionExists('edit-vid', 'description')
->isSelected());
$this->assertTrue($session->optionExists('edit-name', 'name')
->isSelected());
$this->assertTrue($session->optionExists('edit-description', 'name')
->isSelected());
// Test that changes to all the column aliases are saved.
$edit = [
'edit-vid' => 4,
'edit-name' => 0,
'edit-description' => 1,
];
$this->drupalPostForm($editUrlPath, $edit, t('Submit'));
$this->assertTrue($session->optionExists('edit-vid', 'weight')
->isSelected());
$this->assertTrue($session->optionExists('edit-name', 'vid')
->isSelected());
$this->assertTrue($session->optionExists('edit-description', 'name')
->isSelected());
// Test that the changes are saved to store.
$columnConfiguration = $this->store->get('csv_source_test');
$migrationsChanged = $this->store->get('migrations_changed');
$this->assertSame(['csv_source_test'], $migrationsChanged);
$expected =
[
'original' =>
[
0 => ['vid' => 'Vocabulary Id'],
1 => ['name' => 'Name'],
2 => ['description' => 'Description'],
],
'changed' =>
[
4 => ['vid' => 'weight'],
0 => ['name' => 'vid'],
1 => ['description' => 'name'],
],
];
$this->assertSame($expected, $columnConfiguration);
// Test the migration with incorrect column aliases. Flush the cache to
// ensure the plugin alter is run.
drupal_flush_all_caches();
$edit = [
'operation' => 'import',
];
$this->drupalPostForm($executeUrlPath, $edit, t('Execute'));
$session->responseContains("Processed 1 item (1 created, 0 updated, 0 failed, 0 ignored) - done with 'csv_source_test'");
// Rollback.
$edit = [
'operation' => 'rollback',
];
$this->drupalPostForm($executeUrlPath, $edit, t('Execute'));
// Restore to an order that will succesfully migrate.
$edit = [
'edit-vid' => 0,
'edit-name' => 1,
'edit-description' => 2,
];
$this->drupalPostForm($editUrlPath, $edit, t('Submit'));
$this->assertTrue($session->optionExists('edit-vid', 'vid')
->isSelected());
$this->assertTrue($session->optionExists('edit-name', 'name')
->isSelected());
$this->assertTrue($session->optionExists('edit-description', 'description')
->isSelected());
// Test the vocabulary migration.
$edit = [
'operation' => 'import',
];
drupal_flush_all_caches();
$this->drupalPostForm($executeUrlPath, $edit, t('Execute'));
$session->responseContains("Processed 4 items (4 created, 0 updated, 0 failed, 0 ignored) - done with 'csv_source_test'");
$this->assertEntity('tags', 'Tags', 'Use tags to group articles');
$this->assertEntity('forums', 'Sujet de discussion', 'Forum navigation vocabulary');
$this->assertEntity('test_vocabulary', 'Test Vocabulary', 'This is the vocabulary description');
$this->assertEntity('genre', 'Genre', 'Genre description');
}
/**
* Validate a migrated vocabulary contains the expected values.
*
* @param string $id
* Entity ID to load and check.
* @param string $expected_name
* The name the migrated entity should have.
* @param string $expected_description
* The description the migrated entity should have.
*/
protected function assertEntity($id, $expected_name, $expected_description) {
/** @var \Drupal\taxonomy\VocabularyInterface $entity */
$entity = Vocabulary::load($id);
$this->assertTrue($entity instanceof VocabularyInterface);
$this->assertSame($expected_name, $entity->label());
$this->assertSame($expected_description, $entity->getDescription());
}
}