upgrades core to 8.4.2

This commit is contained in:
Bachir Soussi Chiadmi
2017-11-14 16:09:54 +01:00
parent bd60eff9b3
commit c2b4e25be4
3504 changed files with 140306 additions and 38684 deletions
+3 -3
View File
@@ -5,8 +5,8 @@ package: Core (Experimental)
# version: VERSION
# core: 8.x
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -43,4 +43,15 @@ class MigrateDestination extends Plugin {
*/
public $requirements_met = TRUE;
/**
* Identifies the system handling the data the destination plugin will write.
*
* The destination plugin itself determines how the value is used. For
* example, Migrate Drupal's destination plugins expect destination_module to
* be the name of a module that must be installed on the destination.
*
* @var string
*/
public $destination_module;
}
@@ -43,16 +43,15 @@ class MigrateSource extends Plugin implements MultipleProviderAnnotationInterfac
/**
* Identifies the system providing the data the source plugin will read.
*
* This can be any type, and the source plugin itself determines how the value
* is used. For example, Migrate Drupal's source plugins expect
* source_provider to be the name of a module that must be installed and
* enabled in the source database.
* The source plugin itself determines how the value is used. For example,
* Migrate Drupal's source plugins expect source_module to be the name of a
* module that must be installed and enabled in the source database.
*
* @see \Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase::checkRequirements
*
* @var mixed
* @var string
*/
public $source_provider;
public $source_module;
/**
* Specifies the minimum version of the source provider.
@@ -60,7 +59,7 @@ class MigrateSource extends Plugin implements MultipleProviderAnnotationInterfac
* This can be any type, and the source plugin itself determines how it is
* used. For example, Migrate Drupal's source plugins expect this to be an
* integer representing the minimum installed database schema version of the
* module specified by source_provider.
* module specified by source_module.
*
* @var mixed
*/
@@ -2,7 +2,6 @@
namespace Drupal\migrate;
interface MigrateBuildDependencyInterface {
/**
+12 -4
View File
@@ -96,7 +96,7 @@ class MigrateExecutable implements MigrateExecutableInterface {
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* The migration to run.
* @param \Drupal\migrate\MigrateMessageInterface $message
* The message to record.
* The migrate message service.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher.
*
@@ -386,9 +386,14 @@ class MigrateExecutable implements MigrateExecutableInterface {
$multiple = $plugin->multiple();
}
}
// No plugins or no value means do not set.
if ($plugins && !is_null($value)) {
$row->setDestinationProperty($destination, $value);
// Ensure all values, including nulls, are migrated.
if ($plugins) {
if (isset($value)) {
$row->setDestinationProperty($destination, $value);
}
else {
$row->setEmptyDestinationProperty($destination);
}
}
// Reset the value.
$value = NULL;
@@ -534,6 +539,9 @@ class MigrateExecutable implements MigrateExecutableInterface {
// @TODO: explore resetting the container.
// Run garbage collector to further reduce memory.
gc_collect_cycles();
return memory_get_usage();
}
@@ -2,7 +2,6 @@
namespace Drupal\migrate;
interface MigrateMessageInterface {
/**
@@ -133,4 +133,12 @@ interface MigrateDestinationInterface extends PluginInspectionInterface {
*/
public function rollbackAction();
/**
* Gets the destination module handling the destination data.
*
* @return string|null
* The destination module or NULL if not found.
*/
public function getDestinationModule();
}
@@ -213,6 +213,8 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
*
* @deprecated in Drupal 8.1.x, will be removed before Drupal 9.0.x. Use
* lookupDestinationIds() instead.
*
* @see https://www.drupal.org/node/2725809
*/
public function lookupDestinationId(array $source_id_values);
@@ -227,7 +229,7 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
* If unkeyed, the first count($source_id_values) keys will be assumed.
*
* @return array
* An array of arrays of destination identifier values.
* An array of arrays of destination identifier values.
*
* @throws \Drupal\migrate\MigrateException
* Thrown when $source_id_values contains unknown keys, or is the wrong
@@ -266,10 +268,10 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
public function getQualifiedMapTableName();
/**
* Sets the migrate message.
* Sets the migrate message service.
*
* @param \Drupal\migrate\MigrateMessageInterface $message
* The message to display.
* The migrate message service.
*/
public function setMessage(MigrateMessageInterface $message);
@@ -100,4 +100,12 @@ interface MigrateSourceInterface extends \Countable, \Iterator, PluginInspection
*/
public function getIds();
/**
* Gets the source module providing the source data.
*
* @return string|null
* The source module or NULL if not found.
*/
public function getSourceModule();
}
@@ -12,7 +12,7 @@ use Drupal\migrate\Plugin\Discovery\ProviderFilterDecorator;
* Plugin manager for migrate source plugins.
*
* @see \Drupal\migrate\Plugin\MigrateSourceInterface
* @see \Drupal\migrate\Plugin\source\SourcePluginBase
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
* @see \Drupal\migrate\Annotation\MigrateSource
* @see plugin_api
*
@@ -312,6 +312,8 @@ class Migration extends PluginBase implements MigrationInterface, RequirementsIn
*
* @deprecated in Drupal 8.1.x, will be removed before Drupal 9.0.x. Use
* more specific getters instead.
*
* @see https://www.drupal.org/node/2873795
*/
public function get($property) {
return isset($this->$property) ? $this->$property : NULL;
@@ -570,7 +572,7 @@ class Migration extends PluginBase implements MigrationInterface, RequirementsIn
*/
public function mergeProcessOfProperty($property, array $process_of_property) {
// If we already have a process value then merge the incoming process array
//otherwise simply set it.
// otherwise simply set it.
$current_process = $this->getProcess();
if (isset($current_process[$property])) {
$this->process = NestedArray::mergeDeepArray([$current_process, $this->getProcessNormalized([$property => $process_of_property])], TRUE);
@@ -153,7 +153,7 @@ interface MigrationInterface extends PluginInspectionInterface, DerivativeInspec
/**
* Set the current migration status.
*
* @param int $result
* @param int $status
* One of the STATUS_* constants.
*/
public function setStatus($status);
@@ -64,7 +64,7 @@ class MigrationPluginManager extends DefaultPluginManager implements MigrationPl
*/
protected function getDiscovery() {
if (!isset($this->discovery)) {
$directories = array_map(function($directory) {
$directories = array_map(function ($directory) {
return [$directory . '/migration_templates', $directory . '/migrations'];
}, $this->moduleHandler->getModuleDirectories());
@@ -125,7 +125,7 @@ class MigrationPluginManager extends DefaultPluginManager implements MigrationPl
* An array of migration objects with the given tag.
*/
public function createInstancesByTag($tag) {
$migrations = array_filter($this->getDefinitions(), function($migration) use ($tag) {
$migrations = array_filter($this->getDefinitions(), function ($migration) use ($tag) {
return !empty($migration['migration_tags']) && in_array($tag, $migration['migration_tags']);
});
return $this->createInstances(array_keys($migrations));
@@ -64,6 +64,6 @@ abstract class ComponentEntityDisplayBase extends DestinationBase {
* @return \Drupal\Core\Entity\Display\EntityDisplayInterface
* The entity display object.
*/
protected abstract function getEntity($entity_type, $bundle, $mode);
abstract protected function getEntity($entity_type, $bundle, $mode);
}
@@ -195,4 +195,26 @@ class Config extends DestinationBase implements ContainerFactoryPluginInterface,
}
}
/**
* {@inheritdoc}
*/
public function getDestinationModule() {
if (!empty($this->configuration['destination_module'])) {
return $this->configuration['destination_module'];
}
if (!empty($this->pluginDefinition['destination_module'])) {
return $this->pluginDefinition['destination_module'];
}
// Config translations require the config_translation module so set the
// migration provider to 'config_translation'. The corresponding non
// translated configuration is expected to be handled in a separate
// migration.
if (isset($this->configuration['translations'])) {
return 'config_translation';
}
// Get the module handling this configuration object from the config_name,
// which is of the form <module_name>.<configuration object name>
return !empty($this->configuration['config_name']) ? explode('.', $this->configuration['config_name'], 2)[0] : NULL;
}
}
@@ -110,4 +110,22 @@ abstract class DestinationBase extends PluginBase implements MigrateDestinationI
}
}
/**
* {@inheritdoc}
*/
public function getDestinationModule() {
if (!empty($this->configuration['destination_module'])) {
return $this->configuration['destination_module'];
}
if (!empty($this->pluginDefinition['destination_module'])) {
return $this->pluginDefinition['destination_module'];
}
if (is_string($this->migration->provider)) {
return $this->migration->provider;
}
else {
return reset($this->migration->provider);
}
}
}
@@ -149,6 +149,7 @@ class EntityContentBase extends Entity {
* An updated entity, or NULL if it's the same as the one passed in.
*/
protected function updateEntity(EntityInterface $entity, Row $row) {
$empty_destinations = $row->getEmptyDestinationProperties();
// By default, an update will be preserved.
$rollback_action = MigrateIdMapInterface::ROLLBACK_PRESERVE;
@@ -171,6 +172,7 @@ class EntityContentBase extends Entity {
// clone the row with an empty set of destination values, and re-add only
// the specified properties.
if (isset($this->configuration['overwrite_properties'])) {
$empty_destinations = array_intersect($empty_destinations, $this->configuration['overwrite_properties']);
$clone = $row->cloneWithoutDestination();
foreach ($this->configuration['overwrite_properties'] as $property) {
$clone->setDestinationProperty($property, $row->getDestinationProperty($property));
@@ -184,6 +186,9 @@ class EntityContentBase extends Entity {
$field->setValue($values);
}
}
foreach ($empty_destinations as $field_name) {
$entity->$field_name = NULL;
}
$this->setRollbackAction($row->getIdMap(), $rollback_action);
@@ -6,6 +6,7 @@ use Drupal\Component\Utility\Unicode;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\migrate\MigrateMessage;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Event\MigrateIdMapMessageEvent;
use Drupal\migrate\MigrateException;
@@ -55,7 +56,7 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
protected $messageTableName;
/**
* The migrate message.
* The migrate message service.
*
* @var \Drupal\migrate\MigrateMessageInterface
*/
@@ -156,6 +157,7 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->migration = $migration;
$this->eventDispatcher = $event_dispatcher;
$this->message = new MigrateMessage();
}
/**
@@ -17,6 +17,8 @@ Drupal 8.4.x and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPA
*
* @deprecated in Drupal 8.4.x and will be removed in Drupal 9.0.x. Use
* \Drupal\migrate\Plugin\migrate\process\MakeUniqueBase instead.
*
* @see https://www.drupal.org/node/2873762
*/
abstract class DedupeBase extends MakeUniqueBase {
}
@@ -19,5 +19,7 @@ Drupal 8.4.x and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPA
*
* @deprecated in Drupal 8.4.x and will be removed in Drupal 9.0.x. Use
* \Drupal\migrate\Plugin\migrate\process\MakeUniqueEntityField instead.
*
* @see https://www.drupal.org/node/2873762
*/
class DedupeEntity extends MakeUniqueEntityField { }
class DedupeEntity extends MakeUniqueEntityField {}
@@ -19,11 +19,9 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* The file can be moved, reused, or set to be automatically renamed if a
* duplicate exists.
*
* The source value is an array of two values:
* - source: The source path or URI, e.g. '/path/to/foo.txt' or
* 'public://bar.txt'.
* - destination: The destination path or URI, e.g. '/path/to/bar.txt' or
* 'public://foo.txt'.
* The source value is an indexed array of two values:
* - The source path or URI, e.g. '/path/to/foo.txt' or 'public://bar.txt'.
* - The destination URI, e.g. 'public://foo.txt'.
*
* Available configuration keys:
* - move: (optional) Boolean, if TRUE, move the file, otherwise copy the file.
@@ -39,8 +37,9 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* process:
* path_to_file:
* plugin: file_copy
* source: /path/to/file.png
* destination: /new/path/to/file.png
* source:
* - /path/to/file.png
* - public://new/path/to/file.png
* @endcode
*
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
@@ -1,6 +1,7 @@
<?php
namespace Drupal\migrate\Plugin\migrate\process;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
@@ -2,65 +2,20 @@
namespace Drupal\migrate\Plugin\migrate\process;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
@trigger_error('The ' . __NAMESPACE__ . '\Iterator is deprecated in
Drupal 8.4.x and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPACE__ . '\SubProcess', E_USER_DEPRECATED);
/**
* This plugin iterates and processes an array.
* Iterates and processes an associative array.
*
* @link https://www.drupal.org/node/2135345 Online handbook documentation for iterator process plugin @endlink
* @deprecated in Drupal 8.4.x and will be removed in Drupal 9.0.x. Use
* \Drupal\migrate\Plugin\migrate\process\SubProcess instead.
*
* @see https://www.drupal.org/node/2880427
*
* @MigrateProcessPlugin(
* id = "iterator",
* handle_multiples = TRUE
* )
*/
class Iterator extends ProcessPluginBase {
/**
* Runs a process pipeline on each destination property per list item.
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$return = [];
if (!is_null($value)) {
foreach ($value as $key => $new_value) {
$new_row = new Row($new_value, []);
$migrate_executable->processRow($new_row, $this->configuration['process']);
$destination = $new_row->getDestination();
if (array_key_exists('key', $this->configuration)) {
$key = $this->transformKey($key, $migrate_executable, $new_row);
}
$return[$key] = $destination;
}
}
return $return;
}
/**
* Runs the process pipeline for the current key.
*
* @param string|int $key
* The current key.
* @param \Drupal\migrate\MigrateExecutableInterface $migrate_executable
* The migrate executable helper class.
* @param \Drupal\migrate\Row $row
* The current row after processing.
*
* @return mixed
* The transformed key.
*/
protected function transformKey($key, MigrateExecutableInterface $migrate_executable, Row $row) {
$process = ['key' => $this->configuration['key']];
$migrate_executable->processRow($row, $process, $key);
return $row->getDestinationProperty('key');
}
/**
* {@inheritdoc}
*/
public function multiple() {
return TRUE;
}
}
class Iterator extends SubProcess {}
@@ -6,7 +6,6 @@ use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
/**
* Logs values without changing them.
*
@@ -17,4 +17,4 @@ Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPA
* @deprecated in Drupal 8.3.x and will be removed in Drupal 9.0.x.
* Use \Drupal\migrate\Plugin\migrate\process\MigrationLookup instead.
*/
class Migration extends MigrationLookup { }
class Migration extends MigrationLookup {}
@@ -222,15 +222,16 @@ class MigrationLookup extends ProcessPluginBase implements ContainerFactoryPlugi
// Do a normal migration with the stub row.
$migrate_executable->processRow($stub_row, $process);
$destination_ids = [];
$id_map = $migration->getIdMap();
try {
$destination_ids = $destination_plugin->import($stub_row);
}
catch (\Exception $e) {
$migration->getIdMap()->saveMessage($stub_row->getSourceIdValues(), $e->getMessage());
$id_map->saveMessage($stub_row->getSourceIdValues(), $e->getMessage());
}
if ($destination_ids) {
$migration->getIdMap()->saveIdMapping($stub_row, $destination_ids, MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
$id_map->saveIdMapping($stub_row, $destination_ids, MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
}
}
if ($destination_ids) {
@@ -0,0 +1,166 @@
<?php
namespace Drupal\migrate\Plugin\migrate\process;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
/**
* Runs an array of arrays through its own process pipeline.
*
* The sub_process plugin accepts an array of associative arrays and runs each
* one through its own process pipeline, producing a newly keyed associative
* array of transformed values.
*
* Available configuration keys:
* - process: the plugin(s) that will process each element of the source.
* - key: runs the process pipeline for the key to determine a new dynamic
* name.
*
* Examples:
*
* @code
* source: Array
* (
* [upload] => Array
* (
* [0] => Array
* (
* [fid] => 1
* [list] => 0
* [description] => "File number 1"
* )
* [1] => Array
* (
* [fid] => 2
* [list] => 1
* [description] => "File number 2"
* )
* )
* )
* ...
* @endcode
*
* The sub_process process plugin will take these arrays one at a time and run
* its own process over each one:
*
* @code
* process:
* upload:
* plugin: sub_process
* source: upload
* process:
* target_id:
* plugin: migration_lookup
* migration: d6_file
* source: fid
* display: list
* description: description
* @endcode
*
* In this case, each item in the upload array will be processed by the
* sub_process process plugin. The target_id will be found by looking up the
* destination value from a previous migration. The display and description
* fields will simply be mapped.
*
* In the next example, normally the array returned from sub_process will have
* its original keys. If you need to change the key, it is possible for the
* returned array to be keyed by one of the transformed values in the sub-array.
*
* @code
* source: Array
* (
* [format] => 1
* [name] => Filtered HTML
* ...
* [filters] => Array
* (
* [0] => Array
* (
* [module] => filter
* [delta] => 2
* [weight] => 0
* )
* [1] => Array
* (
* [module] => filter
* [delta] => 0
* [weight] => 1
* )
* )
* )
* ...
*
* process:
* filters:
* plugin: iterator
* source: filters
* key: "@id"
* process:
* id:
* plugin: concat
* source:
* - module
* - delta
* delimiter: _
* @endcode
*
* In the above example, the keys of the returned array would be filter_2 and
* filter_0
*
* @see \Drupal\migrate\Plugin\MigrateProcessInterface
*
* @MigrateProcessPlugin(
* id = "sub_process",
* handle_multiples = TRUE
* )
*/
class SubProcess extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$return = [];
if (is_array($value) || $value instanceof \Traversable) {
foreach ($value as $key => $new_value) {
$new_row = new Row($new_value, []);
$migrate_executable->processRow($new_row, $this->configuration['process']);
$destination = $new_row->getDestination();
if (array_key_exists('key', $this->configuration)) {
$key = $this->transformKey($key, $migrate_executable, $new_row);
}
$return[$key] = $destination;
}
}
return $return;
}
/**
* Runs the process pipeline for the key to determine its dynamic name.
*
* @param string|int $key
* The current key.
* @param \Drupal\migrate\MigrateExecutableInterface $migrate_executable
* The migrate executable helper class.
* @param \Drupal\migrate\Row $row
* The current row after processing.
*
* @return mixed
* The transformed key.
*/
protected function transformKey($key, MigrateExecutableInterface $migrate_executable, Row $row) {
$process = ['key' => $this->configuration['key']];
$migrate_executable->processRow($row, $process, $key);
return $row->getDestinationProperty('key');
}
/**
* {@inheritdoc}
*/
public function multiple() {
return TRUE;
}
}
@@ -28,8 +28,8 @@ use Drupal\migrate\Plugin\MigrationInterface;
* -
* channel_machine_name: movies
* channel_description: Movies
* ids:
* channel_machine_name:
* ids:
* channel_machine_name:
* type: string
* @endcode
*
@@ -13,7 +13,49 @@ use Drupal\migrate\Plugin\MigrateSourceInterface;
use Drupal\migrate\Row;
/**
* The base class for all source plugins.
* The base class for source plugins.
*
* Available configuration keys:
* - cache_counts: (optional) If set, cache the source count.
* - skip_count: (optional) If set, do not attempt to count the source.
* - track_changes: (optional) If set, track changes to incoming data.
* - high_water_property: (optional) It is an array of name & alias values
* (optional table alias). This high_water_property is typically a timestamp
* or serial id showing what was the last imported record. Only content with a
* higher value will be imported.
*
* The high_water_property and track_changes are mutually exclusive.
*
* Example:
*
* @code
* source:
* plugin: some_source_plugin_name
* cache_counts: true
* track_changes: true
* @endcode
*
* This example uses the plugin "some_source_plugin_name" and caches the count
* of available source records to save calculating it every time count() is
* called. Changes to incoming data are watched (because track_changes is true),
* which can affect the result of prepareRow().
*
* Example:
*
* @code
* source:
* plugin: some_source_plugin_name
* skip_count: true
* high_water_property:
* name: changed
* alias: n
* @endcode
*
* In this example, skip_count is true which means count() will not attempt to
* count the available source records, but just always return -1 instead. The
* high_water_property defines which field marks the last imported row of the
* migration. This will get converted into a SQL condition that looks like
* 'n.changed' or 'changed' if no alias.
*
* @see \Drupal\migrate\Plugin\MigratePluginManager
* @see \Drupal\migrate\Annotation\MigrateSource
@@ -177,7 +219,7 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
* @return array
* An array of the data for this source.
*/
protected abstract function initializeIterator();
abstract protected function initializeIterator();
/**
* Gets the module handler.
@@ -541,4 +583,17 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
$this->saveHighWater(NULL);
}
/**
* {@inheritdoc}
*/
public function getSourceModule() {
if (!empty($this->configuration['source_module'])) {
return $this->configuration['source_module'];
}
elseif (!empty($this->pluginDefinition['source_module'])) {
return $this->pluginDefinition['source_module'];
}
return NULL;
}
}
@@ -15,13 +15,37 @@ use Drupal\migrate\Plugin\RequirementsInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Sources whose data may be fetched via DBTNG.
* Sources whose data may be fetched via a database connection.
*
* By default, an existing database connection with key 'migrate' and target
* 'default' is used. These may be overridden with explicit 'key' and/or
* 'target' configuration keys. In addition, if the configuration key 'database'
* is present, it is used as a database connection information array to define
* the connection.
* Database configuration, which may appear either within the source plugin
* configuration or in state, is structured as follows:
*
* 'key' - The database key name (defaults to 'migrate').
* 'target' - The database target name (defaults to 'default').
* 'database' - Database connection information as accepted by
* Database::addConnectionInfo(). If not present, the key/target is assumed
* to already be defined (e.g., in settings.php).
*
* This configuration info is obtained in the following order:
*
* 1. If the source plugin configuration contains a key 'database_state_key',
* its value is taken as the name of a state key which contains an array
* with the above database configuration.
* 2. Otherwise, if the source plugin configuration contains 'key', the above
* database configuration is obtained directly from the plugin configuration.
* 3. Otherwise, if the state 'migrate.fallback_state_key' exists, its value is
* taken as the name of a state key which contains an array with the above
* database configuration.
* 4. Otherwise, if a connection named 'migrate' exists, that is used as the
* database connection.
* 5. Otherwise, RequirementsException is thrown.
*
* It is strongly recommended that database connections be explicitly defined
* via 'database_state_key' or in the source plugin configuration. Defining
* migrate.fallback_state_key or a 'migrate' connection affects not only any
* migrations intended to use that particular connection, but all
* SqlBase-derived source plugins which do not have explicit database
* configuration.
*/
abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPluginInterface, RequirementsInterface {
@@ -101,16 +125,21 @@ abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPlugi
*/
public function getDatabase() {
if (!isset($this->database)) {
// See if the database info is in state - if not, fallback to
// configuration.
// Look first for an explicit state key containing the configuration.
if (isset($this->configuration['database_state_key'])) {
$this->database = $this->setUpDatabase($this->state->get($this->configuration['database_state_key']));
}
// Next, use explicit configuration in the source plugin.
elseif (isset($this->configuration['key'])) {
$this->database = $this->setUpDatabase($this->configuration);
}
// Next, try falling back to the global state key.
elseif (($fallback_state_key = $this->state->get('migrate.fallback_state_key'))) {
$this->database = $this->setUpDatabase($this->state->get($fallback_state_key));
}
// If all else fails, let setUpDatabase() fallback to the 'migrate' key.
else {
$this->database = $this->setUpDatabase($this->configuration);
$this->database = $this->setUpDatabase([]);
}
}
return $this->database;
@@ -274,11 +303,17 @@ abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPlugi
}
// 2. If we are using high water marks, also include rows above the mark.
// But, include all rows if the high water mark is not set.
if ($this->getHighWaterProperty() && ($high_water = $this->getHighWater())) {
if ($this->getHighWaterProperty()) {
$high_water_field = $this->getHighWaterField();
$conditions->condition($high_water_field, $high_water, '>');
$high_water = $this->getHighWater();
if ($high_water) {
$conditions->condition($high_water_field, $high_water, '>');
$condition_added = TRUE;
}
// Always sort by the high water field, to ensure that the first run
// (before we have a high water value) also has the results in a
// consistent order.
$this->query->orderBy($high_water_field);
$condition_added = TRUE;
}
if ($condition_added) {
$this->query->condition($conditions);
+27
View File
@@ -77,6 +77,13 @@ class Row {
*/
protected $isStub = FALSE;
/**
* The empty destination properties.
*
* @var array
*/
protected $emptyDestinationProperties = [];
/**
* Constructs a \Drupal\Migrate\Row object.
*
@@ -229,6 +236,26 @@ class Row {
NestedArray::unsetValue($this->destination, explode(static::PROPERTY_SEPARATOR, $property));
}
/**
* Sets a destination to be empty.
*
* @param string $property
* The destination property.
*/
public function setEmptyDestinationProperty($property) {
$this->emptyDestinationProperties[] = $property;
}
/**
* Gets the empty destination properties.
*
* @return array
* An array of destination properties.
*/
public function getEmptyDestinationProperties() {
return $this->emptyDestinationProperties;
}
/**
* Returns the whole destination array.
*
@@ -5,8 +5,8 @@ package: Testing
# version: VERSION
# core: 8.x
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -4,8 +4,8 @@ package: Testing
# version: VERSION
# core: 8.x
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -7,8 +7,8 @@ dependencies:
- node
- migrate
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -8,7 +8,8 @@ use Drupal\migrate\Plugin\migrate\source\SourcePluginBase;
* A simple migrate source for our tests.
*
* @MigrateSource(
* id = "migrate_external_translated_test"
* id = "migrate_external_translated_test",
* source_module = "migrate_external_translated_test"
* )
*/
class MigrateExternalTranslatedTestSource extends SourcePluginBase {
@@ -6,8 +6,8 @@ package: Testing
dependencies:
- migrate
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -5,8 +5,8 @@ package: Testing
# version: VERSION
# core: 8.x
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -6,8 +6,8 @@ package: Testing
dependencies:
- migrate
# Information added by Drupal.org packaging script on 2017-08-16
version: '8.3.7'
# Information added by Drupal.org packaging script on 2017-11-03
version: '8.4.2'
core: '8.x'
project: 'drupal'
datestamp: 1502903957
datestamp: 1509719929
@@ -18,13 +18,14 @@ class MigrateBundleTest extends MigrateTestBase {
*
* @var array
*/
public static $modules = ['taxonomy', 'text'];
public static $modules = ['taxonomy', 'text', 'user'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('user');
$this->installEntitySchema('taxonomy_vocabulary');
$this->installEntitySchema('taxonomy_term');
$this->installConfig(['taxonomy']);
@@ -10,6 +10,7 @@ use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Drupal\migrate_entity_test\Entity\StringIdEntityTest;
/**
* Tests the EntityContentBase destination.
@@ -204,4 +205,65 @@ class MigrateEntityContentBaseTest extends KernelTestBase {
$this->assertEquals(123456789012, $map_row['destid1']);
}
/**
* Tests empty destinations.
*/
public function testEmptyDestinations() {
$this->enableModules(['migrate_entity_test']);
$this->installEntitySchema('migrate_string_id_entity_test');
$definition = [
'source' => [
'plugin' => 'embedded_data',
'data_rows' => [
['id' => 123, 'version' => 'foo'],
// This integer needs an 'int' schema with 'big' size. If 'destid1'
// is not correctly taking the definition from the destination entity
// type, the import will fail with an SQL exception.
['id' => 123456789012, 'version' => 'bar'],
],
'ids' => [
'id' => ['type' => 'integer', 'size' => 'big'],
'version' => ['type' => 'string'],
],
'constants' => ['null' => NULL],
],
'process' => [
'id' => 'id',
'version' => 'version',
],
'destination' => [
'plugin' => 'entity:migrate_string_id_entity_test',
],
];
$migration = \Drupal::service('plugin.manager.migration')
->createStubMigration($definition);
$executable = new MigrateExecutable($migration, new MigrateMessage());
$executable->import();
/** @var \Drupal\migrate_entity_test\Entity\StringIdEntityTest $entity */
$entity = StringIdEntityTest::load('123');
$this->assertSame('foo', $entity->version->value);
$entity = StringIdEntityTest::load('123456789012');
$this->assertSame('bar', $entity->version->value);
// Rerun the migration forcing the version to NULL.
$definition['process'] = [
'id' => 'id',
'version' => 'constants/null',
];
$migration = \Drupal::service('plugin.manager.migration')
->createStubMigration($definition);
$executable = new MigrateExecutable($migration, new MigrateMessage());
$executable->import();
/** @var \Drupal\migrate_entity_test\Entity\StringIdEntityTest $entity */
$entity = StringIdEntityTest::load('123');
$this->assertNull($entity->version->value);
$entity = StringIdEntityTest::load('123456789012');
$this->assertNull($entity->version->value);
}
}
@@ -17,13 +17,14 @@ class MigrateRollbackEntityConfigTest extends MigrateTestBase {
*
* @var array
*/
public static $modules = ['field', 'taxonomy', 'text', 'language', 'config_translation'];
public static $modules = ['field', 'taxonomy', 'text', 'language', 'config_translation', 'user'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('user');
$this->installEntitySchema('taxonomy_vocabulary');
$this->installEntitySchema('taxonomy_term');
$this->installConfig(['taxonomy']);
@@ -20,13 +20,14 @@ class MigrateRollbackTest extends MigrateTestBase {
*
* @var array
*/
public static $modules = ['field', 'taxonomy', 'text'];
public static $modules = ['field', 'taxonomy', 'text', 'user'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('user');
$this->installEntitySchema('taxonomy_vocabulary');
$this->installEntitySchema('taxonomy_term');
$this->installConfig(['taxonomy']);
@@ -39,7 +39,9 @@ abstract class MigrateSqlSourceTestBase extends MigrateSourceTestBase {
->createTable($table, [
// SQLite uses loose affinity typing, so it's OK for every field to
// be a text field.
'fields' => array_map(function() { return ['type' => 'text']; }, $pilot),
'fields' => array_map(function () {
return ['type' => 'text'];
}, $pilot),
]);
$fields = array_keys($pilot);
@@ -230,7 +230,9 @@ abstract class MigrateTestBase extends KernelTestBase implements MigrateMessageI
$migration = $this->getMigration($migration);
}
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$destination = array_map(function() { return NULL; }, $migration->getDestinationPlugin()->getIds());
$destination = array_map(function () {
return NULL;
}, $migration->getDestinationPlugin()->getIds());
$row = new Row($row, $migration->getSourcePlugin()->getIds());
$migration->getIdMap()->saveIdMapping($row, $destination, $status);
}
@@ -0,0 +1,38 @@
<?php
namespace Drupal\Tests\migrate\Kernel;
use Drupal\comment\Entity\CommentType;
use Drupal\node\Entity\NodeType;
/**
* Provides methods for testing node and comment combinations.
*/
trait NodeCommentCombinationTrait {
/**
* Creates a node type with a corresponding comment type.
*
* @param string $node_type
* The node type ID.
* @param string $comment_type
* (optional) The comment type ID, if not provided defaults to
* comment_node_{type}.
*/
protected function createNodeCommentCombination($node_type, $comment_type = NULL) {
if (!$comment_type) {
$comment_type = "comment_node_$node_type";
}
NodeType::create([
'type' => $node_type,
'label' => $this->randomString(),
])->save();
CommentType::create([
'id' => $comment_type,
'label' => $this->randomString(),
'target_entity_type_id' => 'node',
])->save();
}
}
@@ -89,7 +89,9 @@ class MigrationPluginListTest extends KernelTestBase {
// Any database-based source plugins should fail a requirements test in the
// absence of a source database connection (e.g., a connection with the
// 'migrate' key).
$source_plugins = array_map(function ($migration_plugin) { return $migration_plugin->getSourcePlugin(); }, $migration_plugins);
$source_plugins = array_map(function ($migration_plugin) {
return $migration_plugin->getSourcePlugin();
}, $migration_plugins);
foreach ($source_plugins as $id => $source_plugin) {
if ($source_plugin instanceof RequirementsInterface) {
try {
@@ -0,0 +1,64 @@
<?php
namespace Drupal\Tests\migrate\Kernel\Plugin;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\KernelTests\FileSystemModuleDiscoveryDataProviderTrait;
use Drupal\Tests\migrate_drupal\Kernel\MigrateDrupalTestBase;
/**
* Tests that modules exist for all source and destination plugins.
*
* @group migrate_drupal_ui
*/
class MigrationProvidersExistTest extends MigrateDrupalTestBase {
use FileSystemModuleDiscoveryDataProviderTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['migration_provider_test'];
/**
* Tests that modules exist for all source and destination plugins.
*/
public function testProvidersExist() {
// Install all available modules.
$module_handler = $this->container->get('module_handler');
$modules = $this->coreModuleListDataProvider();
$modules_enabled = $module_handler->getModuleList();
$modules_to_enable = array_keys(array_diff_key($modules, $modules_enabled));
$this->enableModules($modules_to_enable);
/** @var \Drupal\migrate\Plugin\MigrationPluginManager $plugin_manager */
$plugin_manager = $this->container->get('plugin.manager.migration');
// Get all the migrations
$migrations = $plugin_manager->createInstances(array_keys($plugin_manager->getDefinitions()));
// Ensure the test module was enabled.
$this->assertTrue(array_key_exists('migration_provider_test', $migrations));
$this->assertTrue(array_key_exists('migration_provider_no_annotation', $migrations));
/** @var \Drupal\migrate\Plugin\Migration $migration */
foreach ($migrations as $migration) {
$source_module = $migration->getSourcePlugin()->getSourceModule();
$destination_module = $migration->getDestinationPlugin()->getDestinationModule();
$migration_id = $migration->getPluginId();
if ($migration_id == 'migration_provider_test') {
$this->assertFalse($source_module, new FormattableMarkup('Source module not found for @migration_id.', ['@migration_id' => $migration_id]));
$this->assertFalse($destination_module, new FormattableMarkup('Destination module not found for @migration_id.', ['@migration_id' => $migration_id]));
}
elseif ($migration_id == 'migration_provider_no_annotation') {
$this->assertFalse($source_module, new FormattableMarkup('Source module not found for @migration_id.', ['@migration_id' => $migration_id]));
$this->assertTrue($destination_module, new FormattableMarkup('Destination module found for @migration_id.', ['@migration_id' => $migration_id]));
}
else {
$this->assertTrue($source_module, new FormattableMarkup('Source module found for @migration_id.', ['@migration_id' => $migration_id]));
$this->assertTrue($destination_module, new FormattableMarkup('Destination module found for @migration_id.', ['@migration_id' => $migration_id]));
}
// Destination module can't be migrate or migrate_drupal or migrate_drupal_ui
$invalid_destinations = ['migrate', 'migrate_drupal', 'migrate_drupal_ui'];
$this->assertNotContains($destination_module, $invalid_destinations, new FormattableMarkup('Invalid destination for @migration_id.', ['@migration_id' => $migration_id]));
}
}
}
@@ -7,8 +7,12 @@
namespace Drupal\Tests\migrate\Kernel;
use Drupal\migrate\Plugin\migrate\source\TestSqlBase;
use Drupal\Core\Database\Query\ConditionInterface;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\Core\Database\Database;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
use Drupal\migrate\Plugin\MigrationInterface;
/**
* Tests the functionality of SqlBase.
@@ -17,17 +21,47 @@ use Drupal\Core\Database\Database;
*/
class SqlBaseTest extends MigrateTestBase {
/**
* The (probably mocked) migration under test.
*
* @var \Drupal\migrate\Plugin\MigrationInterface
*/
protected $migration;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->migration = $this->getMock(MigrationInterface::class);
$this->migration->method('id')->willReturn('fubar');
}
/**
* Tests different connection types.
*/
public function testConnectionTypes() {
$sql_base = new TestSqlBase();
$sql_base = new TestSqlBase([], $this->migration);
// Check the default values.
$sql_base->setConfiguration([]);
$this->assertIdentical($sql_base->getDatabase()->getTarget(), 'default');
$this->assertIdentical($sql_base->getDatabase()->getKey(), 'migrate');
// Verify that falling back to the default 'migrate' connection (defined in
// the base class) works.
$this->assertSame($sql_base->getDatabase()->getTarget(), 'default');
$this->assertSame($sql_base->getDatabase()->getKey(), 'migrate');
// Verify the fallback state key overrides the 'migrate' connection.
$target = 'test_fallback_target';
$key = 'test_fallback_key';
$config = ['target' => $target, 'key' => $key];
$database_state_key = 'test_fallback_state';
\Drupal::state()->set($database_state_key, $config);
\Drupal::state()->set('migrate.fallback_state_key', $database_state_key);
// Create a test connection using the default database configuration.
Database::addConnectionInfo($key, $target, Database::getConnectionInfo('default')['default']);
$this->assertSame($sql_base->getDatabase()->getTarget(), $target);
$this->assertSame($sql_base->getDatabase()->getKey(), $key);
// Verify that setting explicit connection information overrides fallbacks.
$target = 'test_db_target';
$key = 'test_migrate_connection';
$config = ['target' => $target, 'key' => $key];
@@ -35,11 +69,11 @@ class SqlBaseTest extends MigrateTestBase {
Database::addConnectionInfo($key, $target, Database::getConnectionInfo('default')['default']);
// Validate we have injected our custom key and target.
$this->assertIdentical($sql_base->getDatabase()->getTarget(), $target);
$this->assertIdentical($sql_base->getDatabase()->getKey(), $key);
$this->assertSame($sql_base->getDatabase()->getTarget(), $target);
$this->assertSame($sql_base->getDatabase()->getKey(), $key);
// Now test we can have SqlBase create the connection from an info array.
$sql_base = new TestSqlBase();
$sql_base = new TestSqlBase([], $this->migration);
$target = 'test_db_target2';
$key = 'test_migrate_connection2';
@@ -51,7 +85,7 @@ class SqlBaseTest extends MigrateTestBase {
$sql_base->getDatabase();
// Validate the connection has been created with the right values.
$this->assertIdentical(Database::getConnectionInfo($key)[$target], $database);
$this->assertSame(Database::getConnectionInfo($key)[$target], $database);
// Now, test this all works when using state to store db info.
$target = 'test_state_db_target';
@@ -63,11 +97,11 @@ class SqlBaseTest extends MigrateTestBase {
Database::addConnectionInfo($key, $target, Database::getConnectionInfo('default')['default']);
// Validate we have injected our custom key and target.
$this->assertIdentical($sql_base->getDatabase()->getTarget(), $target);
$this->assertIdentical($sql_base->getDatabase()->getKey(), $key);
$this->assertSame($sql_base->getDatabase()->getTarget(), $target);
$this->assertSame($sql_base->getDatabase()->getKey(), $key);
// Now test we can have SqlBase create the connection from an info array.
$sql_base = new TestSqlBase();
$sql_base = new TestSqlBase([], $this->migration);
$target = 'test_state_db_target2';
$key = 'test_state_migrate_connection2';
@@ -81,13 +115,68 @@ class SqlBaseTest extends MigrateTestBase {
$sql_base->getDatabase();
// Validate the connection has been created with the right values.
$this->assertIdentical(Database::getConnectionInfo($key)[$target], $database);
$this->assertSame(Database::getConnectionInfo($key)[$target], $database);
// Verify that falling back to 'migrate' when the connection is not defined
// throws a RequirementsException.
\Drupal::state()->delete('migrate.fallback_state_key');
$sql_base->setConfiguration([]);
Database::renameConnection('migrate', 'fallback_connection');
$this->setExpectedException(RequirementsException::class,
'No database connection configured for source plugin');
$sql_base->getDatabase();
}
/**
* Tests that SqlBase respects high-water values.
*
* @param mixed $high_water
* (optional) The high-water value to set.
* @param array $query_result
* (optional) The expected query results.
*
* @dataProvider highWaterDataProvider
*/
public function testHighWater($high_water = NULL, array $query_result = []) {
$configuration = [
'high_water_property' => [
'name' => 'order',
],
];
$source = new TestSqlBase($configuration, $this->migration);
if ($high_water) {
$source->getHighWaterStorage()->set($this->migration->id(), $high_water);
}
$query_result = new \ArrayIterator($query_result);
$query = $this->getMock(SelectInterface::class);
$query->method('execute')->willReturn($query_result);
$query->expects($this->atLeastOnce())->method('orderBy')->with('order', 'ASC');
$condition_group = $this->getMock(ConditionInterface::class);
$query->method('orConditionGroup')->willReturn($condition_group);
$source->setQuery($query);
$source->rewind();
}
/**
* Data provider for ::testHighWater().
*
* @return array
* The scenarios to test.
*/
public function highWaterDataProvider() {
return [
'no high-water value set' => [],
'high-water value set' => [33],
];
}
}
namespace Drupal\migrate\Plugin\migrate\source;
/**
* A dummy source to help with testing SqlBase.
*
@@ -96,10 +185,22 @@ namespace Drupal\migrate\Plugin\migrate\source;
class TestSqlBase extends SqlBase {
/**
* Overrides the constructor so we can create one easily.
* The query to execute.
*
* @var \Drupal\Core\Database\Query\SelectInterface
*/
public function __construct() {
$this->state = \Drupal::state();
protected $query;
/**
* Overrides the constructor so we can create one easily.
*
* @param array $configuration
* The plugin instance configuration.
* @param \Drupal\migrate\Plugin\MigrationInterface $migration
* (optional) The migration being run.
*/
public function __construct(array $configuration = [], MigrationInterface $migration = NULL) {
parent::__construct($configuration, 'sql_base', [], $migration, \Drupal::state());
}
/**
@@ -133,6 +234,25 @@ class TestSqlBase extends SqlBase {
/**
* {@inheritdoc}
*/
public function query() {}
public function query() {
return $this->query;
}
/**
* Sets the query to execute.
*
* @param \Drupal\Core\Database\Query\SelectInterface $query
* The query to execute.
*/
public function setQuery(SelectInterface $query) {
$this->query = $query;
}
/**
* {@inheritdoc}
*/
public function getHighWaterStorage() {
return parent::getHighWaterStorage();
}
}
@@ -3,12 +3,13 @@
namespace Drupal\Tests\migrate\Unit\Event;
use Drupal\migrate\Event\EventBase;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\migrate\Event\EventBase
* @group migrate
*/
class EventBaseTest extends \PHPUnit_Framework_TestCase {
class EventBaseTest extends UnitTestCase {
/**
* Test getMigration method.
@@ -3,12 +3,13 @@
namespace Drupal\Tests\migrate\Unit\Event;
use Drupal\migrate\Event\MigrateImportEvent;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\migrate\Event\MigrateImportEvent
* @group migrate
*/
class MigrateImportEventTest extends \PHPUnit_Framework_TestCase {
class MigrateImportEventTest extends UnitTestCase {
/**
* Test getMigration method.
@@ -439,6 +439,33 @@ class MigrateExecutableTest extends MigrateTestCase {
$this->executable->processRow($row);
}
/**
* Tests the processRow method.
*/
public function testProcessRowEmptyDestination() {
$expected = [
'test' => 'test destination',
'test1' => 'test1 destination',
'test2' => NULL,
];
$row = new Row();
$plugins = [];
foreach ($expected as $key => $value) {
$plugin = $this->prophesize(MigrateProcessInterface::class);
$plugin->getPluginDefinition()->willReturn([]);
$plugin->transform(NULL, $this->executable, $row, $key)->willReturn($value);
$plugin->multiple()->willReturn(TRUE);
$plugins[$key][0] = $plugin->reveal();
}
$this->migration->method('getProcessPlugins')->willReturn($plugins);
$this->executable->processRow($row);
foreach ($expected as $key => $value) {
$this->assertSame($value, $row->getDestinationProperty($key));
}
$this->assertCount(2, $row->getDestination());
$this->assertSame(['test2'], $row->getEmptyDestinationProperties());
}
/**
* Returns a mock migration source instance.
*
@@ -61,12 +61,12 @@ abstract class MigrateTestCase extends UnitTestCase {
// on the test class and use a return callback.
$migration->expects($this->any())
->method('getStatus')
->willReturnCallback(function() {
->willReturnCallback(function () {
return $this->migrationStatus;
});
$migration->expects($this->any())
->method('setStatus')
->willReturnCallback(function($status) {
->willReturnCallback(function ($status) {
$this->migrationStatus = $status;
});
@@ -147,7 +147,9 @@ abstract class MigrateTestCase extends UnitTestCase {
protected function createSchemaFromRow(array $row) {
// SQLite uses loose ("affinity") typing, so it is OK for every column to be
// a text field.
$fields = array_map(function() { return ['type' => 'text']; }, $row);
$fields = array_map(function () {
return ['type' => 'text'];
}, $row);
return ['fields' => $fields];
}
@@ -183,7 +183,7 @@ class TestMigrationMock extends Migration {
/**
* The values passed into set().
*
* @var array $set
* @var array
*/
public $set = [];
@@ -113,7 +113,7 @@ class EntityContentBaseTest extends UnitTestCase {
$this->storage->getEntityType()->willReturn($entity_type->reveal());
$destination = new EntityTestDestination(
[ 'translations' => TRUE ],
['translations' => TRUE],
'',
[],
$this->migration->reveal(),
@@ -2,9 +2,6 @@
namespace Drupal\Tests\migrate\Unit\process;
@trigger_error('The ' . __NAMESPACE__ . '\DedupeEntityTest is deprecated in
Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPACE__ . '\MakeUniqueEntityFieldTest', E_USER_DEPRECATED);
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Query\QueryInterface;
@@ -14,14 +11,14 @@ use Drupal\Component\Utility\Unicode;
/**
* @coversDefaultClass \Drupal\migrate\Plugin\migrate\process\DedupeEntity
* @group migrate
* @group legacy
*/
class DedupeEntityTest extends MigrateProcessTestCase {
/**
* The mock entity query.
*
* @var \Drupal\Core\Entity\Query\QueryInterface
* @var \Drupal\Core\Entity\Query\QueryFactory
* @var \Drupal\Core\Entity\Query\QueryInterface|\Drupal\Core\Entity\Query\QueryFactory
*/
protected $entityQuery;
@@ -168,7 +165,9 @@ class DedupeEntityTest extends MigrateProcessTestCase {
->will($this->returnValue($this->entityQuery));
$this->entityQuery->expects($this->exactly($count + 1))
->method('execute')
->will($this->returnCallback(function () use (&$count) { return $count--;}));
->will($this->returnCallback(function () use (&$count) {
return $count--;
}));
}
/**
@@ -1,8 +1,8 @@
<?php
namespace Drupal\Tests\migrate\Unit\process;
use Drupal\migrate\Plugin\migrate\process\Flatten;
use Drupal\migrate\Plugin\migrate\process\Flatten;
/**
* Tests the flatten plugin.
@@ -48,7 +48,9 @@ class GetTest extends MigrateProcessTestCase {
$this->plugin->setSource(['test1', 'test2']);
$this->row->expects($this->exactly(2))
->method('getSourceProperty')
->will($this->returnCallback(function ($argument) use ($map) { return $map[$argument]; } ));
->will($this->returnCallback(function ($argument) use ($map) {
return $map[$argument];
}));
$value = $this->plugin->transform(NULL, $this->migrateExecutable, $this->row, 'destinationproperty');
$this->assertSame($value, ['source_value1', 'source_value2']);
}
@@ -79,7 +81,9 @@ class GetTest extends MigrateProcessTestCase {
$this->plugin->setSource(['test1', '@@test2', '@@test3', 'test4']);
$this->row->expects($this->exactly(4))
->method('getSourceProperty')
->will($this->returnCallback(function ($argument) use ($map) { return $map[$argument]; } ));
->will($this->returnCallback(function ($argument) use ($map) {
return $map[$argument];
}));
$value = $this->plugin->transform(NULL, $this->migrateExecutable, $this->row, 'destinationproperty');
$this->assertSame($value, ['source_value1', 'source_value2', 'source_value3', 'source_value4']);
}
@@ -31,6 +31,8 @@ class IteratorTest extends MigrateTestCase {
/**
* Tests the iterator process plugin.
*
* @group legacy
*/
public function testIterator() {
$migration = $this->getMigration();
@@ -17,8 +17,7 @@ class MakeUniqueEntityFieldTest extends MigrateProcessTestCase {
/**
* The mock entity query.
*
* @var \Drupal\Core\Entity\Query\QueryInterface
* @var \Drupal\Core\Entity\Query\QueryFactory
* @var \Drupal\Core\Entity\Query\QueryInterface|\Drupal\Core\Entity\Query\QueryFactory
*/
protected $entityQuery;
@@ -165,7 +164,9 @@ class MakeUniqueEntityFieldTest extends MigrateProcessTestCase {
->will($this->returnValue($this->entityQuery));
$this->entityQuery->expects($this->exactly($count + 1))
->method('execute')
->will($this->returnCallback(function () use (&$count) { return $count--;}));
->will($this->returnCallback(function () use (&$count) {
return $count--;
}));
}
/**
@@ -199,4 +199,43 @@ class MigrationLookupTest extends MigrateProcessTestCase {
];
}
/**
* Tests that a message is successfully created if import fails.
*/
public function testImportException() {
$migration_plugin = $this->prophesize(MigrationInterface::class);
$migration_plugin_manager = $this->prophesize(MigrationPluginManagerInterface::class);
$process_plugin_manager = $this->prophesize(MigratePluginManager::class);
$destination_id_map = $this->prophesize(MigrateIdMapInterface::class);
$destination_migration = $this->prophesize('Drupal\migrate\Plugin\Migration');
$destination_migration->getIdMap()->willReturn($destination_id_map->reveal());
$migration_plugin_manager->createInstances(['destination_migration'])
->willReturn(['destination_migration' => $destination_migration->reveal()]);
$destination_id_map->lookupDestinationId([1])->willReturn(NULL);
$destination_id_map->saveMessage(Argument::any(), Argument::any())->willReturn(NULL);
$destination_id_map->saveIdMapping(Argument::any(), Argument::any(), Argument::any())->shouldNotBeCalled();
$configuration = [
'no_stub' => FALSE,
'migration' => 'destination_migration',
];
$destination_migration->id()->willReturn('destination_migration');
$destination_migration->getDestinationPlugin(TRUE)->shouldBeCalled();
$destination_migration->getProcess()->willReturn([]);
$destination_migration->getSourceConfiguration()->willReturn([]);
$source_plugin = $this->prophesize(MigrateSourceInterface::class);
$source_plugin->getIds()->willReturn(['nid']);
$destination_migration->getSourcePlugin()->willReturn($source_plugin->reveal());
$destination_plugin = $this->prophesize(MigrateDestinationInterface::class);
$e = new \Exception();
$destination_plugin->import(Argument::any())->willThrow($e);
$destination_migration->getDestinationPlugin(TRUE)->willReturn($destination_plugin->reveal());
$migration = new MigrationLookup($configuration, '', [], $migration_plugin->reveal(), $migration_plugin_manager->reveal(), $process_plugin_manager->reveal());
$migration->transform(1, $this->migrateExecutable, $this->row, '');
}
}
@@ -2,9 +2,6 @@
namespace Drupal\Tests\migrate\Unit\process;
@trigger_error('The ' . __NAMESPACE__ . '\MigrationTest is deprecated in
Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use ' . __NAMESPACE__ . '\MigrationLookupTest', E_USER_DEPRECATED);
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\migrate\MigrateSkipProcessException;
use Drupal\migrate\Plugin\MigrationInterface;
@@ -17,11 +14,9 @@ use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Prophecy\Argument;
/**
* @deprecated in Drupal 8.4.x, to be removed before Drupal 9.0.x. Use
* \Drupal\Tests\migrate\Unit\process\MigrationLookupTest instead.
*
* @coversDefaultClass \Drupal\migrate\Plugin\migrate\process\Migration
* @group migrate
* @group legacy
*/
class MigrationTest extends MigrateProcessTestCase {
@@ -0,0 +1,82 @@
<?php
namespace Drupal\Tests\migrate\Unit\process;
use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\Plugin\migrate\process\Get;
use Drupal\migrate\Plugin\migrate\process\SubProcess;
use Drupal\migrate\Row;
use Drupal\Tests\migrate\Unit\MigrateTestCase;
/**
* Tests the sub_process process plugin.
*
* @group migrate
*/
class SubProcessTest extends MigrateTestCase {
/**
* The sub_process plugin being tested.
*
* @var \Drupal\migrate\Plugin\migrate\process\SubProcess
*/
protected $plugin;
/**
* @var array
*/
protected $migrationConfiguration = [
'id' => 'test',
];
/**
* Tests the sub_process process plugin.
*/
public function testSubProcess() {
$migration = $this->getMigration();
// Set up the properties for the sub_process.
$configuration = [
'process' => [
'foo' => 'source_foo',
'id' => 'source_id',
],
'key' => '@id',
];
$plugin = new SubProcess($configuration, 'sub_process', []);
// Manually create the plugins. Migration::getProcessPlugins does this
// normally but the plugin system is not available.
foreach ($configuration['process'] as $destination => $source) {
$sub_process_plugins[$destination][] = new Get(['source' => $source], 'get', []);
}
$migration->expects($this->at(1))
->method('getProcessPlugins')
->willReturn($sub_process_plugins);
// Set up the key plugins.
$key_plugin['key'][] = new Get(['source' => '@id'], 'get', []);
$migration->expects($this->at(2))
->method('getProcessPlugins')
->will($this->returnValue($key_plugin));
$event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$migrate_executable = new MigrateExecutable($migration, $this->getMock('Drupal\migrate\MigrateMessageInterface'), $event_dispatcher);
// The current value of the pipeline.
$current_value = [
[
'source_foo' => 'test',
'source_id' => 42,
],
];
// This is not used but the interface requires it, so create an empty row.
$row = new Row();
// After transformation, check to make sure that source_foo and source_id's
// values ended up in the proper destinations, and that the value of the
// key (@id) is the same as the destination ID (42).
$new_value = $plugin->transform($current_value, $migrate_executable, $row, 'test');
$this->assertSame(count($new_value), 1);
$this->assertSame(count($new_value[42]), 2);
$this->assertSame($new_value[42]['foo'], 'test');
$this->assertSame($new_value[42]['id'], 42);
}
}