Update to Drupal 8.2.4. For more information, see https://www.drupal.org/project/drupal/releases/8.2.4
This commit is contained in:
parent
0a95b8440e
commit
8544b60b39
284 changed files with 12980 additions and 3199 deletions
|
@ -23,15 +23,18 @@ use Drupal\migrate\Row;
|
|||
* means to load data into storage, while traditionally Drupal uses "load" to
|
||||
* mean load data from storage into memory.
|
||||
*
|
||||
* Source, process, and destination phases are each provided by plugins.
|
||||
* Source plugins extract data from a data source in "rows", containing
|
||||
* "properties". Each row is handed off to one or more process plugins which
|
||||
* transform the row's properties. After all the properties are processed, the
|
||||
* resulting row is handed off to a destination plugin, which saves the data.
|
||||
* In the source phase, a set of data, called the row, is retrieved from the
|
||||
* data source, typically a database but it can be a CSV, JSON or XML file. The
|
||||
* row is sent to the process phase where it is transformed as needed by the
|
||||
* destination, or marked to be skipped. Processing can also determine that a
|
||||
* stub needs to be created, for example, if a term has a parent term that does
|
||||
* not yet exist. After processing the transformed row is passed to the
|
||||
* destination phase where it is loaded (saved) into the Drupal 8 site.
|
||||
*
|
||||
* A source plugin, one or more process plugins, and a destination plugin are
|
||||
* brought together to extract, transform, and load (in the ETL sense) a specific
|
||||
* type of data by a migration plugin.
|
||||
* The ETL process is configured by the migration plugin. The different phases:
|
||||
* source, process, and destination are also plugins, and are managed by the
|
||||
* Migration plugin. So there are four types of plugins in the migration
|
||||
* process: migration, source, process and destination.
|
||||
*
|
||||
* @section sec_migrations Migration plugins
|
||||
* Migration plugin definitions are stored in a module's 'migrations' directory.
|
||||
|
@ -50,8 +53,8 @@ use Drupal\migrate\Row;
|
|||
* with \Drupal\migrate\Annotation\MigrateSource annotation, and must be in
|
||||
* namespace subdirectory Plugin\migrate\source under the namespace of the
|
||||
* module that defines them. Migration source plugins are managed by the
|
||||
* \Drupal\migrate\Plugin\MigratePluginManager class. Source plugin providers
|
||||
* are determined by their and their parents namespaces.
|
||||
* \Drupal\migrate\Plugin\MigrateSourcePluginManager class. Source plugin
|
||||
* providers are determined by their and their parents namespaces.
|
||||
*
|
||||
* @section sec_process Process plugins
|
||||
* Migration process plugins implement
|
||||
|
@ -107,6 +110,29 @@ function hook_migrate_prepare_row(Row $row, MigrateSourceInterface $source, Migr
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows altering the list of discovered migration plugins.
|
||||
*
|
||||
* Modules are able to alter specific migrations structures or even remove or
|
||||
* append additional migrations to the discovery. For example, this
|
||||
* implementation filters out Drupal 6 migrations from the discovered migration
|
||||
* list. This is done by checking the migration tags.
|
||||
*
|
||||
* @param array[] $migrations
|
||||
* An associative array of migrations keyed by migration ID. Each value is the
|
||||
* migration array, obtained by decoding the migration YAML file and enriched
|
||||
* with some meta information added during discovery phase, like migration
|
||||
* 'class', 'provider' or '_discovered_file_path'.
|
||||
*
|
||||
* @ingroup migration
|
||||
*/
|
||||
function hook_migration_plugins_alter(array &$migrations) {
|
||||
$migrations = array_filter($migrations, function (array $migration) {
|
||||
$tags = isset($migration['migration_tags']) ? (array) $migration['migration_tags'] : [];
|
||||
return !in_array('Drupal 6', $tags);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup hooks".
|
||||
*/
|
||||
|
|
|
@ -398,7 +398,7 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
$value = NULL;
|
||||
break;
|
||||
}
|
||||
$multiple = $multiple || $plugin->multiple();
|
||||
$multiple = $plugin->multiple();
|
||||
}
|
||||
}
|
||||
// No plugins or no value means do not set.
|
||||
|
|
|
@ -83,11 +83,8 @@ interface MigrateDestinationInterface extends PluginInspectionInterface {
|
|||
* Derived classes must implement fields(), returning a list of available
|
||||
* destination fields.
|
||||
*
|
||||
* @todo Review the cases where we need the Migration parameter, can we avoid
|
||||
* that? To be resolved with https://www.drupal.org/node/2543568.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
|
||||
* (optional) The migration containing this destination. Defaults to NULL.
|
||||
* Unused, will be removed before Drupal 9.0.x. Defaults to NULL.
|
||||
*
|
||||
* @return array
|
||||
* - Keys: machine names of the fields
|
||||
|
|
|
@ -20,13 +20,6 @@ use Drupal\migrate\Plugin\Discovery\ProviderFilterDecorator;
|
|||
*/
|
||||
class MigrateSourcePluginManager extends MigratePluginManager {
|
||||
|
||||
/**
|
||||
* The class loader.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $classLoader;
|
||||
|
||||
/**
|
||||
* MigrateSourcePluginManager constructor.
|
||||
*
|
||||
|
|
107
core/modules/migrate/src/Plugin/migrate/process/ArrayBuild.php
Normal file
107
core/modules/migrate/src/Plugin/migrate/process/ArrayBuild.php
Normal file
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Builds an array based on the key and value configuration.
|
||||
*
|
||||
* The array_build plugin builds a single associative array by extracting keys
|
||||
* and values from each array in the input value, which is expected to be an
|
||||
* array of arrays. The keys of the returned array will be determined by the
|
||||
* 'key' configuration option, and the values will be determined by the 'value'
|
||||
* option.
|
||||
*
|
||||
* Available configuration keys
|
||||
* - key: The key used to lookup a value in the source arrays to be used as
|
||||
* a key in the destination array.
|
||||
* - value: The key used to lookup a value in the source arrays to be used as
|
||||
* a value in the destination array.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Consider the migration of language negotiation by domain.
|
||||
* The source is an array of all the languages:
|
||||
*
|
||||
* @code
|
||||
* languages: Array
|
||||
* (
|
||||
* [0] => Array
|
||||
* (
|
||||
* [language] => en
|
||||
* ...
|
||||
* [domain] => http://example.com
|
||||
* )
|
||||
* [1] => Array
|
||||
* (
|
||||
* [language] => fr
|
||||
* ...
|
||||
* [domain] => http://fr.example.com
|
||||
* )
|
||||
* ...
|
||||
* @endcode
|
||||
*
|
||||
* The destination should be an array of all the domains keyed by their
|
||||
* language code:
|
||||
*
|
||||
* @code
|
||||
* domains: Array
|
||||
* (
|
||||
* [en] => http://example.com
|
||||
* [fr] => http://fr.example.com
|
||||
* ...
|
||||
* @endcode
|
||||
*
|
||||
* The array_build process plugin would be used like this:
|
||||
*
|
||||
* @code
|
||||
* process:
|
||||
* domains:
|
||||
* plugin: array_build
|
||||
* key: language
|
||||
* value: domain
|
||||
* source: languages
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "array_build",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class ArrayBuild extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
$new_value = [];
|
||||
|
||||
foreach ((array) $value as $old_key => $old_value) {
|
||||
// Checks that $old_value is an array.
|
||||
if (!is_array($old_value)) {
|
||||
throw new MigrateException("The input should be an array of arrays");
|
||||
}
|
||||
|
||||
// Checks that the key exists.
|
||||
if (!array_key_exists($this->configuration['key'], $old_value)) {
|
||||
throw new MigrateException("The key '" . $this->configuration['key'] . "' does not exist");
|
||||
}
|
||||
|
||||
// Checks that the value exists.
|
||||
if (!array_key_exists($this->configuration['value'], $old_value)) {
|
||||
throw new MigrateException("The key '" . $this->configuration['value'] . "' does not exist");
|
||||
}
|
||||
|
||||
$new_value[$old_value[$this->configuration['key']]] = $old_value[$this->configuration['value']];
|
||||
}
|
||||
|
||||
return $new_value;
|
||||
}
|
||||
|
||||
}
|
|
@ -10,6 +10,9 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
/**
|
||||
* Ensures value is not duplicated against an entity field.
|
||||
*
|
||||
* If the 'migrated' configuration value is true, an entity will only be
|
||||
* considered a duplicate if it was migrated by the current migration.
|
||||
*
|
||||
* @link https://www.drupal.org/node/2135325 Online handbook documentation for dedupe_entity process plugin @endlink
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
|
@ -25,11 +28,19 @@ class DedupeEntity extends DedupeBase implements ContainerFactoryPluginInterface
|
|||
*/
|
||||
protected $entityQueryFactory;
|
||||
|
||||
/**
|
||||
* The current migration.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, QueryFactory $entity_query_factory) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->migration = $migration;
|
||||
$this->entityQueryFactory = $entity_query_factory;
|
||||
}
|
||||
|
||||
|
@ -51,12 +62,25 @@ class DedupeEntity extends DedupeBase implements ContainerFactoryPluginInterface
|
|||
*/
|
||||
protected function exists($value) {
|
||||
// Plugins are cached so for every run we need a new query object.
|
||||
return $this
|
||||
$query = $this
|
||||
->entityQueryFactory
|
||||
->get($this->configuration['entity_type'], 'AND')
|
||||
->condition($this->configuration['field'], $value)
|
||||
->count()
|
||||
->execute();
|
||||
->condition($this->configuration['field'], $value);
|
||||
if (!empty($this->configuration['migrated'])) {
|
||||
// Check if each entity is in the ID map.
|
||||
$idMap = $this->migration->getIdMap();
|
||||
foreach ($query->execute() as $id) {
|
||||
$dest_id_values[$this->configuration['field']] = $id;
|
||||
if ($idMap->lookupSourceID($dest_id_values)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
// Just check if any such entity exists.
|
||||
return $query->count()->execute();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,6 +38,13 @@ class Migration extends ProcessPluginBase implements ContainerFactoryPluginInter
|
|||
*/
|
||||
protected $migrationPluginManager;
|
||||
|
||||
/**
|
||||
* The migration to be executed.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -70,9 +77,7 @@ class Migration extends ProcessPluginBase implements ContainerFactoryPluginInter
|
|||
if (!is_array($migration_ids)) {
|
||||
$migration_ids = array($migration_ids);
|
||||
}
|
||||
$scalar = FALSE;
|
||||
if (!is_array($value)) {
|
||||
$scalar = TRUE;
|
||||
$value = array($value);
|
||||
}
|
||||
$this->skipOnEmpty($value);
|
||||
|
@ -145,10 +150,8 @@ class Migration extends ProcessPluginBase implements ContainerFactoryPluginInter
|
|||
}
|
||||
}
|
||||
if ($destination_ids) {
|
||||
if ($scalar) {
|
||||
if (count($destination_ids) == 1) {
|
||||
return reset($destination_ids);
|
||||
}
|
||||
if (count($destination_ids) == 1) {
|
||||
return reset($destination_ids);
|
||||
}
|
||||
else {
|
||||
return $destination_ids;
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\Core\Path\PathValidatorInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
|
@ -55,7 +55,14 @@ class Route extends ProcessPluginBase implements ContainerFactoryPluginInterface
|
|||
* Set the destination route information based on the source link_path.
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
list($link_path, $options) = $value;
|
||||
if (is_string($value)) {
|
||||
$link_path = $value;
|
||||
$options = [];
|
||||
}
|
||||
else {
|
||||
list($link_path, $options) = $value;
|
||||
}
|
||||
|
||||
$extracted = $this->pathValidator->getUrlIfValidWithoutAccessCheck($link_path);
|
||||
$route = array();
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ class DownloadTest extends FileTestBase {
|
|||
/**
|
||||
* Tests that an exception is thrown if the destination URI is not writable.
|
||||
*/
|
||||
public function testWriteProectedDestination() {
|
||||
public function testWriteProtectedDestination() {
|
||||
// Create a pre-existing file at the destination, to test overwrite behavior.
|
||||
$destination_uri = $this->createUri('not-writable.txt');
|
||||
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\migrate\Kernel\process;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate\MigrateMessage;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
|
||||
/**
|
||||
* Tests process pipelines with scalar and multiple values handling.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class HandleMultiplesTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['migrate'];
|
||||
|
||||
/**
|
||||
* Provides the test migration definition.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDefinition() {
|
||||
return [
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => [],
|
||||
'ids' => [
|
||||
'id' => ['type' => 'string'],
|
||||
],
|
||||
],
|
||||
'process' => [
|
||||
// Process pipeline for testing values from string to array to string.
|
||||
'first' => [
|
||||
// Expects a string and returns an array.
|
||||
[
|
||||
'plugin' => 'explode',
|
||||
'source' => 'scalar',
|
||||
'delimiter' => '/',
|
||||
],
|
||||
// Expects an array and returns a string.
|
||||
[
|
||||
'plugin' => 'extract',
|
||||
'index' => [1],
|
||||
],
|
||||
// Expects a string and returns a string.
|
||||
[
|
||||
'plugin' => 'callback',
|
||||
'callable' => 'strtoupper',
|
||||
],
|
||||
],
|
||||
// Process pipeline for testing values from array to string to array.
|
||||
'second' => [
|
||||
// Expects an array and returns a string.
|
||||
[
|
||||
'plugin' => 'extract',
|
||||
'source' => 'multiple',
|
||||
'index' => [1],
|
||||
],
|
||||
// Expects a string and returns a string.
|
||||
[
|
||||
'plugin' => 'callback',
|
||||
'callable' => 'strtoupper',
|
||||
],
|
||||
// Expects a string and returns an array.
|
||||
[
|
||||
'plugin' => 'explode',
|
||||
'delimiter' => '/',
|
||||
],
|
||||
],
|
||||
],
|
||||
'destination' => [
|
||||
'plugin' => 'config',
|
||||
'config_name' => 'migrate_test.settings',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests process pipelines with scalar and multiple values handling.
|
||||
*
|
||||
* @dataProvider scalarAndMultipleValuesProviderSource
|
||||
*
|
||||
* @param array $source_data
|
||||
* @param array $expected_data
|
||||
*/
|
||||
public function testScalarAndMultipleValues(array $source_data, array $expected_data) {
|
||||
$definition = $this->getDefinition();
|
||||
$definition['source']['data_rows'] = [$source_data];
|
||||
|
||||
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
|
||||
|
||||
$executable = new MigrateExecutable($migration, new MigrateMessage());
|
||||
$result = $executable->import();
|
||||
|
||||
// Migration needs to succeed before further assertions are made.
|
||||
$this->assertSame(MigrationInterface::RESULT_COMPLETED, $result);
|
||||
|
||||
// Compare with expected data.
|
||||
$this->assertEquals($expected_data, \Drupal::config('migrate_test.settings')->get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the source data with scalar and multiple values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function scalarAndMultipleValuesProviderSource() {
|
||||
return [
|
||||
[
|
||||
'source_data' => [
|
||||
'id' => '1',
|
||||
// Source value for the first pipeline.
|
||||
'scalar' => 'foo/bar',
|
||||
// Source value for the second pipeline.
|
||||
'multiple' => [
|
||||
'foo',
|
||||
'bar/baz',
|
||||
],
|
||||
],
|
||||
'expected_data' => [
|
||||
// Expected value from the first pipeline.
|
||||
'first' => 'BAR',
|
||||
// Expected value from the second pipeline.
|
||||
'second' => [
|
||||
'BAR',
|
||||
'BAZ',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
278
core/modules/migrate/tests/src/Kernel/process/RouteTest.php
Normal file
278
core/modules/migrate/tests/src/Kernel/process/RouteTest.php
Normal file
|
@ -0,0 +1,278 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\migrate\Kernel\process;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\migrate\Plugin\migrate\process\Route;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Tests the route process plugin.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\migrate\Plugin\migrate\process\Route
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class RouteTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['user', 'system'];
|
||||
|
||||
/**
|
||||
* Tests Route plugin based on providerTestRoute() values.
|
||||
*
|
||||
* @param mixed $value
|
||||
* Input value for the Route process plugin.
|
||||
* @param array $expected
|
||||
* The expected results from the Route transform process.
|
||||
*
|
||||
* @dataProvider providerTestRoute
|
||||
*/
|
||||
public function testRoute($value, $expected) {
|
||||
$actual = $this->doTransform($value);
|
||||
$this->assertSame($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testRoute().
|
||||
*
|
||||
* @return array
|
||||
* An array of arrays, where the first element is the input to the Route
|
||||
* process plugin, and the second is the expected results.
|
||||
*/
|
||||
public function providerTestRoute() {
|
||||
// Internal link tests.
|
||||
// Valid link path and options.
|
||||
$values[0] = [
|
||||
'user/login',
|
||||
[
|
||||
'attributes' => [
|
||||
'title' => 'Test menu link 1',
|
||||
],
|
||||
],
|
||||
];
|
||||
$expected[0] = [
|
||||
'route_name' => 'user.login',
|
||||
'route_parameters' => [],
|
||||
'options' => [
|
||||
'query' => [],
|
||||
'attributes' => [
|
||||
'title' => 'Test menu link 1',
|
||||
],
|
||||
],
|
||||
'url' => NULL,
|
||||
];
|
||||
|
||||
// Valid link path and empty options.
|
||||
$values[1] = [
|
||||
'user/login',
|
||||
[],
|
||||
];
|
||||
$expected[1] = [
|
||||
'route_name' => 'user.login',
|
||||
'route_parameters' => [],
|
||||
'options' => [
|
||||
'query' => [],
|
||||
],
|
||||
'url' => NULL,
|
||||
];
|
||||
|
||||
// Valid link path and no options.
|
||||
$values[2] = 'user/login';
|
||||
$expected[2] = [
|
||||
'route_name' => 'user.login',
|
||||
'route_parameters' => [],
|
||||
'options' => [
|
||||
'query' => [],
|
||||
],
|
||||
'url' => NULL,
|
||||
];
|
||||
|
||||
// Invalid link path.
|
||||
$values[3] = 'users';
|
||||
$expected[3] = [];
|
||||
|
||||
// Valid link path with parameter.
|
||||
$values[4] = [
|
||||
'system/timezone/nzdt',
|
||||
[
|
||||
'attributes' => [
|
||||
'title' => 'Show NZDT',
|
||||
],
|
||||
],
|
||||
];
|
||||
$expected[4] = [
|
||||
'route_name' => 'system.timezone',
|
||||
'route_parameters' => [
|
||||
'abbreviation' => 'nzdt',
|
||||
'offset' => -1,
|
||||
'is_daylight_saving_time' => NULL,
|
||||
],
|
||||
'options' => [
|
||||
'query' => [],
|
||||
'attributes' => [
|
||||
'title' => 'Show NZDT',
|
||||
],
|
||||
],
|
||||
'url' => NULL,
|
||||
];
|
||||
|
||||
// External link tests.
|
||||
// Valid external link path and options.
|
||||
$values[5] = [
|
||||
'https://www.drupal.org',
|
||||
[
|
||||
'attributes' => [
|
||||
'title' => 'Drupal',
|
||||
],
|
||||
],
|
||||
];
|
||||
$expected[5] = [
|
||||
'route_name' => NULL,
|
||||
'route_parameters' => [],
|
||||
'options' => [
|
||||
'attributes' => [
|
||||
'title' => 'Drupal',
|
||||
],
|
||||
],
|
||||
'url' => 'https://www.drupal.org',
|
||||
];
|
||||
|
||||
// Valid external link path and options.
|
||||
$values[6] = [
|
||||
'https://www.drupal.org/user/1/edit?pass-reset-token=QgtDKcRV4e4fjg6v2HTa6CbWx-XzMZ5XBZTufinqsM73qIhscIuU_BjZ6J2tv4dQI6N50ZJOag',
|
||||
[
|
||||
'attributes' => [
|
||||
'title' => 'Drupal password reset',
|
||||
],
|
||||
],
|
||||
];
|
||||
$expected[6] = [
|
||||
'route_name' => NULL,
|
||||
'route_parameters' => [],
|
||||
'options' => [
|
||||
'attributes' => [
|
||||
'title' => 'Drupal password reset',
|
||||
],
|
||||
],
|
||||
'url' => 'https://www.drupal.org/user/1/edit?pass-reset-token=QgtDKcRV4e4fjg6v2HTa6CbWx-XzMZ5XBZTufinqsM73qIhscIuU_BjZ6J2tv4dQI6N50ZJOag',
|
||||
];
|
||||
|
||||
return [
|
||||
// Test data for internal paths.
|
||||
// Test with valid link path and options.
|
||||
[$values[0], $expected[0]],
|
||||
// Test with valid link path and empty options.
|
||||
[$values[1], $expected[1]],
|
||||
// Test with valid link path and no options.
|
||||
[$values[2], $expected[2]],
|
||||
// Test with Invalid link path.
|
||||
[$values[3], $expected[3]],
|
||||
// Test with Valid link path with query options and parameters.
|
||||
[$values[4], $expected[4]],
|
||||
|
||||
// Test data for external paths.
|
||||
// Test with external link path and options.
|
||||
[$values[5], $expected[5]],
|
||||
// Test with valid link path and query options.
|
||||
[$values[6], $expected[6]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests Route plugin based on providerTestRoute() values.
|
||||
*
|
||||
* @param mixed $value
|
||||
* Input value for the Route process plugin.
|
||||
* @param array $expected
|
||||
* The expected results from the Route transform process.
|
||||
*
|
||||
* @dataProvider providerTestRouteWithParamQuery
|
||||
*/
|
||||
public function testRouteWithParamQuery($value, $expected) {
|
||||
$this->installSchema('system', ['sequences']);
|
||||
$this->installEntitySchema('user');
|
||||
$this->installConfig(['user']);
|
||||
|
||||
// Create a user so that user/1/edit is a valid path.
|
||||
$adminUser = User::create([
|
||||
'name' => $this->randomMachineName(),
|
||||
]);
|
||||
$adminUser->save();
|
||||
|
||||
$actual = $this->doTransform($value);
|
||||
$this->assertSame($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testRouteWithParamQuery().
|
||||
*
|
||||
* @return array
|
||||
* An array of arrays, where the first element is the input to the Route
|
||||
* process plugin, and the second is the expected results.
|
||||
*/
|
||||
public function providerTestRouteWithParamQuery() {
|
||||
$values = [];
|
||||
$expected = [];
|
||||
// Valid link path with query options and parameters.
|
||||
$values[0] = [
|
||||
'user/1/edit',
|
||||
[
|
||||
'attributes' => [
|
||||
'title' => 'Edit admin',
|
||||
],
|
||||
'query' => [
|
||||
'destination' => '/admin/people',
|
||||
],
|
||||
],
|
||||
];
|
||||
$expected[0] = [
|
||||
'route_name' => 'entity.user.edit_form',
|
||||
'route_parameters' => [
|
||||
'user' => '1',
|
||||
],
|
||||
'options' => [
|
||||
'attributes' => [
|
||||
'title' => 'Edit admin',
|
||||
],
|
||||
'query' => [
|
||||
'destination' => '/admin/people',
|
||||
],
|
||||
],
|
||||
'url' => NULL,
|
||||
];
|
||||
|
||||
return [
|
||||
// Test with valid link path with parameters and options.
|
||||
[$values[0], $expected[0]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms link path data to a route.
|
||||
*
|
||||
* @param array|string $value
|
||||
* Source link path information.
|
||||
*
|
||||
* @return array $actual
|
||||
* The route information based on the source link_path.
|
||||
*/
|
||||
protected function doTransform($value) {
|
||||
// Rebuild the routes.
|
||||
$this->container->get('router.builder')->rebuild();
|
||||
$pathValidator = $this->container->get('path.validator');
|
||||
$row = new Row();
|
||||
$migration = $this->prophesize(MigrationInterface::class)->reveal();
|
||||
$executable = $this->prophesize(MigrateExecutableInterface::class)->reveal();
|
||||
|
||||
$plugin = new Route([], 'route', [], $migration, $pathValidator);
|
||||
$actual = $plugin->transform($value, $executable, $row, 'destinationproperty');
|
||||
return $actual;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\migrate\Unit\process;
|
||||
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\migrate\process\ArrayBuild;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\migrate\Plugin\migrate\process\ArrayBuild
|
||||
* @group migrate
|
||||
*/
|
||||
class ArrayBuildTest extends MigrateProcessTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$configuration = [
|
||||
'key' => 'foo',
|
||||
'value' => 'bar',
|
||||
];
|
||||
$this->plugin = new ArrayBuild($configuration, 'map', []);
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests successful transformation.
|
||||
*/
|
||||
public function testTransform() {
|
||||
$source = [
|
||||
['foo' => 'Foo', 'bar' => 'Bar'],
|
||||
['foo' => 'foo bar', 'bar' => 'bar foo'],
|
||||
];
|
||||
$expected = [
|
||||
'Foo' => 'Bar',
|
||||
'foo bar' => 'bar foo',
|
||||
];
|
||||
$value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->assertSame($value, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests non-existent key for the key configuration.
|
||||
*/
|
||||
public function testNonExistentKey() {
|
||||
$source = [
|
||||
['bar' => 'foo'],
|
||||
];
|
||||
$this->setExpectedException(MigrateException::class, "The key 'foo' does not exist");
|
||||
$this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests non-existent key for the value configuration.
|
||||
*/
|
||||
public function testNonExistentValue() {
|
||||
$source = [
|
||||
['foo' => 'bar'],
|
||||
];
|
||||
$this->setExpectedException(MigrateException::class, "The key 'bar' does not exist");
|
||||
$this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests one-dimensional array input.
|
||||
*/
|
||||
public function testOneDimensionalArrayInput() {
|
||||
$source = ['foo' => 'bar'];
|
||||
$this->setExpectedException(MigrateException::class, 'The input should be an array of arrays');
|
||||
$this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests string input.
|
||||
*/
|
||||
public function testStringInput() {
|
||||
$source = 'foo';
|
||||
$this->setExpectedException(MigrateException::class, 'The input should be an array of arrays');
|
||||
$this->plugin->transform($source, $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\Tests\migrate\Unit\process;
|
||||
|
||||
use Drupal\Core\Entity\Query\QueryInterface;
|
||||
use Drupal\migrate\Plugin\migrate\process\DedupeEntity;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
|
||||
|
@ -161,4 +162,47 @@ class DedupeEntityTest extends MigrateProcessTestCase {
|
|||
->will($this->returnCallback(function () use (&$count) { return $count--;}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test deduplicating only migrated entities.
|
||||
*/
|
||||
public function testDedupeMigrated() {
|
||||
$configuration = array(
|
||||
'entity_type' => 'test_entity_type',
|
||||
'field' => 'test_field',
|
||||
'migrated' => TRUE,
|
||||
);
|
||||
$plugin = new DedupeEntity($configuration, 'dedupe_entity', array(), $this->getMigration(), $this->entityQueryFactory);
|
||||
|
||||
// Setup the entityQuery used in DedupeEntity::exists. The map, $map, is
|
||||
// an array consisting of the four input parameters to the query condition
|
||||
// method and then the query to return. Both 'forum' and
|
||||
// 'test_vocab' are existing entities. There is no 'test_vocab1'.
|
||||
$map = [];
|
||||
foreach (['forums', 'test_vocab', 'test_vocab1'] as $id) {
|
||||
$query = $this->prophesize(QueryInterface::class);
|
||||
$query->willBeConstructedWith([]);
|
||||
$query->execute()->willReturn($id === 'test_vocab1' ? [] : [$id]);
|
||||
$map[] = ['test_field', $id, NULL, NULL, $query->reveal()];
|
||||
}
|
||||
$this->entityQuery
|
||||
->method('condition')
|
||||
->will($this->returnValueMap($map));
|
||||
|
||||
// Entity 'forums' is pre-existing, entity 'test_vocab' was migrated.
|
||||
$this->idMap
|
||||
->method('lookupSourceID')
|
||||
->will($this->returnValueMap([
|
||||
[['test_field' => 'forums'], FALSE],
|
||||
[['test_field' => 'test_vocab'], ['source_id' => 42]],
|
||||
]));
|
||||
|
||||
// Existing entity 'forums' was not migrated, it should not be deduplicated.
|
||||
$actual = $plugin->transform('forums', $this->migrateExecutable, $this->row, 'testproperty');
|
||||
$this->assertEquals('forums', $actual, 'Pre-existing name is re-used');
|
||||
|
||||
// Entity 'test_vocab' was migrated, should be deduplicated.
|
||||
$actual = $plugin->transform('test_vocab', $this->migrateExecutable, $this->row, 'testproperty');
|
||||
$this->assertEquals('test_vocab1', $actual, 'Migrated name is deduplicated');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ class MigrationTest extends MigrateProcessTestCase {
|
|||
|
||||
/**
|
||||
* Tests that processing is skipped when the input value is empty.
|
||||
*
|
||||
*
|
||||
* @expectedException \Drupal\migrate\MigrateSkipProcessException
|
||||
*/
|
||||
public function testSkipOnEmpty() {
|
||||
|
@ -107,8 +107,19 @@ class MigrationTest extends MigrateProcessTestCase {
|
|||
|
||||
/**
|
||||
* Tests a successful lookup.
|
||||
*
|
||||
* @dataProvider successfulLookupDataProvider
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The source id(s) of the migration map.
|
||||
* @param array $destination_id_values
|
||||
* The destination id(s) of the migration map.
|
||||
* @param string|array $source_value
|
||||
* The source value(s) for the migration process plugin.
|
||||
* @param string|array $expected_value
|
||||
* The expected value(s) of the migration process plugin.
|
||||
*/
|
||||
public function testSuccessfulLookup() {
|
||||
public function testSuccessfulLookup($source_id_values, $destination_id_values, $source_value, $expected_value) {
|
||||
$migration_plugin = $this->prophesize(MigrationInterface::class);
|
||||
$migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
|
||||
$process_plugin_manager = $this->prophesize(MigratePluginManager::class);
|
||||
|
@ -119,7 +130,7 @@ class MigrationTest extends MigrateProcessTestCase {
|
|||
$migration_plugin->id()->willReturn(uniqid());
|
||||
|
||||
$id_map = $this->prophesize(MigrateIdMapInterface::class);
|
||||
$id_map->lookupDestinationId([1])->willReturn([3]);
|
||||
$id_map->lookupDestinationId($source_id_values)->willReturn($destination_id_values);
|
||||
$migration_plugin->getIdMap()->willReturn($id_map->reveal());
|
||||
|
||||
$migration_plugin_manager->createInstances(['foobaz'])
|
||||
|
@ -131,7 +142,61 @@ class MigrationTest extends MigrateProcessTestCase {
|
|||
->willReturn([$migration_plugin->reveal()]);
|
||||
|
||||
$migration = new Migration($configuration, 'migration', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
|
||||
$this->assertSame(3, $migration->transform(1, $this->migrateExecutable, $this->row, 'foo'));
|
||||
$this->assertSame($expected_value, $migration->transform($source_value, $this->migrateExecutable, $this->row, 'foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for the successful lookup test.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function successfulLookupDataProvider() {
|
||||
return [
|
||||
// Test data for scalar to scalar.
|
||||
[
|
||||
// Source ID of the migration map.
|
||||
[1],
|
||||
// Destination ID of the migration map.
|
||||
[3],
|
||||
// Input value for the migration plugin.
|
||||
1,
|
||||
// Expected output value of the migration plugin.
|
||||
3,
|
||||
],
|
||||
// Test data for scalar to array.
|
||||
[
|
||||
// Source ID of the migration map.
|
||||
[1],
|
||||
// Destination IDs of the migration map.
|
||||
[3, 'foo'],
|
||||
// Input value for the migration plugin.
|
||||
1,
|
||||
// Expected output values of the migration plugin.
|
||||
[3, 'foo'],
|
||||
],
|
||||
// Test data for array to scalar.
|
||||
[
|
||||
// Source IDs of the migration map.
|
||||
[1, 3],
|
||||
// Destination ID of the migration map.
|
||||
['foo'],
|
||||
// Input values for the migration plugin.
|
||||
[1, 3],
|
||||
// Expected output value of the migration plugin.
|
||||
'foo',
|
||||
],
|
||||
// Test data for array to array.
|
||||
[
|
||||
// Source IDs of the migration map.
|
||||
[1, 3],
|
||||
// Destination IDs of the migration map.
|
||||
[3, 'foo'],
|
||||
// Input values for the migration plugin.
|
||||
[1, 3],
|
||||
// Expected output values of the migration plugin.
|
||||
[3, 'foo'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Reference in a new issue