Update to Drupal 8.2.2. For more information, see https://www.drupal.org/project/drupal/releases/8.2.2
This commit is contained in:
parent
23ffed3665
commit
507b45a0ed
378 changed files with 11434 additions and 5542 deletions
|
@ -66,13 +66,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
*/
|
||||
protected $counts = array();
|
||||
|
||||
/**
|
||||
* The object currently being constructed.
|
||||
*
|
||||
* @var \stdClass
|
||||
*/
|
||||
protected $destinationValues;
|
||||
|
||||
/**
|
||||
* The source.
|
||||
*
|
||||
|
@ -80,13 +73,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
*/
|
||||
protected $source;
|
||||
|
||||
/**
|
||||
* The current data row retrieved from the source.
|
||||
*
|
||||
* @var \stdClass
|
||||
*/
|
||||
protected $sourceValues;
|
||||
|
||||
/**
|
||||
* The event dispatcher.
|
||||
*
|
||||
|
@ -94,6 +80,15 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
*/
|
||||
protected $eventDispatcher;
|
||||
|
||||
/**
|
||||
* Migration message service.
|
||||
*
|
||||
* @todo https://www.drupal.org/node/2822663 Make this protected.
|
||||
*
|
||||
* @var \Drupal\migrate\MigrateMessageInterface
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* Constructs a MigrateExecutable and verifies and sets the memory limit.
|
||||
*
|
||||
|
@ -229,7 +224,12 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
$save = FALSE;
|
||||
}
|
||||
catch (MigrateSkipRowException $e) {
|
||||
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED);
|
||||
if ($e->getSaveToMap()) {
|
||||
$id_map->saveIdMapping($row, [], MigrateIdMapInterface::STATUS_IGNORED);
|
||||
}
|
||||
if ($message = trim($e->getMessage())) {
|
||||
$this->saveMessage($message, MigrationInterface::MESSAGE_INFORMATIONAL);
|
||||
}
|
||||
$save = FALSE;
|
||||
}
|
||||
|
||||
|
@ -263,8 +263,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
}
|
||||
}
|
||||
|
||||
// Reset row properties.
|
||||
unset($sourceValues, $destinationValues);
|
||||
$this->sourceRowStatus = MigrateIdMapInterface::STATUS_IMPORTED;
|
||||
|
||||
// Check for memory exhaustion.
|
||||
|
|
|
@ -21,15 +21,59 @@ use Drupal\migrate\Row;
|
|||
interface MigrateDestinationInterface extends PluginInspectionInterface {
|
||||
|
||||
/**
|
||||
* Get the destination IDs.
|
||||
* Gets the destination IDs.
|
||||
*
|
||||
* To support MigrateIdMap maps, derived destination classes should return
|
||||
* schema field definition(s) corresponding to the primary key of the
|
||||
* destination being implemented. These are used to construct the destination
|
||||
* key fields of the map table for a migration using this destination.
|
||||
* field definition(s) corresponding to the primary key of the destination
|
||||
* being implemented. These are used to construct the destination key fields
|
||||
* of the map table for a migration using this destination.
|
||||
*
|
||||
* @return array
|
||||
* An array of IDs.
|
||||
* @return array[]
|
||||
* An associative array of field definitions keyed by field ID. Values are
|
||||
* associative arrays with a structure that contains the field type ('type'
|
||||
* key). The other keys are the field storage settings as they are returned
|
||||
* by FieldStorageDefinitionInterface::getSettings(). As an example, for a
|
||||
* composite destination primary key that is defined by an integer and a
|
||||
* string, the returned value might look like:
|
||||
* @code
|
||||
* return [
|
||||
* 'id' => [
|
||||
* 'type' => 'integer',
|
||||
* 'unsigned' => FALSE,
|
||||
* 'size' => 'big',
|
||||
* ],
|
||||
* 'version' => [
|
||||
* 'type' => 'string',
|
||||
* 'max_length' => 64,
|
||||
* 'is_ascii' => TRUE,
|
||||
* ],
|
||||
* ];
|
||||
* @endcode
|
||||
* If 'type' points to a field plugin with multiple columns and needs to
|
||||
* refer to a column different than 'value', the key of that column will be
|
||||
* appended as a suffix to the plugin name, separated by dot ('.'). Example:
|
||||
* @code
|
||||
* return [
|
||||
* 'format' => [
|
||||
* 'type' => 'text.format',
|
||||
* ],
|
||||
* ];
|
||||
* @endcode
|
||||
* Additional custom keys/values, that are not part of field storage
|
||||
* definition, can be passed in definitions:
|
||||
* @code
|
||||
* return [
|
||||
* 'nid' => [
|
||||
* 'type' => 'integer',
|
||||
* 'custom_setting' => 'some_value',
|
||||
* ],
|
||||
* ];
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\Core\Field\FieldStorageDefinitionInterface::getSettings()
|
||||
* @see \Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem
|
||||
* @see \Drupal\Core\Field\Plugin\Field\FieldType\StringItem
|
||||
* @see \Drupal\text\Plugin\Field\FieldType\TextItem
|
||||
*/
|
||||
public function getIds();
|
||||
|
||||
|
|
|
@ -41,8 +41,7 @@ class MigratePluginManager extends DefaultPluginManager implements MigratePlugin
|
|||
* 'Drupal\Component\Annotation\PluginID'.
|
||||
*/
|
||||
public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, $annotation = 'Drupal\Component\Annotation\PluginID') {
|
||||
$plugin_interface = isset($plugin_interface_map[$type]) ? $plugin_interface_map[$type] : NULL;
|
||||
parent::__construct("Plugin/migrate/$type", $namespaces, $module_handler, $plugin_interface, $annotation);
|
||||
parent::__construct("Plugin/migrate/$type", $namespaces, $module_handler, NULL, $annotation);
|
||||
$this->alterInfo('migrate_' . $type . '_info');
|
||||
$this->setCacheBackend($cache_backend, 'migrate_plugins_' . $type);
|
||||
}
|
||||
|
|
|
@ -49,9 +49,54 @@ interface MigrateSourceInterface extends \Countable, \Iterator, PluginInspection
|
|||
* prepareRow() or hook_migrate_prepare_row() to rewrite NULL values to
|
||||
* appropriate empty values (such as '' or 0).
|
||||
*
|
||||
* @return array
|
||||
* Array keyed by source field name, with values being a schema array
|
||||
* describing the field (such as ['type' => 'string]).
|
||||
* @return array[]
|
||||
* An associative array of field definitions keyed by field ID. Values are
|
||||
* associative arrays with a structure that contains the field type ('type'
|
||||
* key). The other keys are the field storage settings as they are returned
|
||||
* by FieldStorageDefinitionInterface::getSettings(). As an example, for a
|
||||
* composite source primary key that is defined by an integer and a
|
||||
* string, the returned value might look like:
|
||||
* @code
|
||||
* return [
|
||||
* 'id' => [
|
||||
* 'type' => 'integer',
|
||||
* 'unsigned' => FALSE,
|
||||
* 'size' => 'big',
|
||||
* ],
|
||||
* 'version' => [
|
||||
* 'type' => 'string',
|
||||
* 'max_length' => 64,
|
||||
* 'is_ascii' => TRUE,
|
||||
* ],
|
||||
* ];
|
||||
* @endcode
|
||||
* If 'type' points to a field plugin with multiple columns and needs to
|
||||
* refer to a column different than 'value', the key of that column will be
|
||||
* appended as a suffix to the plugin name, separated by dot ('.'). Example:
|
||||
* @code
|
||||
* return [
|
||||
* 'format' => [
|
||||
* 'type' => 'text.format',
|
||||
* ],
|
||||
* ];
|
||||
* @endcode
|
||||
* Additional custom keys/values, that are not part of field storage
|
||||
* definition, can be passed in definitions. The most common setting, passed
|
||||
* along the ID definition, is 'alias' used by SqlBase source plugin:
|
||||
* @code
|
||||
* return [
|
||||
* 'nid' => [
|
||||
* 'type' => 'integer',
|
||||
* 'alias' => 'n',
|
||||
* ],
|
||||
* ];
|
||||
* @endcode
|
||||
*
|
||||
* @see \Drupal\Core\Field\FieldStorageDefinitionInterface::getSettings()
|
||||
* @see \Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem
|
||||
* @see \Drupal\Core\Field\Plugin\Field\FieldType\StringItem
|
||||
* @see \Drupal\text\Plugin\Field\FieldType\TextItem
|
||||
* @see \Drupal\migrate\Plugin\migrate\source\SqlBase
|
||||
*/
|
||||
public function getIds();
|
||||
|
||||
|
|
|
@ -125,15 +125,13 @@ class EntityContentBase extends Entity {
|
|||
*/
|
||||
public function getIds() {
|
||||
$id_key = $this->getKey('id');
|
||||
$ids[$id_key]['type'] = 'integer';
|
||||
$ids[$id_key] = $this->getDefinitionFromEntity($id_key);
|
||||
|
||||
if ($this->isTranslationDestination()) {
|
||||
if ($key = $this->getKey('langcode')) {
|
||||
$ids[$key]['type'] = 'string';
|
||||
}
|
||||
else {
|
||||
if (!$langcode_key = $this->getKey('langcode')) {
|
||||
throw new MigrateException('This entity type does not support translation.');
|
||||
}
|
||||
$ids[$langcode_key] = $this->getDefinitionFromEntity($langcode_key);
|
||||
}
|
||||
|
||||
return $ids;
|
||||
|
@ -263,4 +261,32 @@ class EntityContentBase extends Entity {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the field definition from a specific entity base field.
|
||||
*
|
||||
* The method takes the field ID as an argument and returns the field storage
|
||||
* definition to be used in getIds() by querying the destination entity base
|
||||
* field definition.
|
||||
*
|
||||
* @param string $key
|
||||
* The field ID key.
|
||||
*
|
||||
* @return array
|
||||
* An associative array with a structure that contains the field type, keyed
|
||||
* as 'type', together with field storage settings as they are returned by
|
||||
* FieldStorageDefinitionInterface::getSettings().
|
||||
*
|
||||
* @see \Drupal\Core\Field\FieldStorageDefinitionInterface::getSettings()
|
||||
*/
|
||||
protected function getDefinitionFromEntity($key) {
|
||||
$entity_type_id = static::getEntityTypeId($this->getPluginId());
|
||||
/** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $definitions */
|
||||
$definitions = $this->entityManager->getBaseFieldDefinitions($entity_type_id);
|
||||
$field_definition = $definitions[$key];
|
||||
|
||||
return [
|
||||
'type' => $field_definition->getType(),
|
||||
] + $field_definition->getSettings();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -73,8 +73,7 @@ class EntityRevision extends EntityContentBase {
|
|||
*/
|
||||
public function getIds() {
|
||||
if ($key = $this->getKey('revision')) {
|
||||
$ids[$key]['type'] = 'integer';
|
||||
return $ids;
|
||||
return [$key => $this->getDefinitionFromEntity($key)];
|
||||
}
|
||||
throw new MigrateException('This entity type does not support revisions.');
|
||||
}
|
||||
|
|
|
@ -441,20 +441,40 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
* Creates schema from an ID definition.
|
||||
*
|
||||
* @param array $id_definition
|
||||
* A field schema definition. Can be SQL schema or a type data
|
||||
* based schema. In the latter case, the value of type needs to be
|
||||
* $typed_data_type.$column.
|
||||
* The definition of the field having the structure as the items returned by
|
||||
* MigrateSourceInterface or MigrateDestinationInterface::getIds().
|
||||
*
|
||||
* @return array
|
||||
* The schema definition.
|
||||
* The database schema definition.
|
||||
*
|
||||
* @see \Drupal\migrate\Plugin\MigrateSourceInterface::getIds()
|
||||
* @see \Drupal\migrate\Plugin\MigrateDestinationInterface::getIds()
|
||||
*/
|
||||
protected function getFieldSchema(array $id_definition) {
|
||||
$type_parts = explode('.', $id_definition['type']);
|
||||
if (count($type_parts) == 1) {
|
||||
$type_parts[] = 'value';
|
||||
}
|
||||
$schema = BaseFieldDefinition::create($type_parts[0])->getColumns();
|
||||
return $schema[$type_parts[1]];
|
||||
unset($id_definition['type']);
|
||||
|
||||
// Get the field storage definition.
|
||||
$definition = BaseFieldDefinition::create($type_parts[0]);
|
||||
|
||||
// Get a list of setting keys belonging strictly to the field definition.
|
||||
$default_field_settings = $definition->getSettings();
|
||||
// Separate field definition settings from custom settings. Custom settings
|
||||
// are settings passed in $id_definition that are not part of field storage
|
||||
// definition settings.
|
||||
$field_settings = array_intersect_key($id_definition, $default_field_settings);
|
||||
$custom_settings = array_diff_key($id_definition, $default_field_settings);
|
||||
|
||||
// Resolve schema from field storage definition settings.
|
||||
$schema = $definition
|
||||
->setSettings($field_settings)
|
||||
->getColumns()[$type_parts[1]];
|
||||
|
||||
// Merge back custom settings.
|
||||
return $schema + $custom_settings;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
117
core/modules/migrate/src/Plugin/migrate/process/Download.php
Normal file
117
core/modules/migrate/src/Plugin/migrate/process/Download.php
Normal file
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Core\File\FileSystemInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
use GuzzleHttp\Client;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Downloads a file from a remote location into the local file system.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "download"
|
||||
* )
|
||||
*/
|
||||
class Download extends ProcessPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The file system service.
|
||||
*
|
||||
* @var \Drupal\Core\File\FileSystemInterface
|
||||
*/
|
||||
protected $fileSystem;
|
||||
|
||||
/**
|
||||
* The Guzzle HTTP Client service.
|
||||
*
|
||||
* @var \GuzzleHttp\Client
|
||||
*/
|
||||
protected $httpClient;
|
||||
|
||||
/**
|
||||
* Constructs a download process plugin.
|
||||
*
|
||||
* @param array $configuration
|
||||
* The plugin configuration.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin definition.
|
||||
* @param \Drupal\Core\File\FileSystemInterface $file_system
|
||||
* The file system service.
|
||||
* @param \GuzzleHttp\Client $http_client
|
||||
* The HTTP client.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, array $plugin_definition, FileSystemInterface $file_system, Client $http_client) {
|
||||
$configuration += [
|
||||
'rename' => FALSE,
|
||||
'guzzle_options' => [],
|
||||
];
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->fileSystem = $file_system;
|
||||
$this->httpClient = $http_client;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('file_system'),
|
||||
$container->get('http_client')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
// If we're stubbing a file entity, return a uri of NULL so it will get
|
||||
// stubbed by the general process.
|
||||
if ($row->isStub()) {
|
||||
return NULL;
|
||||
}
|
||||
list($source, $destination) = $value;
|
||||
|
||||
// Modify the destination filename if necessary.
|
||||
$replace = !empty($this->configuration['rename']) ?
|
||||
FILE_EXISTS_RENAME :
|
||||
FILE_EXISTS_REPLACE;
|
||||
$final_destination = file_destination($destination, $replace);
|
||||
|
||||
// Try opening the file first, to avoid calling file_prepare_directory()
|
||||
// unnecessarily. We're suppressing fopen() errors because we want to try
|
||||
// to prepare the directory before we give up and fail.
|
||||
$destination_stream = @fopen($final_destination, 'w');
|
||||
if (!$destination_stream) {
|
||||
// If fopen didn't work, make sure there's a writable directory in place.
|
||||
$dir = $this->fileSystem->dirname($final_destination);
|
||||
if (!file_prepare_directory($dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
|
||||
throw new MigrateException("Could not create or write to directory '$dir'");
|
||||
}
|
||||
// Let's try that fopen again.
|
||||
$destination_stream = @fopen($final_destination, 'w');
|
||||
if (!$destination_stream) {
|
||||
throw new MigrateException("Could not write to file '$final_destination'");
|
||||
}
|
||||
}
|
||||
|
||||
// Stream the request body directly to the final destination stream.
|
||||
$this->configuration['guzzle_options']['sink'] = $destination_stream;
|
||||
|
||||
// Make the request. Guzzle throws an exception for anything other than 200.
|
||||
$this->httpClient->get($source, $this->configuration['guzzle_options']);
|
||||
|
||||
return $final_destination;
|
||||
}
|
||||
|
||||
}
|
|
@ -14,7 +14,8 @@ use Drupal\migrate\Row;
|
|||
* @link https://www.drupal.org/node/2152731 Online handbook documentation for extract process plugin @endlink
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "extract"
|
||||
* id = "extract",
|
||||
* handle_multiples = TRUE
|
||||
* )
|
||||
*/
|
||||
class Extract extends ProcessPluginBase {
|
||||
|
|
|
@ -8,6 +8,7 @@ use Drupal\Core\StreamWrapper\LocalStream;
|
|||
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Plugin\MigrateProcessInterface;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
@ -35,6 +36,13 @@ class FileCopy extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
*/
|
||||
protected $fileSystem;
|
||||
|
||||
/**
|
||||
* An instance of the download process plugin.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigrateProcessInterface
|
||||
*/
|
||||
protected $downloadPlugin;
|
||||
|
||||
/**
|
||||
* Constructs a file_copy process plugin.
|
||||
*
|
||||
|
@ -48,8 +56,10 @@ class FileCopy extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
* The stream wrapper manager service.
|
||||
* @param \Drupal\Core\File\FileSystemInterface $file_system
|
||||
* The file system service.
|
||||
* @param \Drupal\migrate\Plugin\MigrateProcessInterface $download_plugin
|
||||
* An instance of the download plugin for handling remote URIs.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, array $plugin_definition, StreamWrapperManagerInterface $stream_wrappers, FileSystemInterface $file_system) {
|
||||
public function __construct(array $configuration, $plugin_id, array $plugin_definition, StreamWrapperManagerInterface $stream_wrappers, FileSystemInterface $file_system, MigrateProcessInterface $download_plugin) {
|
||||
$configuration += array(
|
||||
'move' => FALSE,
|
||||
'rename' => FALSE,
|
||||
|
@ -58,6 +68,7 @@ class FileCopy extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->streamWrapperManager = $stream_wrappers;
|
||||
$this->fileSystem = $file_system;
|
||||
$this->downloadPlugin = $download_plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,7 +80,8 @@ class FileCopy extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('stream_wrapper_manager'),
|
||||
$container->get('file_system')
|
||||
$container->get('file_system'),
|
||||
$container->get('plugin.manager.migrate.process')->createInstance('download')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -84,8 +96,14 @@ class FileCopy extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
}
|
||||
list($source, $destination) = $value;
|
||||
|
||||
// If the source path or URI represents a remote resource, delegate to the
|
||||
// download plugin.
|
||||
if (!$this->isLocalUri($source)) {
|
||||
return $this->downloadPlugin->transform($value, $migrate_executable, $row, $destination_property);
|
||||
}
|
||||
|
||||
// Ensure the source file exists, if it's a local URI or path.
|
||||
if ($this->isLocalUri($source) && !file_exists($source)) {
|
||||
if (!file_exists($source)) {
|
||||
throw new MigrateException("File '$source' does not exist");
|
||||
}
|
||||
|
||||
|
@ -128,20 +146,14 @@ class FileCopy extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
* File destination on success, FALSE on failure.
|
||||
*/
|
||||
protected function writeFile($source, $destination, $replace = FILE_EXISTS_REPLACE) {
|
||||
if ($this->configuration['move']) {
|
||||
return file_unmanaged_move($source, $destination, $replace);
|
||||
}
|
||||
// Check if there is a destination available for copying. If there isn't,
|
||||
// it already exists at the destination and the replace flag tells us to not
|
||||
// replace it. In that case, return the original destination.
|
||||
if (!($final_destination = file_destination($destination, $replace))) {
|
||||
return $destination;
|
||||
}
|
||||
// We can't use file_unmanaged_copy because it will break with remote Urls.
|
||||
if (@copy($source, $final_destination)) {
|
||||
return $final_destination;
|
||||
}
|
||||
return FALSE;
|
||||
$function = 'file_unmanaged_' . ($this->configuration['move'] ? 'move' : 'copy');
|
||||
return $function($source, $destination, $replace);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,8 +199,6 @@ class FileCopy extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
/**
|
||||
* Determines if the source and destination URIs represent identical paths.
|
||||
*
|
||||
* If either URI is a remote stream, will return FALSE.
|
||||
*
|
||||
* @param string $source
|
||||
* The source URI.
|
||||
* @param string $destination
|
||||
|
@ -199,10 +209,7 @@ class FileCopy extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
* otherwise FALSE.
|
||||
*/
|
||||
protected function isLocationUnchanged($source, $destination) {
|
||||
if ($this->isLocalUri($source) && $this->isLocalUri($destination)) {
|
||||
return $this->fileSystem->realpath($source) === $this->fileSystem->realpath($destination);
|
||||
}
|
||||
return FALSE;
|
||||
return $this->fileSystem->realpath($source) === $this->fileSystem->realpath($destination);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -219,6 +226,13 @@ class FileCopy extends ProcessPluginBase implements ContainerFactoryPluginInterf
|
|||
*/
|
||||
protected function isLocalUri($uri) {
|
||||
$scheme = $this->fileSystem->uriScheme($uri);
|
||||
|
||||
// The vfs scheme is vfsStream, which is used in testing. vfsStream is a
|
||||
// simulated file system that exists only in memory, but should be treated
|
||||
// as a local resource.
|
||||
if ($scheme == 'vfs') {
|
||||
$scheme = FALSE;
|
||||
}
|
||||
return $scheme === FALSE || $this->streamWrapperManager->getViaScheme($scheme) instanceof LocalStream;
|
||||
}
|
||||
|
||||
|
|
|
@ -207,6 +207,9 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
catch (MigrateSkipRowException $e) {
|
||||
$skip = TRUE;
|
||||
$save_to_map = $e->getSaveToMap();
|
||||
if ($message = trim($e->getMessage())) {
|
||||
$this->idMap->saveMessage($row->getSourceIdValues(), $message, MigrationInterface::MESSAGE_INFORMATIONAL);
|
||||
}
|
||||
}
|
||||
|
||||
// We're explicitly skipping this row - keep track in the map table.
|
||||
|
|
|
@ -91,7 +91,7 @@ class Row {
|
|||
* @throws \InvalidArgumentException
|
||||
* Thrown when a source ID property does not exist.
|
||||
*/
|
||||
public function __construct(array $values, array $source_ids, $is_stub = FALSE) {
|
||||
public function __construct(array $values = [], array $source_ids = [], $is_stub = FALSE) {
|
||||
$this->source = $values;
|
||||
$this->sourceIds = $source_ids;
|
||||
$this->isStub = $is_stub;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
name: 'Migrate entity test'
|
||||
type: module
|
||||
description: 'Support module for entity destination test.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_entity_test\Entity;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityBase;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
|
||||
/**
|
||||
* Defines a content entity type that has a string ID.
|
||||
*
|
||||
* @ContentEntityType(
|
||||
* id = "migrate_string_id_entity_test",
|
||||
* label = @Translation("String id entity test"),
|
||||
* base_table = "migrate_entity_test_string_id",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class StringIdEntityTest extends ContentEntityBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
|
||||
return [
|
||||
'id' => BaseFieldDefinition::create('integer')
|
||||
->setSetting('size', 'big')
|
||||
->setLabel('ID'),
|
||||
'version' => BaseFieldDefinition::create('string')
|
||||
->setLabel('Version'),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -18,9 +18,11 @@ function migrate_prepare_row_test_migrate_prepare_row(Row $row, MigrateSourceInt
|
|||
// Test both options for save_to_map.
|
||||
$data = $row->getSourceProperty('data');
|
||||
if ($data == 'skip_and_record') {
|
||||
// Record mapping but don't record a message.
|
||||
throw new MigrateSkipRowException('', TRUE);
|
||||
}
|
||||
elseif ($data == 'skip_and_dont_record') {
|
||||
throw new MigrateSkipRowException('', FALSE);
|
||||
// Don't record mapping but record a message.
|
||||
throw new MigrateSkipRowException('skip_and_dont_record message', FALSE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_prepare_row_test\Plugin\migrate\process;
|
||||
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Provides a testing process plugin that skips rows.
|
||||
*
|
||||
* @MigrateProcessPlugin(
|
||||
* id = "test_skip_row_process"
|
||||
* )
|
||||
*/
|
||||
class TestSkipRowProcess extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
|
||||
// Test both options for save_to_map.
|
||||
$data = $row->getSourceProperty('data');
|
||||
if ($data == 'skip_and_record (use plugin)') {
|
||||
throw new MigrateSkipRowException('', TRUE);
|
||||
}
|
||||
elseif ($data == 'skip_and_dont_record (use plugin)') {
|
||||
throw new MigrateSkipRowException('', FALSE);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,8 @@ namespace Drupal\Tests\migrate\Kernel;
|
|||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate\MigrateMessage;
|
||||
use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
|
@ -123,7 +125,7 @@ class MigrateEntityContentBaseTest extends KernelTestBase {
|
|||
|
||||
// Import some rows.
|
||||
foreach ($destination_rows as $idx => $destination_row) {
|
||||
$row = new Row([], []);
|
||||
$row = new Row();
|
||||
foreach ($destination_row as $key => $value) {
|
||||
$row->setDestinationProperty($key, $value);
|
||||
}
|
||||
|
@ -156,4 +158,50 @@ class MigrateEntityContentBaseTest extends KernelTestBase {
|
|||
$this->assertTranslations(4, 'fr');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests creation of ID columns table with definitions taken from entity type.
|
||||
*/
|
||||
public function testEntityWithStringId() {
|
||||
$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 a SQL exception.
|
||||
['id' => 123456789012, 'version' => 'bar'],
|
||||
],
|
||||
'ids' => [
|
||||
'id' => ['type' => 'integer', 'size' => 'big'],
|
||||
'version' => ['type' => 'string'],
|
||||
],
|
||||
],
|
||||
'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());
|
||||
$result = $executable->import();
|
||||
$this->assertEquals(MigrationInterface::RESULT_COMPLETED, $result);
|
||||
|
||||
/** @var \Drupal\migrate\Plugin\MigrateIdMapInterface $id_map_plugin */
|
||||
$id_map_plugin = $migration->getIdMap();
|
||||
|
||||
// Check that the destination has been stored.
|
||||
$map_row = $id_map_plugin->getRowBySource(['id' => 123, 'version' => 'foo']);
|
||||
$this->assertEquals(123, $map_row['destid1']);
|
||||
$map_row = $id_map_plugin->getRowBySource(['id' => 123456789012, 'version' => 'bar']);
|
||||
$this->assertEquals(123456789012, $map_row['destid1']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -54,14 +54,49 @@ class MigrateSkipRowTest extends KernelTestBase {
|
|||
$result = $executable->import();
|
||||
$this->assertEqual($result, MigrationInterface::RESULT_COMPLETED);
|
||||
|
||||
/** @var \Drupal\migrate\Plugin\MigrateIdMapInterface $id_map_plugin */
|
||||
$id_map_plugin = $migration->getIdMap();
|
||||
// The first row is recorded in the map as ignored.
|
||||
$map_row = $id_map_plugin->getRowBySource(['id' => 1]);
|
||||
$this->assertEqual(MigrateIdMapInterface::STATUS_IGNORED, $map_row['source_row_status']);
|
||||
// Check that no message has been logged for the first exception.
|
||||
$messages = $id_map_plugin->getMessageIterator(['id' => 1])->fetchAll();
|
||||
$this->assertEmpty($messages);
|
||||
|
||||
// The second row is not recorded in the map.
|
||||
$map_row = $id_map_plugin->getRowBySource(['id' => 2]);
|
||||
$this->assertFalse($map_row);
|
||||
// Check that the correct message has been logged for the second exception.
|
||||
$messages = $id_map_plugin->getMessageIterator(['id' => 2])->fetchAll();
|
||||
$this->assertCount(1, $messages);
|
||||
$message = reset($messages);
|
||||
$this->assertEquals('skip_and_dont_record message', $message->message);
|
||||
$this->assertEquals(MigrationInterface::MESSAGE_INFORMATIONAL, $message->level);
|
||||
|
||||
// Insert a custom processor in the process flow.
|
||||
$definition['process']['value'] = [
|
||||
'source' => 'data',
|
||||
'plugin' => 'test_skip_row_process',
|
||||
];
|
||||
// Change data to avoid triggering again hook_migrate_prepare_row().
|
||||
$definition['source']['data_rows'] = [
|
||||
['id' => '1', 'data' => 'skip_and_record (use plugin)'],
|
||||
['id' => '2', 'data' => 'skip_and_dont_record (use plugin)'],
|
||||
];
|
||||
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
|
||||
|
||||
$executable = new MigrateExecutable($migration, new MigrateMessage());
|
||||
$result = $executable->import();
|
||||
$this->assertEquals($result, MigrationInterface::RESULT_COMPLETED);
|
||||
|
||||
$id_map_plugin = $migration->getIdMap();
|
||||
|
||||
// The first row is recorded in the map as ignored.
|
||||
$map_row = $id_map_plugin->getRowBySource(['id' => 1]);
|
||||
$this->assertEquals(MigrateIdMapInterface::STATUS_IGNORED, $map_row['source_row_status']);
|
||||
// The second row is not recorded in the map.
|
||||
$map_row = $id_map_plugin->getRowBySource(['id' => 2]);
|
||||
$this->assertFalse($map_row);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class CopyFileTest extends FileTestBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['system'];
|
||||
public static $modules = ['migrate', 'system'];
|
||||
|
||||
/**
|
||||
* The file system service.
|
||||
|
@ -172,7 +172,7 @@ class CopyFileTest extends FileTestBase {
|
|||
protected function doImport($source_path, $destination_path, $configuration = []) {
|
||||
$plugin = FileCopy::create($this->container, $configuration, 'file_copy', []);
|
||||
$executable = $this->prophesize(MigrateExecutableInterface::class)->reveal();
|
||||
$row = new Row([], []);
|
||||
$row = new Row();
|
||||
|
||||
$result = $plugin->transform([$source_path, $destination_path], $executable, $row, 'foobaz');
|
||||
|
||||
|
|
128
core/modules/migrate/tests/src/Kernel/process/DownloadTest.php
Normal file
128
core/modules/migrate/tests/src/Kernel/process/DownloadTest.php
Normal file
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\migrate\Kernel\process;
|
||||
|
||||
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
|
||||
use Drupal\KernelTests\Core\File\FileTestBase;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\migrate\process\Download;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
|
||||
/**
|
||||
* Tests the download process plugin.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class DownloadTest extends FileTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['system'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->container->get('stream_wrapper_manager')->registerWrapper('temporary', 'Drupal\Core\StreamWrapper\TemporaryStream', StreamWrapperInterface::LOCAL_NORMAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a download that overwrites an existing local file.
|
||||
*/
|
||||
public function testOverwritingDownload() {
|
||||
// Create a pre-existing file at the destination, to test overwrite behavior.
|
||||
$destination_uri = $this->createUri('existing_file.txt');
|
||||
|
||||
// Test destructive download.
|
||||
$actual_destination = $this->doTransform($destination_uri);
|
||||
$this->assertSame($destination_uri, $actual_destination, 'Import returned a destination that was not renamed');
|
||||
$this->assertFileNotExists('public://existing_file_0.txt', 'Import did not rename the file');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a download that renames the downloaded file if there's a collision.
|
||||
*/
|
||||
public function testNonDestructiveDownload() {
|
||||
// Create a pre-existing file at the destination, to test overwrite behavior.
|
||||
$destination_uri = $this->createUri('another_existing_file.txt');
|
||||
|
||||
// Test non-destructive download.
|
||||
$actual_destination = $this->doTransform($destination_uri, ['rename' => TRUE]);
|
||||
$this->assertSame('public://another_existing_file_0.txt', $actual_destination, 'Import returned a renamed destination');
|
||||
$this->assertFileExists($actual_destination, 'Downloaded file was created');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an exception is thrown if the destination URI is not writable.
|
||||
*/
|
||||
public function testWriteProectedDestination() {
|
||||
// Create a pre-existing file at the destination, to test overwrite behavior.
|
||||
$destination_uri = $this->createUri('not-writable.txt');
|
||||
|
||||
// Make the destination non-writable.
|
||||
$this->container
|
||||
->get('file_system')
|
||||
->chmod($destination_uri, 0444);
|
||||
|
||||
// Pass or fail, we'll need to make the file writable again so the test
|
||||
// can clean up after itself.
|
||||
$fix_permissions = function () use ($destination_uri) {
|
||||
$this->container
|
||||
->get('file_system')
|
||||
->chmod($destination_uri, 0755);
|
||||
};
|
||||
|
||||
try {
|
||||
$this->doTransform($destination_uri);
|
||||
$fix_permissions();
|
||||
$this->fail('MigrateException was not thrown for non-writable destination URI.');
|
||||
}
|
||||
catch (MigrateException $e) {
|
||||
$this->assertTrue(TRUE, 'MigrateException was thrown for non-writable destination URI.');
|
||||
$fix_permissions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an input value through the download plugin.
|
||||
*
|
||||
* @param string $destination_uri
|
||||
* The destination URI to download to.
|
||||
* @param array $configuration
|
||||
* (optional) Configuration for the download plugin.
|
||||
*
|
||||
* @return string
|
||||
* The local URI of the downloaded file.
|
||||
*/
|
||||
protected function doTransform($destination_uri, $configuration = []) {
|
||||
// The HTTP client will return a file with contents 'It worked!'
|
||||
$body = fopen('data://text/plain;base64,SXQgd29ya2VkIQ==', 'r');
|
||||
|
||||
// Prepare a mock HTTP client.
|
||||
$this->container->set('http_client', $this->getMock(Client::class));
|
||||
$this->container->get('http_client')
|
||||
->method('get')
|
||||
->willReturn(new Response(200, [], $body));
|
||||
|
||||
// Instantiate the plugin statically so it can pull dependencies out of
|
||||
// the container.
|
||||
$plugin = Download::create($this->container, $configuration, 'download', []);
|
||||
|
||||
// Execute the transformation.
|
||||
$executable = $this->getMock(MigrateExecutableInterface::class);
|
||||
$row = new Row([], []);
|
||||
|
||||
// Return the downloaded file's local URI.
|
||||
$value = [
|
||||
'http://drupal.org/favicon.ico',
|
||||
$destination_uri,
|
||||
];
|
||||
return $plugin->transform($value, $executable, $row, 'foobaz');
|
||||
}
|
||||
|
||||
}
|
111
core/modules/migrate/tests/src/Kernel/process/ExtractTest.php
Normal file
111
core/modules/migrate/tests/src/Kernel/process/ExtractTest.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?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 the extract process plugin.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class ExtractTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['migrate'];
|
||||
|
||||
/**
|
||||
* Returns test migration definition.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDefinition() {
|
||||
return [
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => [],
|
||||
'ids' => [
|
||||
'id' => ['type' => 'string'],
|
||||
],
|
||||
],
|
||||
'process' => [
|
||||
'first' => [
|
||||
'plugin' => 'extract',
|
||||
'index' => [0],
|
||||
'source' => 'simple_array',
|
||||
],
|
||||
'second' => [
|
||||
'plugin' => 'extract',
|
||||
'index' => [1],
|
||||
'source' => 'complex_array',
|
||||
],
|
||||
],
|
||||
'destination' => [
|
||||
'plugin' => 'config',
|
||||
'config_name' => 'migrate_test.settings',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests multiple value handling.
|
||||
*
|
||||
* @dataProvider multipleValueProviderSource
|
||||
*
|
||||
* @param array $source_data
|
||||
* @param array $expected_data
|
||||
*/
|
||||
public function testMultipleValueExplode(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 multiple source data for "extract" process plugin test.
|
||||
*/
|
||||
public function multipleValueProviderSource() {
|
||||
$tests = [
|
||||
[
|
||||
'source_data' => [
|
||||
'id' => '1',
|
||||
'simple_array' => ['alpha', 'beta'],
|
||||
'complex_array' => [['alpha', 'beta'], ['psi', 'omega']],
|
||||
],
|
||||
'expected_data' => [
|
||||
'first' => 'alpha',
|
||||
'second' => ['psi', 'omega'],
|
||||
],
|
||||
],
|
||||
[
|
||||
'source_data' => [
|
||||
'id' => '2',
|
||||
'simple_array' => ['one'],
|
||||
'complex_array' => [0, 1],
|
||||
],
|
||||
'expected_data' => [
|
||||
'first' => 'one',
|
||||
'second' => 1,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
180
core/modules/migrate/tests/src/Kernel/process/FileCopyTest.php
Normal file
180
core/modules/migrate/tests/src/Kernel/process/FileCopyTest.php
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\migrate\Kernel\process;
|
||||
|
||||
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
|
||||
use Drupal\KernelTests\Core\File\FileTestBase;
|
||||
use Drupal\migrate\Plugin\migrate\process\FileCopy;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\Plugin\MigrateProcessInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Tests the file_copy process plugin.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class FileCopyTest extends FileTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['migrate', 'system'];
|
||||
|
||||
/**
|
||||
* The file system service.
|
||||
*
|
||||
* @var \Drupal\Core\File\FileSystemInterface
|
||||
*/
|
||||
protected $fileSystem;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->fileSystem = $this->container->get('file_system');
|
||||
$this->container->get('stream_wrapper_manager')->registerWrapper('temporary', 'Drupal\Core\StreamWrapper\TemporaryStream', StreamWrapperInterface::LOCAL_NORMAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test successful imports/copies.
|
||||
*/
|
||||
public function testSuccessfulCopies() {
|
||||
$file = $this->createUri(NULL, NULL, 'temporary');
|
||||
$file_absolute = $this->fileSystem->realpath($file);
|
||||
$data_sets = [
|
||||
// Test a local to local copy.
|
||||
[
|
||||
$this->root . '/core/modules/simpletest/files/image-test.jpg',
|
||||
'public://file1.jpg'
|
||||
],
|
||||
// Test a temporary file using an absolute path.
|
||||
[
|
||||
$file_absolute,
|
||||
'temporary://test.jpg'
|
||||
],
|
||||
// Test a temporary file using a relative path.
|
||||
[
|
||||
$file_absolute,
|
||||
'temporary://core/modules/simpletest/files/test.jpg'
|
||||
],
|
||||
];
|
||||
foreach ($data_sets as $data) {
|
||||
list($source_path, $destination_path) = $data;
|
||||
$actual_destination = $this->doTransform($source_path, $destination_path);
|
||||
$message = sprintf('File %s exists', $destination_path);
|
||||
$this->assertFileExists($destination_path, $message);
|
||||
// Make sure we didn't accidentally do a move.
|
||||
$this->assertFileExists($source_path, $message);
|
||||
$this->assertSame($actual_destination, $destination_path, 'The import returned the copied filename.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test successful moves.
|
||||
*/
|
||||
public function testSuccessfulMoves() {
|
||||
$file_1 = $this->createUri(NULL, NULL, 'temporary');
|
||||
$file_1_absolute = $this->fileSystem->realpath($file_1);
|
||||
$file_2 = $this->createUri(NULL, NULL, 'temporary');
|
||||
$file_2_absolute = $this->fileSystem->realpath($file_2);
|
||||
$local_file = $this->createUri(NULL, NULL, 'public');
|
||||
$data_sets = [
|
||||
// Test a local to local copy.
|
||||
[
|
||||
$local_file,
|
||||
'public://file1.jpg'
|
||||
],
|
||||
// Test a temporary file using an absolute path.
|
||||
[
|
||||
$file_1_absolute,
|
||||
'temporary://test.jpg'
|
||||
],
|
||||
// Test a temporary file using a relative path.
|
||||
[
|
||||
$file_2_absolute,
|
||||
'temporary://core/modules/simpletest/files/test.jpg'
|
||||
],
|
||||
];
|
||||
foreach ($data_sets as $data) {
|
||||
list($source_path, $destination_path) = $data;
|
||||
$actual_destination = $this->doTransform($source_path, $destination_path, ['move' => TRUE]);
|
||||
$message = sprintf('File %s exists', $destination_path);
|
||||
$this->assertFileExists($destination_path, $message);
|
||||
$message = sprintf('File %s does not exist', $source_path);
|
||||
$this->assertFileNotExists($source_path, $message);
|
||||
$this->assertSame($actual_destination, $destination_path, 'The importer returned the moved filename.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that non-existent files throw an exception.
|
||||
*
|
||||
* @expectedException \Drupal\migrate\MigrateException
|
||||
*
|
||||
* @expectedExceptionMessage File '/non/existent/file' does not exist
|
||||
*/
|
||||
public function testNonExistentSourceFile() {
|
||||
$source = '/non/existent/file';
|
||||
$this->doTransform($source, 'public://wontmatter.jpg');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the 'rename' overwrite mode.
|
||||
*/
|
||||
public function testRenameFile() {
|
||||
$source = $this->createUri(NULL, NULL, 'temporary');
|
||||
$destination = $this->createUri('foo.txt', NULL, 'public');
|
||||
$expected_destination = 'public://foo_0.txt';
|
||||
$actual_destination = $this->doTransform($source, $destination, ['rename' => TRUE]);
|
||||
$this->assertFileExists($expected_destination, 'File was renamed on import');
|
||||
$this->assertSame($actual_destination, $expected_destination, 'The importer returned the renamed filename.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that remote URIs are delegated to the download plugin.
|
||||
*/
|
||||
public function testDownloadRemoteUri() {
|
||||
$download_plugin = $this->getMock(MigrateProcessInterface::class);
|
||||
$download_plugin->expects($this->once())->method('transform');
|
||||
|
||||
$plugin = new FileCopy(
|
||||
[],
|
||||
$this->randomMachineName(),
|
||||
[],
|
||||
$this->container->get('stream_wrapper_manager'),
|
||||
$this->container->get('file_system'),
|
||||
$download_plugin
|
||||
);
|
||||
|
||||
$plugin->transform(
|
||||
['http://drupal.org/favicon.ico', '/destination/path'],
|
||||
$this->getMock(MigrateExecutableInterface::class),
|
||||
new Row([], []),
|
||||
$this->randomMachineName()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do an import using the destination.
|
||||
*
|
||||
* @param string $source_path
|
||||
* Source path to copy from.
|
||||
* @param string $destination_path
|
||||
* The destination path to copy to.
|
||||
* @param array $configuration
|
||||
* Process plugin configuration settings.
|
||||
*
|
||||
* @return string
|
||||
* The URI of the copied file.
|
||||
*/
|
||||
protected function doTransform($source_path, $destination_path, $configuration = []) {
|
||||
$plugin = FileCopy::create($this->container, $configuration, 'file_copy', []);
|
||||
$executable = $this->prophesize(MigrateExecutableInterface::class)->reveal();
|
||||
$row = new Row([], []);
|
||||
|
||||
return $plugin->transform([$source_path, $destination_path], $executable, $row, 'foobaz');
|
||||
}
|
||||
|
||||
}
|
|
@ -398,7 +398,7 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
->method('getProcessPlugins')
|
||||
->with(NULL)
|
||||
->will($this->returnValue($plugins));
|
||||
$row = new Row(array(), array());
|
||||
$row = new Row();
|
||||
$this->executable->processRow($row);
|
||||
foreach ($expected as $key => $value) {
|
||||
$this->assertSame($row->getDestinationProperty($key), $value);
|
||||
|
@ -414,7 +414,7 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
->method('getProcessPlugins')
|
||||
->with(NULL)
|
||||
->will($this->returnValue(array('test' => array())));
|
||||
$row = new Row(array(), array());
|
||||
$row = new Row();
|
||||
$this->executable->processRow($row);
|
||||
$this->assertSame($row->getDestination(), array());
|
||||
}
|
||||
|
|
|
@ -286,7 +286,7 @@ class MigrateSourceTest extends MigrateTestCase {
|
|||
// Get a new migration with an id.
|
||||
$migration = $this->getMigration();
|
||||
$source = new StubSourcePlugin([], '', [], $migration);
|
||||
$row = new Row([], []);
|
||||
$row = new Row();
|
||||
|
||||
$module_handler = $this->prophesize(ModuleHandlerInterface::class);
|
||||
$module_handler->invokeAll('migrate_prepare_row', [$row, $source, $migration])
|
||||
|
@ -328,7 +328,7 @@ class MigrateSourceTest extends MigrateTestCase {
|
|||
|
||||
$migration = $this->getMigration();
|
||||
$source = new StubSourcePlugin([], '', [], $migration);
|
||||
$row = new Row([], []);
|
||||
$row = new Row();
|
||||
|
||||
$module_handler = $this->prophesize(ModuleHandlerInterface::class);
|
||||
// Return a failure from a prepare row hook.
|
||||
|
@ -357,7 +357,7 @@ class MigrateSourceTest extends MigrateTestCase {
|
|||
|
||||
$migration = $this->getMigration();
|
||||
$source = new StubSourcePlugin([], '', [], $migration);
|
||||
$row = new Row([], []);
|
||||
$row = new Row();
|
||||
|
||||
$module_handler = $this->prophesize(ModuleHandlerInterface::class);
|
||||
// Return a failure from a prepare row hook.
|
||||
|
@ -386,7 +386,7 @@ class MigrateSourceTest extends MigrateTestCase {
|
|||
|
||||
$migration = $this->getMigration();
|
||||
$source = new StubSourcePlugin([], '', [], $migration);
|
||||
$row = new Row([], []);
|
||||
$row = new Row();
|
||||
|
||||
$module_handler = $this->prophesize(ModuleHandlerInterface::class);
|
||||
// Return a failure from a prepare row hook.
|
||||
|
|
|
@ -147,7 +147,7 @@ abstract class MigrateSqlSourceTestCase extends MigrateTestCase {
|
|||
public function testSourceCount() {
|
||||
$count = $this->source->count();
|
||||
$this->assertTrue(is_numeric($count));
|
||||
$this->assertEquals($count, $this->expectedCount);
|
||||
$this->assertEquals($this->expectedCount, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ use Drupal\Core\Entity\ContentEntityInterface;
|
|||
use Drupal\Core\Entity\ContentEntityType;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Field\FieldTypePluginManagerInterface;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
|
||||
|
@ -74,7 +75,7 @@ class EntityContentBaseTest extends UnitTestCase {
|
|||
->willReturn(5);
|
||||
$destination->setEntity($entity->reveal());
|
||||
// Ensure the id is saved entity id is returned from import.
|
||||
$this->assertEquals([5], $destination->import(new Row([], [])));
|
||||
$this->assertEquals([5], $destination->import(new Row()));
|
||||
// Assert that import set the rollback action.
|
||||
$this->assertEquals(MigrateIdMapInterface::ROLLBACK_DELETE, $destination->rollbackAction());
|
||||
}
|
||||
|
@ -95,7 +96,7 @@ class EntityContentBaseTest extends UnitTestCase {
|
|||
$this->entityManager->reveal(),
|
||||
$this->prophesize(FieldTypePluginManagerInterface::class)->reveal());
|
||||
$destination->setEntity(FALSE);
|
||||
$destination->import(new Row([], []));
|
||||
$destination->import(new Row());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,6 +110,8 @@ class EntityContentBaseTest extends UnitTestCase {
|
|||
$entity_type = $this->prophesize(ContentEntityType::class);
|
||||
$entity_type->getKey('langcode')->willReturn('');
|
||||
$entity_type->getKey('id')->willReturn('id');
|
||||
$this->entityManager->getBaseFieldDefinitions('foo')
|
||||
->willReturn(['id' => BaseFieldDefinitionTest::create('integer')]);
|
||||
|
||||
$this->storage->getEntityType()->willReturn($entity_type->reveal());
|
||||
|
||||
|
@ -144,4 +147,27 @@ class EntityTestDestination extends EntityContentBase {
|
|||
return $this->entity;
|
||||
}
|
||||
|
||||
public static function getEntityTypeId($plugin_id) {
|
||||
return 'foo';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub class for BaseFieldDefinition.
|
||||
*/
|
||||
class BaseFieldDefinitionTest extends BaseFieldDefinition {
|
||||
|
||||
public static function create($type) {
|
||||
return new static([]);
|
||||
}
|
||||
|
||||
public function getSettings() {
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getType() {
|
||||
return 'integer';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ class RowTest extends UnitTestCase {
|
|||
* Tests object creation: empty.
|
||||
*/
|
||||
public function testRowWithoutData() {
|
||||
$row = new Row(array(), array());
|
||||
$row = new Row();
|
||||
$this->assertSame(array(), $row->getSource(), 'Empty row');
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ class EntityRevisionTest extends UnitTestCase {
|
|||
$this->storage->loadRevision(12)
|
||||
->shouldBeCalled()
|
||||
->willReturn($entity->reveal());
|
||||
$row = new Row([], []);
|
||||
$row = new Row();
|
||||
$this->assertEquals($entity->reveal(), $destination->getEntity($row, [12, 13]));
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ class PerComponentEntityDisplayTest extends MigrateTestCase {
|
|||
'field_name' => 'field_name_test',
|
||||
'options' => array('test setting'),
|
||||
);
|
||||
$row = new Row(array(), array());
|
||||
$row = new Row();
|
||||
foreach ($values as $key => $value) {
|
||||
$row->setDestinationProperty($key, $value);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class PerComponentEntityFormDisplayTest extends MigrateTestCase {
|
|||
'field_name' => 'field_name_test',
|
||||
'options' => array('test setting'),
|
||||
);
|
||||
$row = new Row(array(), array());
|
||||
$row = new Row();
|
||||
foreach ($values as $key => $value) {
|
||||
$row->setDestinationProperty($key, $value);
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ class IteratorTest extends MigrateTestCase {
|
|||
),
|
||||
);
|
||||
// This is not used but the interface requires it, so create an empty row.
|
||||
$row = new Row(array(), array());
|
||||
$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
|
||||
|
|
|
@ -57,7 +57,7 @@ class UrlEncodeTest extends MigrateTestCase {
|
|||
*/
|
||||
protected function doTransform($value) {
|
||||
$executable = new MigrateExecutable($this->getMigration(), new MigrateMessage());
|
||||
$row = new Row([], []);
|
||||
$row = new Row();
|
||||
|
||||
return (new UrlEncode([], 'urlencode', []))
|
||||
->transform($value, $executable, $row, 'foobaz');
|
||||
|
|
Reference in a new issue