Update to Drupal 8.0.0-beta15. For more information, see: https://www.drupal.org/node/2563023
This commit is contained in:
parent
2720a9ec4b
commit
f3791f1da3
1898 changed files with 54300 additions and 11481 deletions
|
@ -27,7 +27,3 @@ migrate_source_sql:
|
|||
target:
|
||||
type: string
|
||||
label: 'The migration database target'
|
||||
|
||||
migrate_load:
|
||||
type: migrate_plugin
|
||||
label: 'Load'
|
||||
|
|
|
@ -16,19 +16,3 @@ migrate.destination.config:
|
|||
config_name:
|
||||
type: string
|
||||
label: 'Configuration name'
|
||||
|
||||
migrate.destination.entity:user:
|
||||
type: migrate_destination
|
||||
label: 'User'
|
||||
mapping:
|
||||
md5_passwords:
|
||||
type: boolean
|
||||
label: 'Passwords'
|
||||
|
||||
migrate.destination.entity:file:
|
||||
type: migrate_destination
|
||||
label: 'Picture'
|
||||
mapping:
|
||||
source_path_property:
|
||||
type: string
|
||||
label: 'Source path'
|
||||
|
|
|
@ -16,9 +16,6 @@ migrate.migration.*:
|
|||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
load:
|
||||
type: migrate.load.[plugin]
|
||||
label: 'Source'
|
||||
source:
|
||||
type: migrate.source.[plugin]
|
||||
label: 'Source'
|
||||
|
@ -28,6 +25,9 @@ migrate.migration.*:
|
|||
destination:
|
||||
type: migrate.destination.[plugin]
|
||||
label: 'Destination'
|
||||
template:
|
||||
type: string
|
||||
label: 'Template'
|
||||
migration_dependencies:
|
||||
type: mapping
|
||||
label: 'Dependencies'
|
||||
|
|
|
@ -11,3 +11,24 @@ migrate.source.empty:
|
|||
provider:
|
||||
type: string
|
||||
label: 'Provider'
|
||||
|
||||
migrate.source.embedded_data:
|
||||
type: migrate_source
|
||||
label: 'Embedded data source'
|
||||
mapping:
|
||||
data_rows:
|
||||
type: sequence
|
||||
label: 'Data rows'
|
||||
sequence:
|
||||
type: ignore
|
||||
label: 'Data row'
|
||||
ids:
|
||||
type: sequence
|
||||
label: 'Unique key'
|
||||
sequence:
|
||||
type: mapping
|
||||
label: 'Key column'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Column type'
|
||||
|
|
|
@ -98,6 +98,8 @@ use Drupal\migrate\Row;
|
|||
* - d6_custom_block
|
||||
* - d6_block
|
||||
* @endcode
|
||||
*
|
||||
* @see update_api
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
name: Migrate
|
||||
type: module
|
||||
description: 'Handles migrations'
|
||||
package: Core
|
||||
package: Core (Experimental)
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
;configure: admin/structure/migrate
|
||||
|
|
27
core/modules/migrate/migrate.install
Normal file
27
core/modules/migrate/migrate.install
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains install and update functions for Migrate.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup updates-8.0.0-beta
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Remove load plugin references from existing migrations.
|
||||
*/
|
||||
function migrate_update_8001() {
|
||||
$config_factory = \Drupal::configFactory();
|
||||
foreach ($config_factory->listAll('migrate.migration.') as $migration_config_name) {
|
||||
$migration = $config_factory->getEditable($migration_config_name);
|
||||
$migration->clear('load');
|
||||
$migration->save(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup updates-8.0.0-beta".
|
||||
*/
|
|
@ -8,6 +8,9 @@ services:
|
|||
migrate.template_storage:
|
||||
class: Drupal\migrate\MigrateTemplateStorage
|
||||
arguments: ['@module_handler']
|
||||
migrate.migration_builder:
|
||||
class: Drupal\migrate\MigrationBuilder
|
||||
arguments: ['@plugin.manager.migrate.builder']
|
||||
plugin.manager.migrate.source:
|
||||
class: Drupal\migrate\Plugin\MigratePluginManager
|
||||
arguments: [source, '@container.namespaces', '@cache.discovery', '@module_handler', 'Drupal\migrate\Annotation\MigrateSource']
|
||||
|
@ -20,6 +23,6 @@ services:
|
|||
plugin.manager.migrate.id_map:
|
||||
class: Drupal\migrate\Plugin\MigratePluginManager
|
||||
arguments: [id_map, '@container.namespaces', '@cache.discovery', '@module_handler']
|
||||
password_migrate:
|
||||
class: Drupal\migrate\MigratePassword
|
||||
arguments: ['@password_original']
|
||||
plugin.manager.migrate.builder:
|
||||
class: Drupal\migrate\Plugin\MigratePluginManager
|
||||
arguments: [builder, '@container.namespaces', '@cache.discovery', '@module_handler']
|
||||
|
|
|
@ -24,7 +24,6 @@ use Drupal\Component\Utility\NestedArray;
|
|||
* @ConfigEntityType(
|
||||
* id = "migration",
|
||||
* label = @Translation("Migration"),
|
||||
* module = "migrate",
|
||||
* handlers = {
|
||||
* "storage" = "Drupal\migrate\MigrationStorage"
|
||||
* },
|
||||
|
@ -232,6 +231,13 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
|
|||
*/
|
||||
protected $dependencies = [];
|
||||
|
||||
/**
|
||||
* The ID of the template from which this migration was derived, if any.
|
||||
*
|
||||
* @var string|NULL
|
||||
*/
|
||||
protected $template;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
|
@ -239,6 +245,19 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
|
|||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Labels corresponding to each defined status.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $statusLabels = [
|
||||
self::STATUS_IDLE => 'Idle',
|
||||
self::STATUS_IMPORTING => 'Importing',
|
||||
self::STATUS_ROLLING_BACK => 'Rolling back',
|
||||
self::STATUS_STOPPING => 'Stopping',
|
||||
self::STATUS_DISABLED => 'Disabled',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -397,20 +416,53 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
|
|||
return $this->entityManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setStatus($status) {
|
||||
\Drupal::keyValue('migrate_status')->set($this->id(), $status);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStatus() {
|
||||
return \Drupal::keyValue('migrate_status')->get($this->id(), static::STATUS_IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStatusLabel() {
|
||||
$status = $this->getStatus();
|
||||
if (isset($this->statusLabels[$status])) {
|
||||
return $this->statusLabels[$status];
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMigrationResult($result) {
|
||||
$migrate_result_store = \Drupal::keyValue('migrate_result');
|
||||
$migrate_result_store->set($this->id(), $result);
|
||||
\Drupal::keyValue('migrate_result')->set($this->id(), $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMigrationResult() {
|
||||
$migrate_result_store = \Drupal::keyValue('migrate_result');
|
||||
return $migrate_result_store->get($this->id(), static::RESULT_INCOMPLETE);
|
||||
return \Drupal::keyValue('migrate_result')->get($this->id(), static::RESULT_INCOMPLETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function interruptMigration($result) {
|
||||
$this->setStatus(MigrationInterface::STATUS_STOPPING);
|
||||
$this->setMigrationResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -428,6 +480,10 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
|
|||
// Invalidate the source plugin.
|
||||
unset($this->sourcePlugin);
|
||||
}
|
||||
elseif ($property_name === 'destination') {
|
||||
// Invalidate the destination plugin.
|
||||
unset($this->destinationPlugin);
|
||||
}
|
||||
return parent::set($property_name, $value);
|
||||
}
|
||||
|
||||
|
|
|
@ -166,6 +166,30 @@ interface MigrationInterface extends ConfigEntityInterface {
|
|||
*/
|
||||
public function isComplete();
|
||||
|
||||
/**
|
||||
* Set the current migration status.
|
||||
*
|
||||
* @param int $result
|
||||
* One of the STATUS_* constants.
|
||||
*/
|
||||
public function setStatus($status);
|
||||
|
||||
/**
|
||||
* Get the current migration status.
|
||||
*
|
||||
* @return int
|
||||
* The current migration status. Defaults to STATUS_IDLE.
|
||||
*/
|
||||
public function getStatus();
|
||||
|
||||
/**
|
||||
* Retrieve a label for the current status.
|
||||
*
|
||||
* @return string
|
||||
* User-friendly string corresponding to a STATUS_ constant.
|
||||
*/
|
||||
public function getStatusLabel();
|
||||
|
||||
/**
|
||||
* Set the migration result.
|
||||
*
|
||||
|
@ -182,6 +206,15 @@ interface MigrationInterface extends ConfigEntityInterface {
|
|||
*/
|
||||
public function getMigrationResult();
|
||||
|
||||
/**
|
||||
* Signal that the migration should be interrupted with the specified result
|
||||
* code.
|
||||
*
|
||||
* @param int $result
|
||||
* One of the MigrationInterface::RESULT_* constants.
|
||||
*/
|
||||
public function interruptMigration($result);
|
||||
|
||||
/**
|
||||
* Get the normalized process pipeline configuration describing the process
|
||||
* plugins.
|
||||
|
|
111
core/modules/migrate/src/Event/MigrateEvents.php
Normal file
111
core/modules/migrate/src/Event/MigrateEvents.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains Drupal\migrate\Event\MigrateEvents.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Event;
|
||||
|
||||
/**
|
||||
* Defines events for the migration system.
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigrateMapSaveEvent
|
||||
* @see \Drupal\migrate\Event\MigrateMapDeleteEvent
|
||||
* @see \Drupal\migrate\Event\MigrateImportEvent
|
||||
* @see \Drupal\migrate\Event\MigratePreRowSaveEvent
|
||||
* @see \Drupal\migrate\Event\MigratePostRowSaveEvent
|
||||
*/
|
||||
final class MigrateEvents {
|
||||
|
||||
/**
|
||||
* Name of the event fired when saving to a migration's map.
|
||||
*
|
||||
* This event allows modules to perform an action whenever the disposition of
|
||||
* an item being migrated is saved to the map table. The event listener method
|
||||
* receives a \Drupal\migrate\Event\MigrateMapSaveEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigrateMapSaveEvent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const MAP_SAVE = 'migrate.map_save';
|
||||
|
||||
/**
|
||||
* Name of the event fired when removing an entry from a migration's map.
|
||||
*
|
||||
* This event allows modules to perform an action whenever a row is deleted
|
||||
* from a migration's map table (implying it has been rolled back). The event
|
||||
* listener method receives a \Drupal\migrate\Event\MigrateMapDeleteEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigrateMapDeleteEvent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const MAP_DELETE = 'migrate.map_delete';
|
||||
|
||||
/**
|
||||
* Name of the event fired when beginning a migration import operation.
|
||||
*
|
||||
* This event allows modules to perform an action whenever a migration import
|
||||
* operation is about to begin. The event listener method receives a
|
||||
* \Drupal\migrate\Event\MigrateImportEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigrateImportEvent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PRE_IMPORT = 'migrate.pre_import';
|
||||
|
||||
/**
|
||||
* Name of the event fired when finishing a migration import operation.
|
||||
*
|
||||
* This event allows modules to perform an action whenever a migration import
|
||||
* operation is completing. The event listener method receives a
|
||||
* \Drupal\migrate\Event\MigrateImportEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigrateImportEvent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const POST_IMPORT = 'migrate.post_import';
|
||||
|
||||
/**
|
||||
* Name of the event fired when about to import a single item.
|
||||
*
|
||||
* This event allows modules to perform an action whenever a specific item
|
||||
* is about to be saved by the destination plugin. The event listener method
|
||||
* receives a \Drupal\migrate\Event\MigratePreSaveEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigratePreRowSaveEvent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PRE_ROW_SAVE = 'migrate.pre_row_save';
|
||||
|
||||
/**
|
||||
* Name of the event fired just after a single item has been imported.
|
||||
*
|
||||
* This event allows modules to perform an action whenever a specific item
|
||||
* has been saved by the destination plugin. The event listener method
|
||||
* receives a \Drupal\migrate\Event\MigratePostRowSaveEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigratePostRowSaveEvent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const POST_ROW_SAVE = 'migrate.post_row_save';
|
||||
|
||||
}
|
45
core/modules/migrate/src/Event/MigrateImportEvent.php
Normal file
45
core/modules/migrate/src/Event/MigrateImportEvent.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Event\MigrateImportEvent.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Event;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Wraps a pre- or post-import event for event listeners.
|
||||
*/
|
||||
class MigrateImportEvent extends Event {
|
||||
|
||||
/**
|
||||
* Migration entity.
|
||||
*
|
||||
* @var \Drupal\migrate\Entity\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* Constructs an import event object.
|
||||
*
|
||||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* Migration entity.
|
||||
*/
|
||||
public function __construct(MigrationInterface $migration) {
|
||||
$this->migration = $migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the migration entity.
|
||||
*
|
||||
* @return \Drupal\migrate\Entity\MigrationInterface
|
||||
* The migration entity involved.
|
||||
*/
|
||||
public function getMigration() {
|
||||
return $this->migration;
|
||||
}
|
||||
|
||||
}
|
65
core/modules/migrate/src/Event/MigrateMapDeleteEvent.php
Normal file
65
core/modules/migrate/src/Event/MigrateMapDeleteEvent.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Event\MigrateMapDeleteEvent.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Event;
|
||||
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Wraps a migrate map delete event for event listeners.
|
||||
*/
|
||||
class MigrateMapDeleteEvent extends Event {
|
||||
|
||||
/**
|
||||
* Map plugin.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigrateIdMapInterface
|
||||
*/
|
||||
protected $map;
|
||||
|
||||
/**
|
||||
* Array of source ID fields.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $sourceId;
|
||||
|
||||
/**
|
||||
* Constructs a migration map delete event object.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigrateIdMapInterface $map
|
||||
* Map plugin.
|
||||
* @param array $source_id
|
||||
* Array of source ID fields representing the object being deleted from the map.
|
||||
*/
|
||||
public function __construct(MigrateIdMapInterface $map, array $source_id) {
|
||||
$this->map = $map;
|
||||
$this->sourceId = $source_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the map plugin.
|
||||
*
|
||||
* @return \Drupal\migrate\Plugin\MigrateIdMapInterface
|
||||
* The map plugin that caused the event to fire.
|
||||
*/
|
||||
public function getMap() {
|
||||
return $this->map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source ID of the item being removed from the map.
|
||||
*
|
||||
* @return array
|
||||
* Array of source ID fields.
|
||||
*/
|
||||
public function getSourceId() {
|
||||
return $this->sourceId;
|
||||
}
|
||||
|
||||
}
|
65
core/modules/migrate/src/Event/MigrateMapSaveEvent.php
Normal file
65
core/modules/migrate/src/Event/MigrateMapSaveEvent.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Event\MigrateMapSaveEvent.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Event;
|
||||
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Wraps a migrate map save event for event listeners.
|
||||
*/
|
||||
class MigrateMapSaveEvent extends Event {
|
||||
|
||||
/**
|
||||
* Map plugin.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigrateIdMapInterface
|
||||
*/
|
||||
protected $map;
|
||||
|
||||
/**
|
||||
* Array of fields being saved to the map, keyed by field name.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fields;
|
||||
|
||||
/**
|
||||
* Constructs a migration map event object.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigrateIdMapInterface $map
|
||||
* Map plugin.
|
||||
* @param array $fields
|
||||
* Array of fields being saved to the map.
|
||||
*/
|
||||
public function __construct(MigrateIdMapInterface $map, array $fields) {
|
||||
$this->map = $map;
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the map plugin.
|
||||
*
|
||||
* @return \Drupal\migrate\Plugin\MigrateIdMapInterface
|
||||
* The map plugin that caused the event to fire.
|
||||
*/
|
||||
public function getMap() {
|
||||
return $this->map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fields about to be saved to the map.
|
||||
*
|
||||
* @return array
|
||||
* Array of map fields, keyed by field name.
|
||||
*/
|
||||
public function getFields() {
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
}
|
43
core/modules/migrate/src/Event/MigratePostRowSaveEvent.php
Normal file
43
core/modules/migrate/src/Event/MigratePostRowSaveEvent.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Event\MigratePostRowSaveEvent.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Event;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Wraps a post-save event for event listeners.
|
||||
*/
|
||||
class MigratePostRowSaveEvent extends MigratePreRowSaveEvent {
|
||||
|
||||
/**
|
||||
* Constructs a post-save event object.
|
||||
*
|
||||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* Migration entity.
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* Row object.
|
||||
* @param array|bool $destination_id_values
|
||||
* Values represent the destination ID.
|
||||
*/
|
||||
public function __construct(MigrationInterface $migration, Row $row, $destination_id_values) {
|
||||
parent::__construct($migration, $row);
|
||||
$this->destinationIdValues = $destination_id_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the destination ID values.
|
||||
*
|
||||
* @return array
|
||||
* The destination ID as an array.
|
||||
*/
|
||||
public function getDestinationIdValues() {
|
||||
return $this->destinationIdValues;
|
||||
}
|
||||
|
||||
}
|
64
core/modules/migrate/src/Event/MigratePreRowSaveEvent.php
Normal file
64
core/modules/migrate/src/Event/MigratePreRowSaveEvent.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Event\MigratePreSaveEvent.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Event;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Wraps a pre-save event for event listeners.
|
||||
*/
|
||||
class MigratePreRowSaveEvent extends Event {
|
||||
|
||||
/**
|
||||
* Row object.
|
||||
*
|
||||
* @var \Drupal\migrate\Row
|
||||
*/
|
||||
protected $row;
|
||||
|
||||
/**
|
||||
* Migration entity.
|
||||
*
|
||||
* @var \Drupal\migrate\Entity\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* Constructs a pre-save event object.
|
||||
*
|
||||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* Migration entity.
|
||||
*/
|
||||
public function __construct(MigrationInterface $migration, Row $row) {
|
||||
$this->migration = $migration;
|
||||
$this->row = $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the migration entity.
|
||||
*
|
||||
* @return \Drupal\migrate\Entity\MigrationInterface
|
||||
* The migration entity being imported.
|
||||
*/
|
||||
public function getMigration() {
|
||||
return $this->migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the row object.
|
||||
*
|
||||
* @return \Drupal\migrate\Row
|
||||
* The row object about to be imported.
|
||||
*/
|
||||
public function getRow() {
|
||||
return $this->row;
|
||||
}
|
||||
|
||||
}
|
|
@ -10,8 +10,13 @@ namespace Drupal\migrate;
|
|||
use Drupal\Core\Utility\Error;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Event\MigrateEvents;
|
||||
use Drupal\migrate\Event\MigrateImportEvent;
|
||||
use Drupal\migrate\Event\MigratePostRowSaveEvent;
|
||||
use Drupal\migrate\Event\MigratePreRowSaveEvent;
|
||||
use Drupal\migrate\Exception\RequirementsException;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* Defines a migrate executable class.
|
||||
|
@ -26,20 +31,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* The number of successfully imported rows since feedback was given.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $successesSinceFeedback;
|
||||
|
||||
/**
|
||||
* The number of rows that were successfully processed.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $totalSuccesses;
|
||||
|
||||
/**
|
||||
* Status of one row.
|
||||
*
|
||||
|
@ -50,15 +41,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
*/
|
||||
protected $sourceRowStatus;
|
||||
|
||||
/**
|
||||
* The number of rows processed.
|
||||
*
|
||||
* The total attempted, whether or not they were successful.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $totalProcessed;
|
||||
|
||||
/**
|
||||
* The queued messages not yet saved.
|
||||
*
|
||||
|
@ -70,23 +52,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
*/
|
||||
protected $queuedMessages = array();
|
||||
|
||||
/**
|
||||
* The options that can be set when executing the migration.
|
||||
*
|
||||
* Values can be set for:
|
||||
* - 'limit': Sets a time limit.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* The PHP max_execution_time.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $maxExecTime;
|
||||
|
||||
/**
|
||||
* The ratio of the memory limit at which an operation will be interrupted.
|
||||
*
|
||||
|
@ -95,18 +60,11 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
protected $memoryThreshold = 0.85;
|
||||
|
||||
/**
|
||||
* The ratio of the time limit at which an operation will be interrupted.
|
||||
* The PHP memory_limit expressed in bytes.
|
||||
*
|
||||
* @var float
|
||||
* @var int
|
||||
*/
|
||||
public $timeThreshold = 0.90;
|
||||
|
||||
/**
|
||||
* The time limit when executing the migration.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $limit = array();
|
||||
protected $memoryLimit;
|
||||
|
||||
/**
|
||||
* The configuration values of the source.
|
||||
|
@ -115,20 +73,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
*/
|
||||
protected $sourceIdValues;
|
||||
|
||||
/**
|
||||
* The number of rows processed since feedback was given.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $processedSinceFeedback = 0;
|
||||
|
||||
/**
|
||||
* The PHP memory_limit expressed in bytes.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $memoryLimit;
|
||||
|
||||
/**
|
||||
* The rollback action to be saved for the current row.
|
||||
*
|
||||
|
@ -173,6 +117,13 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
*/
|
||||
protected $sourceValues;
|
||||
|
||||
/**
|
||||
* The event dispatcher.
|
||||
*
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
protected $eventDispatcher;
|
||||
|
||||
/**
|
||||
* Constructs a MigrateExecutable and verifies and sets the memory limit.
|
||||
*
|
||||
|
@ -180,13 +131,16 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
* The migration to run.
|
||||
* @param \Drupal\migrate\MigrateMessageInterface $message
|
||||
* The message to record.
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
|
||||
* The event dispatcher.
|
||||
*
|
||||
* @throws \Drupal\migrate\MigrateException
|
||||
*/
|
||||
public function __construct(MigrationInterface $migration, MigrateMessageInterface $message) {
|
||||
public function __construct(MigrationInterface $migration, MigrateMessageInterface $message, EventDispatcherInterface $event_dispatcher = NULL) {
|
||||
$this->migration = $migration;
|
||||
$this->message = $message;
|
||||
$this->migration->getIdMap()->setMessage($message);
|
||||
$this->eventDispatcher = $event_dispatcher;
|
||||
// Record the memory limit in bytes
|
||||
$limit = trim(ini_get('memory_limit'));
|
||||
if ($limit == '-1') {
|
||||
|
@ -204,14 +158,13 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
$limit *= 1024;
|
||||
break;
|
||||
default:
|
||||
throw new MigrateException($this->t('Invalid PHP memory_limit !limit',
|
||||
$limit = PHP_INT_MAX;
|
||||
$this->message->display($this->t('Invalid PHP memory_limit !limit, setting to unlimited.',
|
||||
array('!limit' => $limit)));
|
||||
}
|
||||
}
|
||||
$this->memoryLimit = $limit;
|
||||
}
|
||||
// Record the maximum execution time limit.
|
||||
$this->maxExecTime = ini_get('max_execution_time');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -233,10 +186,33 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
return $this->source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the event dispatcher.
|
||||
*
|
||||
* @return \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
protected function getEventDispatcher() {
|
||||
if (!$this->eventDispatcher) {
|
||||
$this->eventDispatcher = \Drupal::service('event_dispatcher');
|
||||
}
|
||||
return $this->eventDispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import() {
|
||||
// Only begin the import operation if the migration is currently idle.
|
||||
if ($this->migration->getStatus() !== MigrationInterface::STATUS_IDLE) {
|
||||
$this->message->display($this->t('Migration @id is busy with another operation: @status',
|
||||
array(
|
||||
'@id' => $this->migration->id(),
|
||||
'@status' => $this->t($this->migration->getStatusLabel()),
|
||||
)), 'error');
|
||||
return MigrationInterface::RESULT_FAILED;
|
||||
}
|
||||
$this->getEventDispatcher()->dispatch(MigrateEvents::PRE_IMPORT, new MigrateImportEvent($this->migration));
|
||||
|
||||
// Knock off migration if the requirements haven't been met.
|
||||
try {
|
||||
$this->migration->checkRequirements();
|
||||
|
@ -251,6 +227,7 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
return MigrationInterface::RESULT_FAILED;
|
||||
}
|
||||
|
||||
$this->migration->setStatus(MigrationInterface::STATUS_IMPORTING);
|
||||
$return = MigrationInterface::RESULT_COMPLETED;
|
||||
$source = $this->getSource();
|
||||
$id_map = $this->migration->getIdMap();
|
||||
|
@ -261,6 +238,7 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
catch (\Exception $e) {
|
||||
$this->message->display(
|
||||
$this->t('Migration failed with source plugin exception: !e', array('!e' => $e->getMessage())), 'error');
|
||||
$this->migration->setStatus(MigrationInterface::STATUS_IDLE);
|
||||
return MigrationInterface::RESULT_FAILED;
|
||||
}
|
||||
|
||||
|
@ -284,14 +262,14 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
|
||||
if ($save) {
|
||||
try {
|
||||
$this->getEventDispatcher()->dispatch(MigrateEvents::PRE_ROW_SAVE, new MigratePreRowSaveEvent($this->migration, $row));
|
||||
$destination_id_values = $destination->import($row, $id_map->lookupDestinationId($this->sourceIdValues));
|
||||
$this->getEventDispatcher()->dispatch(MigrateEvents::POST_ROW_SAVE, new MigratePostRowSaveEvent($this->migration, $row, $destination_id_values));
|
||||
if ($destination_id_values) {
|
||||
// We do not save an idMap entry for config.
|
||||
if ($destination_id_values !== TRUE) {
|
||||
$id_map->saveIdMapping($row, $destination_id_values, $this->sourceRowStatus, $this->rollbackAction);
|
||||
}
|
||||
$this->successesSinceFeedback++;
|
||||
$this->totalSuccesses++;
|
||||
}
|
||||
else {
|
||||
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_FAILED, $this->rollbackAction);
|
||||
|
@ -312,8 +290,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
$this->handleException($e);
|
||||
}
|
||||
}
|
||||
$this->totalProcessed++;
|
||||
$this->processedSinceFeedback++;
|
||||
if ($high_water_property = $this->migration->get('highWaterProperty')) {
|
||||
$this->migration->saveHighWater($row->getSourceProperty($high_water_property['name']));
|
||||
}
|
||||
|
@ -322,12 +298,17 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
unset($sourceValues, $destinationValues);
|
||||
$this->sourceRowStatus = MigrateIdMapInterface::STATUS_IMPORTED;
|
||||
|
||||
// Check for memory exhaustion.
|
||||
if (($return = $this->checkStatus()) != MigrationInterface::RESULT_COMPLETED) {
|
||||
break;
|
||||
}
|
||||
if ($this->timeOptionExceeded()) {
|
||||
|
||||
// If anyone has requested we stop, return the requested result.
|
||||
if ($this->migration->getStatus() == MigrationInterface::STATUS_STOPPING) {
|
||||
$return = $this->migration->getMigrationResult();
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
$source->next();
|
||||
}
|
||||
|
@ -335,16 +316,14 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
$this->message->display(
|
||||
$this->t('Migration failed with source plugin exception: !e',
|
||||
array('!e' => $e->getMessage())), 'error');
|
||||
$this->migration->setStatus(MigrationInterface::STATUS_IDLE);
|
||||
return MigrationInterface::RESULT_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO uncomment this
|
||||
*/
|
||||
#$this->progressMessage($return);
|
||||
|
||||
$this->migration->setMigrationResult($return);
|
||||
$this->getEventDispatcher()->dispatch(MigrateEvents::POST_IMPORT, new MigrateImportEvent($this->migration));
|
||||
$this->migration->setStatus(MigrationInterface::STATUS_IDLE);
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
@ -409,40 +388,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
return $this->getSource()->getCurrentIds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether we've exceeded the designated time limit.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the threshold is exceeded, FALSE if not.
|
||||
*/
|
||||
protected function timeOptionExceeded() {
|
||||
// If there is no time limit, then it is not exceeded.
|
||||
if (!$time_limit = $this->getTimeLimit()) {
|
||||
return FALSE;
|
||||
}
|
||||
// Calculate if the time limit is exceeded.
|
||||
$time_elapsed = $this->getTimeElapsed();
|
||||
if ($time_elapsed >= $time_limit) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTimeLimit() {
|
||||
$limit = $this->limit;
|
||||
if (isset($limit['unit']) && isset($limit['value']) && ($limit['unit'] == 'seconds' || $limit['unit'] == 'second')) {
|
||||
return $limit['value'];
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -468,34 +413,32 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks for exceptional conditions, and display feedback.
|
||||
* Takes an Exception object and both saves and displays it.
|
||||
*
|
||||
* Standard top-of-loop stuff, common between rollback and import.
|
||||
* Pulls in additional information on the location triggering the exception.
|
||||
*
|
||||
* @param \Exception $exception
|
||||
* Object representing the exception.
|
||||
* @param bool $save
|
||||
* (optional) Whether to save the message in the migration's mapping table.
|
||||
* Set to FALSE in contexts where this doesn't make sense.
|
||||
*/
|
||||
protected function handleException(\Exception $exception, $save = TRUE) {
|
||||
$result = Error::decodeException($exception);
|
||||
$message = $result['@message'] . ' (' . $result['%file'] . ':' . $result['%line'] . ')';
|
||||
if ($save) {
|
||||
$this->saveMessage($message);
|
||||
}
|
||||
$this->message->display($message, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for exceptional conditions, and display feedback.
|
||||
*/
|
||||
protected function checkStatus() {
|
||||
if ($this->memoryExceeded()) {
|
||||
return MigrationInterface::RESULT_INCOMPLETE;
|
||||
}
|
||||
if ($this->maxExecTimeExceeded()) {
|
||||
return MigrationInterface::RESULT_INCOMPLETE;
|
||||
}
|
||||
/*
|
||||
* @TODO uncomment this
|
||||
if ($this->getStatus() == MigrationInterface::STATUS_STOPPING) {
|
||||
return MigrationBase::RESULT_STOPPED;
|
||||
}
|
||||
*/
|
||||
// If feedback is requested, produce a progress message at the proper time
|
||||
/*
|
||||
* @TODO uncomment this
|
||||
if (isset($this->feedback)) {
|
||||
if (($this->feedback_unit == 'seconds' && time() - $this->lastfeedback >= $this->feedback) ||
|
||||
($this->feedback_unit == 'items' && $this->processed_since_feedback >= $this->feedback)) {
|
||||
$this->progressMessage(MigrationInterface::RESULT_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return MigrationInterface::RESULT_COMPLETED;
|
||||
}
|
||||
|
||||
|
@ -568,7 +511,15 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
// First, try resetting Drupal's static storage - this frequently releases
|
||||
// plenty of memory to continue.
|
||||
drupal_static_reset();
|
||||
|
||||
// Entity storage can blow up with caches so clear them out.
|
||||
$manager = \Drupal::entityManager();
|
||||
foreach ($manager->getDefinitions() as $id => $definition) {
|
||||
$manager->getStorage($id)->resetCache();
|
||||
}
|
||||
|
||||
// @TODO: explore resetting the container.
|
||||
|
||||
return memory_get_usage();
|
||||
}
|
||||
|
||||
|
@ -585,43 +536,4 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
return format_size($size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether we're approaching the PHP maximum execution time limit.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the threshold is exceeded, FALSE if not.
|
||||
*/
|
||||
protected function maxExecTimeExceeded() {
|
||||
return $this->maxExecTime && (($this->getTimeElapsed() / $this->maxExecTime) > $this->timeThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time elapsed.
|
||||
*
|
||||
* This allows a test to set a fake elapsed time.
|
||||
*/
|
||||
protected function getTimeElapsed() {
|
||||
return time() - REQUEST_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an Exception object and both saves and displays it.
|
||||
*
|
||||
* Pulls in additional information on the location triggering the exception.
|
||||
*
|
||||
* @param \Exception $exception
|
||||
* Object representing the exception.
|
||||
* @param bool $save
|
||||
* (optional) Whether to save the message in the migration's mapping table.
|
||||
* Set to FALSE in contexts where this doesn't make sense.
|
||||
*/
|
||||
protected function handleException(\Exception $exception, $save = TRUE) {
|
||||
$result = Error::decodeException($exception);
|
||||
$message = $result['!message'] . ' (' . $result['%file'] . ':' . $result['%line'] . ')';
|
||||
if ($save) {
|
||||
$this->saveMessage($message);
|
||||
}
|
||||
$this->message->display($message, 'error');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,14 +36,6 @@ interface MigrateExecutableInterface {
|
|||
*/
|
||||
public function processRow(Row $row, array $process = NULL, $value = NULL);
|
||||
|
||||
/**
|
||||
* Returns the time limit.
|
||||
*
|
||||
* @return null|int
|
||||
* The time limit, NULL if no limit or if the units were not in seconds.
|
||||
*/
|
||||
public function getTimeLimit();
|
||||
|
||||
/**
|
||||
* Passes messages through to the map class.
|
||||
*
|
||||
|
|
|
@ -12,4 +12,35 @@ namespace Drupal\migrate;
|
|||
*/
|
||||
class MigrateSkipRowException extends \Exception {
|
||||
|
||||
/**
|
||||
* Whether to record the skip in the map table, or skip silently.
|
||||
*
|
||||
* @var bool
|
||||
* TRUE to record as STATUS_IGNORED in the map, FALSE to skip silently.
|
||||
*/
|
||||
protected $saveToMap;
|
||||
|
||||
/**
|
||||
* Constructs a MigrateSkipRowException object.
|
||||
*
|
||||
* @param string $message
|
||||
* The message for the exception.
|
||||
* @param bool $save_to_map
|
||||
* TRUE to record as STATUS_IGNORED in the map, FALSE to skip silently.
|
||||
*/
|
||||
public function __construct($message = NULL, $save_to_map = TRUE) {
|
||||
parent::__construct($message);
|
||||
$this->saveToMap = $save_to_map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the thrower wants to record this skip in the map table.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE to record as STATUS_IGNORED in the map, FALSE to skip silently.
|
||||
*/
|
||||
public function getSaveToMap() {
|
||||
return $this->saveToMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
69
core/modules/migrate/src/MigrationBuilder.php
Normal file
69
core/modules/migrate/src/MigrationBuilder.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\MigrationBuilder.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate;
|
||||
|
||||
use Drupal\migrate\Entity\Migration;
|
||||
use Drupal\migrate\Plugin\MigratePluginManager;
|
||||
|
||||
/**
|
||||
* Builds migration entities from migration templates.
|
||||
*/
|
||||
class MigrationBuilder {
|
||||
|
||||
/**
|
||||
* The builder plugin manager.
|
||||
*
|
||||
* @var \Drupal\migrate\Plugin\MigratePluginManager
|
||||
*/
|
||||
protected $builderManager;
|
||||
|
||||
/**
|
||||
* Constructs a MigrationBuilder.
|
||||
*
|
||||
* @param \Drupal\migrate\Plugin\MigratePluginManager $builder_manager
|
||||
* The builder plugin manager.
|
||||
*/
|
||||
public function __construct(MigratePluginManager $builder_manager) {
|
||||
$this->builderManager = $builder_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds migration entities from templates.
|
||||
*
|
||||
* @param array $templates
|
||||
* The parsed templates (each of which is an array parsed from YAML), keyed
|
||||
* by ID.
|
||||
*
|
||||
* @return \Drupal\migrate\Entity\MigrationInterface[]
|
||||
* The migration entities derived from the templates.
|
||||
*/
|
||||
public function createMigrations(array $templates) {
|
||||
/** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */
|
||||
$migrations = [];
|
||||
|
||||
foreach ($templates as $template_id => $template) {
|
||||
if (isset($template['builder'])) {
|
||||
$variants = $this->builderManager
|
||||
->createInstance($template['builder']['plugin'], $template['builder'])
|
||||
->buildMigrations($template);
|
||||
}
|
||||
else {
|
||||
$variants = array(Migration::create($template));
|
||||
}
|
||||
|
||||
/** @var \Drupal\migrate\Entity\MigrationInterface[] $variants */
|
||||
foreach ($variants as $variant) {
|
||||
$variant->set('template', $template_id);
|
||||
}
|
||||
$migrations = array_merge($migrations, $variants);
|
||||
}
|
||||
|
||||
return $migrations;
|
||||
}
|
||||
|
||||
}
|
|
@ -8,13 +8,112 @@
|
|||
namespace Drupal\migrate;
|
||||
|
||||
use Drupal\Component\Graph\Graph;
|
||||
use Drupal\Component\Uuid\UuidInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityStorage;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\Query\QueryFactoryInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Storage for migration entities.
|
||||
*/
|
||||
class MigrationStorage extends ConfigEntityStorage implements MigrateBuildDependencyInterface {
|
||||
|
||||
/**
|
||||
* The entity query factory service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Query\QueryFactoryInterface
|
||||
*/
|
||||
protected $queryFactory;
|
||||
|
||||
/**
|
||||
* Constructs a MigrationStorage object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* An entity type definition.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory service.
|
||||
* @param \Drupal\Component\Uuid\UuidInterface $uuid_service
|
||||
* The UUID service.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
* @param \Drupal\Core\Entity\Query\QueryFactoryInterface $query_factory
|
||||
* The entity query factory service.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, ConfigFactoryInterface $config_factory, UuidInterface $uuid_service, LanguageManagerInterface $language_manager, QueryFactoryInterface $query_factory) {
|
||||
parent::__construct($entity_type, $config_factory, $uuid_service, $language_manager);
|
||||
$this->queryFactory = $query_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
return new static(
|
||||
$entity_type,
|
||||
$container->get('config.factory'),
|
||||
$container->get('uuid'),
|
||||
$container->get('language_manager'),
|
||||
$container->get('entity.query.config')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadMultiple(array $ids = NULL) {
|
||||
if ($ids) {
|
||||
$ids = $this->getVariantIds($ids);
|
||||
}
|
||||
/** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */
|
||||
$migrations = parent::loadMultiple($ids);
|
||||
|
||||
foreach ($migrations as $migration) {
|
||||
$dependencies = array_map([$this, 'getVariantIds'], $migration->getMigrationDependencies());
|
||||
$migration->set('migration_dependencies', $dependencies);
|
||||
}
|
||||
|
||||
// Build an array of dependencies and set the order of the migrations.
|
||||
return $this->buildDependencyMigration($migrations, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splices variant IDs into a list of migration IDs.
|
||||
*
|
||||
* IDs which match the template_id:* pattern are shorthand for every variant
|
||||
* of template_id. This method queries for those variant IDs and splices them
|
||||
* into the original list.
|
||||
*
|
||||
* @param string[] $ids
|
||||
* A set of migration IDs.
|
||||
*
|
||||
* @return string[]
|
||||
* The expanded list of IDs.
|
||||
*/
|
||||
protected function getVariantIds(array $ids) {
|
||||
// Re-index the array numerically, since we need to limit the loop by size.
|
||||
$ids = array_values($ids);
|
||||
|
||||
$index = 0;
|
||||
while ($index < count($ids)) {
|
||||
if (substr($ids[$index], -2) == ':*') {
|
||||
$template_id = substr($ids[$index], 0, -2);
|
||||
$variants = $this->queryFactory->get($this->entityType, 'OR')
|
||||
->condition('id', $template_id)
|
||||
->condition('template', $template_id)
|
||||
->execute();
|
||||
array_splice($ids, $index, 1, $variants);
|
||||
$index += count($variants);
|
||||
}
|
||||
else {
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
31
core/modules/migrate/src/Plugin/MigrateBuilderInterface.php
Normal file
31
core/modules/migrate/src/Plugin/MigrateBuilderInterface.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\MigrateBuilderInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin;
|
||||
|
||||
/**
|
||||
* Defines the builder plugin type.
|
||||
*
|
||||
* Builder plugins implement custom logic to generate migration entities from
|
||||
* migration templates. For example, a migration may need to be customized
|
||||
* based on data that's present in the source database; such customization is
|
||||
* implemented by builders.
|
||||
*/
|
||||
interface MigrateBuilderInterface {
|
||||
|
||||
/**
|
||||
* Builds migration entities based on a template.
|
||||
*
|
||||
* @param array $template
|
||||
* The parsed template.
|
||||
*
|
||||
* @return \Drupal\migrate\Entity\MigrationInterface[]
|
||||
* The unsaved migrations generated from the template.
|
||||
*/
|
||||
public function buildMigrations(array $template);
|
||||
|
||||
}
|
|
@ -55,33 +55,6 @@ interface MigrateDestinationInterface extends PluginInspectionInterface {
|
|||
*/
|
||||
public function fields(MigrationInterface $migration = NULL);
|
||||
|
||||
|
||||
/**
|
||||
* Allows pre-processing of an import.
|
||||
*
|
||||
* Derived classes may implement preImport() to do any processing they need
|
||||
* done before over all source rows.
|
||||
*/
|
||||
public function preImport();
|
||||
|
||||
/**
|
||||
* Allows pre-processing of a rollback.
|
||||
*/
|
||||
public function preRollback();
|
||||
|
||||
/**
|
||||
* Allows post-processing of an import.
|
||||
*
|
||||
* Derived classes may implement postImport(), to do any processing they need
|
||||
* done after looping over all source rows.
|
||||
*/
|
||||
public function postImport();
|
||||
|
||||
/**
|
||||
* Allows post-processing of a rollback.
|
||||
*/
|
||||
public function postRollback();
|
||||
|
||||
/**
|
||||
* Import the row.
|
||||
*
|
||||
|
|
|
@ -65,6 +65,20 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
|
|||
*/
|
||||
public function saveMessage(array $source_id_values, $message, $level = MigrationInterface::MESSAGE_ERROR);
|
||||
|
||||
/**
|
||||
* Retrieves an iterator over messages relate to source records.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* (optional) The source identifier values of a specific record to retrieve.
|
||||
* If empty, all messages are retrieved.
|
||||
* @param int $level
|
||||
* (optional) Message severity. If NULL, retrieve messages of all severities.
|
||||
*
|
||||
* @return \Iterator
|
||||
* Retrieves an iterator over the message rows.
|
||||
*/
|
||||
public function getMessageIterator(array $source_id_values = [], $level = NULL);
|
||||
|
||||
/**
|
||||
* Prepares to run a full update.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\builder\BuilderBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\builder;
|
||||
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\migrate\Entity\Migration;
|
||||
use Drupal\migrate\Plugin\MigrateBuilderInterface;
|
||||
|
||||
/**
|
||||
* Base class for builder plugins.
|
||||
*/
|
||||
abstract class BuilderBase extends PluginBase implements MigrateBuilderInterface {
|
||||
|
||||
/**
|
||||
* Returns a fully initialized instance of a source plugin.
|
||||
*
|
||||
* @param string $plugin_id
|
||||
* The plugin ID.
|
||||
* @param array $configuration
|
||||
* (optional) Additional configuration for the plugin.
|
||||
*
|
||||
* @return \Drupal\migrate\Plugin\MigrateSourceInterface
|
||||
* The fully initialized source plugin.
|
||||
*/
|
||||
protected function getSourcePlugin($plugin_id, array $configuration = []) {
|
||||
$configuration['plugin'] = $plugin_id;
|
||||
// By default, SqlBase subclasses will try to join on a map table. But in
|
||||
// this case we're trying to use the source plugin as a detached iterator
|
||||
// over the source data, so we don't want to join on (or create) the map
|
||||
// table.
|
||||
// @see SqlBase::initializeIterator()
|
||||
$configuration['ignore_map'] = TRUE;
|
||||
// Source plugins are tightly coupled to migration entities, so we need
|
||||
// to create a fake migration in order to properly initialize the plugin.
|
||||
$values = [
|
||||
'id' => uniqid(),
|
||||
'source' => $configuration,
|
||||
// Since this isn't a real migration, we don't want a real destination --
|
||||
// the 'null' destination is perfect for this.
|
||||
'destination' => [
|
||||
'plugin' => 'null',
|
||||
],
|
||||
];
|
||||
return Migration::create($values)->getSourcePlugin();
|
||||
}
|
||||
|
||||
}
|
|
@ -59,34 +59,6 @@ abstract class DestinationBase extends PluginBase implements MigrateDestinationI
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the Row before it is imported.
|
||||
*/
|
||||
public function preImport() {
|
||||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the Row before it is rolled back.
|
||||
*/
|
||||
public function preRollback() {
|
||||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postImport() {
|
||||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postRollback() {
|
||||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -94,25 +66,4 @@ abstract class DestinationBase extends PluginBase implements MigrateDestinationI
|
|||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCreated() {
|
||||
// TODO: Implement getCreated() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUpdated() {
|
||||
// TODO: Implement getUpdated() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resetStats() {
|
||||
// TODO: Implement resetStats() method.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,13 +9,20 @@ namespace Drupal\migrate\Plugin\migrate\id_map;
|
|||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateMessageInterface;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate\Event\MigrateEvents;
|
||||
use Drupal\migrate\Event\MigrateMapSaveEvent;
|
||||
use Drupal\migrate\Event\MigrateMapDeleteEvent;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* Defines the sql based ID map implementation.
|
||||
|
@ -25,7 +32,14 @@ use Drupal\migrate\Row;
|
|||
*
|
||||
* @PluginID("sql")
|
||||
*/
|
||||
class Sql extends PluginBase implements MigrateIdMapInterface {
|
||||
class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* An event dispatcher instance to use for map events.
|
||||
*
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
protected $eventDispatcher;
|
||||
|
||||
/**
|
||||
* The migration map table name.
|
||||
|
@ -137,10 +151,23 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
|
|||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* The migration to do.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EventDispatcherInterface $event_dispatcher) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->migration = $migration;
|
||||
$this->eventDispatcher = $event_dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('event_dispatcher')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -504,6 +531,8 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
|
|||
$fields['last_imported'] = time();
|
||||
}
|
||||
if ($keys) {
|
||||
// Notify anyone listening of the map row we're about to save.
|
||||
$this->eventDispatcher->dispatch(MigrateEvents::MAP_SAVE, new MigrateMapSaveEvent($this, $keys + $fields));
|
||||
$this->getDatabase()->merge($this->mapTableName())
|
||||
->key($keys)
|
||||
->fields($fields)
|
||||
|
@ -530,6 +559,22 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
|
|||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMessageIterator(array $source_id_values = [], $level = NULL) {
|
||||
$query = $this->getDatabase()->select($this->messageTableName(), 'msg')
|
||||
->fields('msg');
|
||||
$count = 1;
|
||||
foreach ($source_id_values as $id_value) {
|
||||
$query->condition('sourceid' . $count++, $id_value);
|
||||
}
|
||||
if ($level) {
|
||||
$query->condition('level', $level);
|
||||
}
|
||||
return $query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -620,6 +665,8 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
|
|||
}
|
||||
|
||||
if (!$messages_only) {
|
||||
// Notify anyone listening of the map row we're about to delete.
|
||||
$this->eventDispatcher->dispatch(MigrateEvents::MAP_DELETE, new MigrateMapDeleteEvent($this, $source_id_values));
|
||||
$map_query->execute();
|
||||
}
|
||||
$message_query->execute();
|
||||
|
@ -638,6 +685,8 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
|
|||
$map_query->condition('destid' . $count, $key_value);
|
||||
$count++;
|
||||
}
|
||||
// Notify anyone listening of the map row we're about to delete.
|
||||
$this->eventDispatcher->dispatch(MigrateEvents::MAP_DELETE, new MigrateMapDeleteEvent($this, $source_id));
|
||||
$map_query->execute();
|
||||
$count = 1;
|
||||
foreach ($source_id as $key_value) {
|
||||
|
@ -673,6 +722,8 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
|
|||
if (count($this->migration->getSourcePlugin()->getIds()) == 1) {
|
||||
$sourceids = array();
|
||||
foreach ($source_id_values as $source_id) {
|
||||
// Notify anyone listening of the map rows we're about to delete.
|
||||
$this->eventDispatcher->dispatch(MigrateEvents::MAP_DELETE, new MigrateMapDeleteEvent($this, $source_id));
|
||||
$sourceids[] = $source_id;
|
||||
}
|
||||
$this->getDatabase()->delete($this->mapTableName())
|
||||
|
@ -684,6 +735,8 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
|
|||
}
|
||||
else {
|
||||
foreach ($source_id_values as $source_id) {
|
||||
// Notify anyone listening of the map rows we're deleting.
|
||||
$this->eventDispatcher->dispatch(MigrateEvents::MAP_DELETE, new MigrateMapDeleteEvent($this, $source_id));
|
||||
$map_query = $this->getDatabase()->delete($this->mapTableName());
|
||||
$message_query = $this->getDatabase()->delete($this->messageTableName());
|
||||
$count = 1;
|
||||
|
@ -716,8 +769,6 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
|
|||
* Implementation of Iterator::rewind().
|
||||
*
|
||||
* This is called before beginning a foreach loop.
|
||||
*
|
||||
* @todo Support idlist, itemlimit.
|
||||
*/
|
||||
public function rewind() {
|
||||
$this->currentRow = NULL;
|
||||
|
@ -728,13 +779,6 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
|
|||
foreach ($this->destinationIdFields() as $field) {
|
||||
$fields[] = $field;
|
||||
}
|
||||
|
||||
// @todo Make this work.
|
||||
/*
|
||||
if (isset($this->options['itemlimit'])) {
|
||||
$query = $query->range(0, $this->options['itemlimit']);
|
||||
}
|
||||
*/
|
||||
$this->result = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map', $fields)
|
||||
->execute();
|
||||
|
@ -786,7 +830,6 @@ class Sql extends PluginBase implements MigrateIdMapInterface {
|
|||
* and FALSE to terminate it.
|
||||
*/
|
||||
public function valid() {
|
||||
// @todo Check numProcessed against itemlimit.
|
||||
return $this->currentRow !== FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,12 @@ class Extract extends ProcessPluginBase {
|
|||
}
|
||||
$new_value = NestedArray::getValue($value, $this->configuration['index'], $key_exists);
|
||||
if (!$key_exists) {
|
||||
throw new MigrateException('Array index missing, extraction failed.');
|
||||
if (isset($this->configuration['default'])) {
|
||||
$new_value = $this->configuration['default'];
|
||||
}
|
||||
else {
|
||||
throw new MigrateException('Array index missing, extraction failed.');
|
||||
}
|
||||
}
|
||||
return $new_value;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ namespace Drupal\migrate\Plugin\migrate\process;
|
|||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\MigrateSkipProcessException;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
use Drupal\migrate\Plugin\MigratePluginManager;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
|
@ -145,7 +144,6 @@ class Migration extends ProcessPluginBase implements ContainerFactoryPluginInter
|
|||
return $destination_ids;
|
||||
}
|
||||
}
|
||||
throw new MigrateSkipRowException();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,6 +47,7 @@ class Route extends ProcessPluginBase implements ContainerFactoryPluginInterface
|
|||
$container->get('path.validator')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\source\EmbeddedDataSource.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Plugin\migrate\source;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
|
||||
/**
|
||||
* Source which takes its data directly from the plugin config.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "embedded_data"
|
||||
* )
|
||||
*/
|
||||
class EmbeddedDataSource extends SourcePluginBase {
|
||||
|
||||
/**
|
||||
* Data obtained from the source plugin configuration.
|
||||
*
|
||||
* @var array[]
|
||||
* Array of data rows, each one an array of values keyed by field names.
|
||||
*/
|
||||
protected $dataRows = [];
|
||||
|
||||
/**
|
||||
* Description of the unique ID fields for this source.
|
||||
*
|
||||
* @var array[]
|
||||
* Each array member is keyed by a field name, with a value that is an
|
||||
* array with a single member with key 'type' and value a column type such
|
||||
* as 'integer'.
|
||||
*/
|
||||
protected $ids = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
$this->dataRows = $configuration['data_rows'];
|
||||
$this->ids = $configuration['ids'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
if ($this->count() > 0) {
|
||||
$first_row = reset($this->dataRows);
|
||||
$field_names = array_keys($first_row);
|
||||
return array_combine($field_names, $field_names);
|
||||
}
|
||||
else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function initializeIterator() {
|
||||
return new \ArrayIterator($this->dataRows);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString() {
|
||||
return 'Embedded data';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return $this->ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count() {
|
||||
return count($this->dataRows);
|
||||
}
|
||||
|
||||
}
|
|
@ -10,6 +10,8 @@ namespace Drupal\migrate\Plugin\migrate\source;
|
|||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\Plugin\MigrateSourceInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
@ -59,20 +61,6 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
*/
|
||||
protected $currentSourceIds;
|
||||
|
||||
/**
|
||||
* Number of rows intentionally ignored (prepareRow() returned FALSE)
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $numIgnored = 0;
|
||||
|
||||
/**
|
||||
* Number of rows we've at least looked at.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $numProcessed = 0;
|
||||
|
||||
/**
|
||||
* The high water mark at the beginning of the import operation.
|
||||
*
|
||||
|
@ -83,13 +71,6 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
*/
|
||||
protected $originalHighWater;
|
||||
|
||||
/**
|
||||
* List of source IDs to process.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $idList = array();
|
||||
|
||||
/**
|
||||
* Whether this instance should cache the source count.
|
||||
*
|
||||
|
@ -144,8 +125,12 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
*/
|
||||
protected $iterator;
|
||||
|
||||
// @TODO, find out how to remove this.
|
||||
// @see https://www.drupal.org/node/2443617
|
||||
/**
|
||||
* @TODO, find out how to remove this.
|
||||
* @see https://www.drupal.org/node/2443617
|
||||
*
|
||||
* @var MigrateExecutableInterface
|
||||
*/
|
||||
public $migrateExecutable;
|
||||
|
||||
/**
|
||||
|
@ -166,10 +151,6 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
$this->originalHighWater = $this->migration->getHighWater();
|
||||
}
|
||||
|
||||
if ($id_list = $this->migration->get('idlist')) {
|
||||
$this->idList = $id_list;
|
||||
}
|
||||
|
||||
// Don't allow the use of both highwater and track changes together.
|
||||
if ($this->highWaterProperty && $this->trackChanges) {
|
||||
throw new MigrateException('You should either use a highwater mark or track changes not both. They are both designed to solve the same problem');
|
||||
|
@ -201,22 +182,31 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
|
||||
$result = TRUE;
|
||||
$result_hook = $this->getModuleHandler()->invokeAll('migrate_prepare_row', array($row, $this, $this->migration));
|
||||
$result_named_hook = $this->getModuleHandler()->invokeAll('migrate_' . $this->migration->id() . '_prepare_row', array($row, $this, $this->migration));
|
||||
try {
|
||||
$result_hook = $this->getModuleHandler()->invokeAll('migrate_prepare_row', array($row, $this, $this->migration));
|
||||
$result_named_hook = $this->getModuleHandler()->invokeAll('migrate_' . $this->migration->id() . '_prepare_row', array($row, $this, $this->migration));
|
||||
// We will skip if any hook returned FALSE.
|
||||
$skip = ($result_hook && in_array(FALSE, $result_hook)) || ($result_named_hook && in_array(FALSE, $result_named_hook));
|
||||
$save_to_map = TRUE;
|
||||
}
|
||||
catch (MigrateSkipRowException $e) {
|
||||
$skip = TRUE;
|
||||
$save_to_map = $e->getSaveToMap();
|
||||
}
|
||||
|
||||
// We're explicitly skipping this row - keep track in the map table.
|
||||
if (($result_hook && in_array(FALSE, $result_hook)) || ($result_named_hook && in_array(FALSE, $result_named_hook))) {
|
||||
if ($skip) {
|
||||
// Make sure we replace any previous messages for this item with any
|
||||
// new ones.
|
||||
$id_map = $this->migration->getIdMap();
|
||||
$id_map->delete($this->currentSourceIds, TRUE);
|
||||
$this->migrateExecutable->saveQueuedMessages();
|
||||
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED, $this->migrateExecutable->rollbackAction);
|
||||
$this->numIgnored++;
|
||||
$this->currentRow = NULL;
|
||||
$this->currentSourceIds = NULL;
|
||||
if ($save_to_map) {
|
||||
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED, $this->migrateExecutable->rollbackAction);
|
||||
$this->currentRow = NULL;
|
||||
$this->currentSourceIds = NULL;
|
||||
}
|
||||
$result = FALSE;
|
||||
}
|
||||
elseif ($this->trackChanges) {
|
||||
|
@ -226,7 +216,6 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
// after hashes).
|
||||
$row->rehash();
|
||||
}
|
||||
$this->numProcessed++;
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -280,8 +269,6 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
*/
|
||||
public function rewind() {
|
||||
$this->idMap = $this->migration->getIdMap();
|
||||
$this->numProcessed = 0;
|
||||
$this->numIgnored = 0;
|
||||
$this->getIterator()->rewind();
|
||||
$this->next();
|
||||
}
|
||||
|
@ -320,25 +307,17 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
$row->setIdMap($id_map);
|
||||
}
|
||||
|
||||
// In case we have specified an ID list, but the ID given by the source is
|
||||
// not in there, we skip the row.
|
||||
$id_in_the_list = $this->idList && in_array(reset($this->currentSourceIds), $this->idList);
|
||||
if ($this->idList && !$id_in_the_list) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Preparing the row gives source plugins the chance to skip.
|
||||
if ($this->prepareRow($row) === FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check whether the row needs processing.
|
||||
// 1. Explicitly specified IDs.
|
||||
// 2. This row has not been imported yet.
|
||||
// 3. Explicitly set to update.
|
||||
// 4. The row is newer than the current highwater mark.
|
||||
// 5. If no such property exists then try by checking the hash of the row.
|
||||
if ($id_in_the_list || !$row->getIdMap() || $row->needsUpdate() || $this->aboveHighwater($row) || $this->rowChanged($row) ) {
|
||||
// 1. This row has not been imported yet.
|
||||
// 2. Explicitly set to update.
|
||||
// 3. The row is newer than the current highwater mark.
|
||||
// 4. If no such property exists then try by checking the hash of the row.
|
||||
if (!$row->getIdMap() || $row->needsUpdate() || $this->aboveHighwater($row) || $this->rowChanged($row) ) {
|
||||
$this->currentRow = $row->freezeSource();
|
||||
}
|
||||
}
|
||||
|
@ -377,27 +356,6 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
return $this->currentSourceIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for numIgnored data member.
|
||||
*/
|
||||
public function getIgnored() {
|
||||
return $this->numIgnored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for numProcessed data member.
|
||||
*/
|
||||
public function getProcessed() {
|
||||
return $this->numProcessed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset numIgnored back to 0.
|
||||
*/
|
||||
public function resetStats() {
|
||||
$this->numIgnored = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source count.
|
||||
*
|
||||
|
@ -423,7 +381,7 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
// class to get the count from the source.
|
||||
if ($refresh || !$this->cacheCounts) {
|
||||
$count = $this->getIterator()->count();
|
||||
$this->getCache()->set($this->cacheKey, $count, 'cache');
|
||||
$this->getCache()->set($this->cacheKey, $count);
|
||||
}
|
||||
else {
|
||||
// Caching is in play, first try to retrieve a cached count.
|
||||
|
@ -436,7 +394,7 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
// No cached count, ask the derived class to count 'em up, and cache
|
||||
// the result.
|
||||
$count = $this->getIterator()->count();
|
||||
$this->getCache()->set($this->cacheKey, $count, 'cache');
|
||||
$this->getCache()->set($this->cacheKey, $count);
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
|
|
|
@ -28,11 +28,6 @@ abstract class SqlBase extends SourcePluginBase {
|
|||
*/
|
||||
protected $query;
|
||||
|
||||
/**
|
||||
* @var \Drupal\migrate\Entity\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
|
@ -116,76 +111,69 @@ abstract class SqlBase extends SourcePluginBase {
|
|||
$this->prepareQuery();
|
||||
$high_water_property = $this->migration->get('highWaterProperty');
|
||||
|
||||
// Get the key values, for potential use in joining to the map table, or
|
||||
// enforcing idlist.
|
||||
// Get the key values, for potential use in joining to the map table.
|
||||
$keys = array();
|
||||
|
||||
// The rules for determining what conditions to add to the query are as
|
||||
// follows (applying first applicable rule)
|
||||
// 1. If idlist is provided, then only process items in that list (AND key
|
||||
// IN (idlist)). Only applicable with single-value keys.
|
||||
if ($id_list = $this->migration->get('idlist')) {
|
||||
$this->query->condition($keys[0], $id_list, 'IN');
|
||||
}
|
||||
else {
|
||||
// 2. If the map is joinable, join it. We will want to accept all rows
|
||||
// which are either not in the map, or marked in the map as NEEDS_UPDATE.
|
||||
// Note that if high water fields are in play, we want to accept all rows
|
||||
// above the high water mark in addition to those selected by the map
|
||||
// conditions, so we need to OR them together (but AND with any existing
|
||||
// conditions in the query). So, ultimately the SQL condition will look
|
||||
// like (original conditions) AND (map IS NULL OR map needs update
|
||||
// OR above high water).
|
||||
$conditions = $this->query->orConditionGroup();
|
||||
$condition_added = FALSE;
|
||||
if ($this->mapJoinable()) {
|
||||
// Build the join to the map table. Because the source key could have
|
||||
// multiple fields, we need to build things up.
|
||||
$count = 1;
|
||||
$map_join = '';
|
||||
$delimiter = '';
|
||||
foreach ($this->getIds() as $field_name => $field_schema) {
|
||||
if (isset($field_schema['alias'])) {
|
||||
$field_name = $field_schema['alias'] . '.' . $field_name;
|
||||
}
|
||||
$map_join .= "$delimiter$field_name = map.sourceid" . $count++;
|
||||
$delimiter = ' AND ';
|
||||
|
||||
// 1. If the map is joinable, join it. We will want to accept all rows
|
||||
// which are either not in the map, or marked in the map as NEEDS_UPDATE.
|
||||
// Note that if high water fields are in play, we want to accept all rows
|
||||
// above the high water mark in addition to those selected by the map
|
||||
// conditions, so we need to OR them together (but AND with any existing
|
||||
// conditions in the query). So, ultimately the SQL condition will look
|
||||
// like (original conditions) AND (map IS NULL OR map needs update
|
||||
// OR above high water).
|
||||
$conditions = $this->query->orConditionGroup();
|
||||
$condition_added = FALSE;
|
||||
if (empty($this->configuration['ignore_map']) && $this->mapJoinable()) {
|
||||
// Build the join to the map table. Because the source key could have
|
||||
// multiple fields, we need to build things up.
|
||||
$count = 1;
|
||||
$map_join = '';
|
||||
$delimiter = '';
|
||||
foreach ($this->getIds() as $field_name => $field_schema) {
|
||||
if (isset($field_schema['alias'])) {
|
||||
$field_name = $field_schema['alias'] . '.' . $field_name;
|
||||
}
|
||||
$map_join .= "$delimiter$field_name = map.sourceid" . $count++;
|
||||
$delimiter = ' AND ';
|
||||
}
|
||||
|
||||
$alias = $this->query->leftJoin($this->migration->getIdMap()->getQualifiedMapTableName(), 'map', $map_join);
|
||||
$conditions->isNull($alias . '.sourceid1');
|
||||
$conditions->condition($alias . '.source_row_status', MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
|
||||
$condition_added = TRUE;
|
||||
$alias = $this->query->leftJoin($this->migration->getIdMap()->getQualifiedMapTableName(), 'map', $map_join);
|
||||
$conditions->isNull($alias . '.sourceid1');
|
||||
$conditions->condition($alias . '.source_row_status', MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
|
||||
$condition_added = TRUE;
|
||||
|
||||
// And as long as we have the map table, add its data to the row.
|
||||
$n = count($this->getIds());
|
||||
// And as long as we have the map table, add its data to the row.
|
||||
$n = count($this->getIds());
|
||||
for ($count = 1; $count <= $n; $count++) {
|
||||
$map_key = 'sourceid' . $count;
|
||||
$this->query->addField($alias, $map_key, "migrate_map_$map_key");
|
||||
}
|
||||
if ($n = count($this->migration->get('destinationIds'))) {
|
||||
for ($count = 1; $count <= $n; $count++) {
|
||||
$map_key = 'sourceid' . $count;
|
||||
$map_key = 'destid' . $count++;
|
||||
$this->query->addField($alias, $map_key, "migrate_map_$map_key");
|
||||
}
|
||||
if ($n = count($this->migration->get('destinationIds'))) {
|
||||
for ($count = 1; $count <= $n; $count++) {
|
||||
$map_key = 'destid' . $count++;
|
||||
$this->query->addField($alias, $map_key, "migrate_map_$map_key");
|
||||
}
|
||||
}
|
||||
$this->query->addField($alias, 'source_row_status', 'migrate_map_source_row_status');
|
||||
}
|
||||
// 3. 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 (isset($high_water_property['name']) && ($high_water = $this->migration->getHighWater()) !== '') {
|
||||
if (isset($high_water_property['alias'])) {
|
||||
$high_water = $high_water_property['alias'] . '.' . $high_water_property['name'];
|
||||
}
|
||||
else {
|
||||
$high_water = $high_water_property['name'];
|
||||
}
|
||||
$conditions->condition($high_water, $high_water, '>');
|
||||
$condition_added = TRUE;
|
||||
$this->query->addField($alias, 'source_row_status', 'migrate_map_source_row_status');
|
||||
}
|
||||
// 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 (isset($high_water_property['name']) && ($high_water = $this->migration->getHighWater()) !== '') {
|
||||
if (isset($high_water_property['alias'])) {
|
||||
$high_water = $high_water_property['alias'] . '.' . $high_water_property['name'];
|
||||
}
|
||||
if ($condition_added) {
|
||||
$this->query->condition($conditions);
|
||||
else {
|
||||
$high_water = $high_water_property['name'];
|
||||
}
|
||||
$conditions->condition($high_water, $high_water, '>');
|
||||
$condition_added = TRUE;
|
||||
}
|
||||
if ($condition_added) {
|
||||
$this->query->condition($conditions);
|
||||
}
|
||||
|
||||
return new \IteratorIterator($this->query->execute());
|
||||
|
|
77
core/modules/migrate/src/Tests/MigrateEmbeddedDataTest.php
Normal file
77
core/modules/migrate/src/Tests/MigrateEmbeddedDataTest.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Tests\MigrateEmbeddedDataTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Tests;
|
||||
|
||||
use Drupal\migrate\Entity\Migration;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\simpletest\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests the EmbeddedDataSource plugin.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class MigrateEmbeddedDataTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['migrate'];
|
||||
|
||||
/**
|
||||
* Tests the embedded_data source plugin.
|
||||
*/
|
||||
public function testEmbeddedData() {
|
||||
$data_rows = [
|
||||
['key' => '1', 'field1' => 'f1value1', 'field2' => 'f2value1'],
|
||||
['key' => '2', 'field1' => 'f1value2', 'field2' => 'f2value2'],
|
||||
];
|
||||
$ids = ['key' => ['type' => 'integer']];
|
||||
$config = [
|
||||
'id' => 'sample_data',
|
||||
'migration_tags' => ['Embedded data test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => $data_rows,
|
||||
'ids' => $ids,
|
||||
],
|
||||
'process' => [],
|
||||
'destination' => ['plugin' => 'null'],
|
||||
];
|
||||
|
||||
$migration = Migration::create($config);
|
||||
$source = $migration->getSourcePlugin();
|
||||
|
||||
// Validate the plugin returns the source data that was provided.
|
||||
$results = [];
|
||||
/** @var Row $row */
|
||||
foreach ($source as $row) {
|
||||
$data_row = $row->getSource();
|
||||
// The "data" row returned by getSource() also includes all source
|
||||
// configuration - we remove it so we see only the data itself.
|
||||
unset($data_row['plugin']);
|
||||
unset($data_row['data_rows']);
|
||||
unset($data_row['ids']);
|
||||
$results[] = $data_row;
|
||||
}
|
||||
$this->assertIdentical($results, $data_rows);
|
||||
|
||||
// Validate the public APIs.
|
||||
$this->assertIdentical($source->count(), count($data_rows));
|
||||
$this->assertIdentical($source->getIds(), $ids);
|
||||
$expected_fields = [
|
||||
'key' => 'key',
|
||||
'field1' => 'field1',
|
||||
'field2' => 'field2',
|
||||
];
|
||||
$this->assertIdentical($source->fields(), $expected_fields);
|
||||
}
|
||||
|
||||
}
|
227
core/modules/migrate/src/Tests/MigrateEventsTest.php
Normal file
227
core/modules/migrate/src/Tests/MigrateEventsTest.php
Normal file
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Tests\MigrateEventsTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Tests;
|
||||
|
||||
use Drupal\migrate\Entity\Migration;
|
||||
use Drupal\migrate\Event\MigrateImportEvent;
|
||||
use Drupal\migrate\Event\MigrateMapDeleteEvent;
|
||||
use Drupal\migrate\Event\MigrateMapSaveEvent;
|
||||
use Drupal\migrate\Event\MigratePostRowSaveEvent;
|
||||
use Drupal\migrate\Event\MigratePreRowSaveEvent;
|
||||
use Drupal\migrate\MigrateMessage;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Event\MigrateEvents;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\simpletest\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests events fired on migrations.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class MigrateEventsTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* State service for recording information received by event listeners.
|
||||
*
|
||||
* @var \Drupal\Core\State\State
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['migrate', 'migrate_events_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->state = \Drupal::state();
|
||||
\Drupal::service('event_dispatcher')->addListener(MigrateEvents::MAP_SAVE,
|
||||
array($this, 'mapSaveEventRecorder'));
|
||||
\Drupal::service('event_dispatcher')->addListener(MigrateEvents::MAP_DELETE,
|
||||
array($this, 'mapDeleteEventRecorder'));
|
||||
\Drupal::service('event_dispatcher')->addListener(MigrateEvents::PRE_IMPORT,
|
||||
array($this, 'preImportEventRecorder'));
|
||||
\Drupal::service('event_dispatcher')->addListener(MigrateEvents::POST_IMPORT,
|
||||
array($this, 'postImportEventRecorder'));
|
||||
\Drupal::service('event_dispatcher')->addListener(MigrateEvents::PRE_ROW_SAVE,
|
||||
array($this, 'preRowSaveEventRecorder'));
|
||||
\Drupal::service('event_dispatcher')->addListener(MigrateEvents::POST_ROW_SAVE,
|
||||
array($this, 'postRowSaveEventRecorder'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration events.
|
||||
*/
|
||||
public function testMigrateEvents() {
|
||||
// Run a simple little migration, which should trigger one of each event
|
||||
// other than map_delete.
|
||||
$config = [
|
||||
'id' => 'sample_data',
|
||||
'migration_tags' => ['Event test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => [
|
||||
['data' => 'dummy value'],
|
||||
],
|
||||
'ids' => [
|
||||
'data' => ['type' => 'string'],
|
||||
],
|
||||
],
|
||||
'process' => ['value' => 'data'],
|
||||
'destination' => ['plugin' => 'dummy'],
|
||||
];
|
||||
|
||||
$migration = Migration::create($config);
|
||||
|
||||
/** @var MigrationInterface $migration */
|
||||
$executable = new MigrateExecutable($migration, new MigrateMessage);
|
||||
// As the import runs, events will be dispatched, recording the received
|
||||
// information in state.
|
||||
$executable->import();
|
||||
|
||||
// Validate from the recorded state that the events were received.
|
||||
$event = $this->state->get('migrate_events_test.pre_import_event', []);
|
||||
$this->assertIdentical($event['event_name'], MigrateEvents::PRE_IMPORT);
|
||||
$this->assertIdentical($event['migration']->id(), $migration->id());
|
||||
|
||||
$event = $this->state->get('migrate_events_test.post_import_event', []);
|
||||
$this->assertIdentical($event['event_name'], MigrateEvents::POST_IMPORT);
|
||||
$this->assertIdentical($event['migration']->id(), $migration->id());
|
||||
|
||||
$event = $this->state->get('migrate_events_test.map_save_event', []);
|
||||
$this->assertIdentical($event['event_name'], MigrateEvents::MAP_SAVE);
|
||||
// Validating the last row processed.
|
||||
$this->assertIdentical($event['fields']['sourceid1'], 'dummy value');
|
||||
$this->assertIdentical($event['fields']['destid1'], 'dummy value');
|
||||
$this->assertIdentical($event['fields']['source_row_status'], 0);
|
||||
|
||||
$event = $this->state->get('migrate_events_test.map_delete_event', []);
|
||||
$this->assertIdentical($event, []);
|
||||
|
||||
$event = $this->state->get('migrate_events_test.pre_row_save_event', []);
|
||||
$this->assertIdentical($event['event_name'], MigrateEvents::PRE_ROW_SAVE);
|
||||
$this->assertIdentical($event['migration']->id(), $migration->id());
|
||||
// Validating the last row processed.
|
||||
$this->assertIdentical($event['row']->getSourceProperty('data'), 'dummy value');
|
||||
|
||||
$event = $this->state->get('migrate_events_test.post_row_save_event', []);
|
||||
$this->assertIdentical($event['event_name'], MigrateEvents::POST_ROW_SAVE);
|
||||
$this->assertIdentical($event['migration']->id(), $migration->id());
|
||||
// Validating the last row processed.
|
||||
$this->assertIdentical($event['row']->getSourceProperty('data'), 'dummy value');
|
||||
$this->assertIdentical($event['destination_id_values']['value'], 'dummy value');
|
||||
|
||||
// Generate a map delete event.
|
||||
$migration->getIdMap()->delete(['data' => 'dummy value']);
|
||||
$event = $this->state->get('migrate_events_test.map_delete_event', []);
|
||||
$this->assertIdentical($event['event_name'], MigrateEvents::MAP_DELETE);
|
||||
$this->assertIdentical($event['source_id'], ['data' => 'dummy value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reacts to map save event.
|
||||
*
|
||||
* @param \Drupal\Migrate\Event\MigrateMapSaveEvent $event
|
||||
* The migration event.
|
||||
* @param string $name
|
||||
* The event name.
|
||||
*/
|
||||
public function mapSaveEventRecorder(MigrateMapSaveEvent $event, $name) {
|
||||
$this->state->set('migrate_events_test.map_save_event', array(
|
||||
'event_name' => $name,
|
||||
'map' => $event->getMap(),
|
||||
'fields' => $event->getFields(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reacts to map delete event.
|
||||
*
|
||||
* @param \Drupal\Migrate\Event\MigrateMapDeleteEvent $event
|
||||
* The migration event.
|
||||
* @param string $name
|
||||
* The event name.
|
||||
*/
|
||||
public function mapDeleteEventRecorder(MigrateMapDeleteEvent $event, $name) {
|
||||
$this->state->set('migrate_events_test.map_delete_event', array(
|
||||
'event_name' => $name,
|
||||
'map' => $event->getMap(),
|
||||
'source_id' => $event->getSourceId(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reacts to pre-import event.
|
||||
*
|
||||
* @param \Drupal\Migrate\Event\MigrateImportEvent $event
|
||||
* The migration event.
|
||||
* @param string $name
|
||||
* The event name.
|
||||
*/
|
||||
public function preImportEventRecorder(MigrateImportEvent $event, $name) {
|
||||
$this->state->set('migrate_events_test.pre_import_event', array(
|
||||
'event_name' => $name,
|
||||
'migration' => $event->getMigration(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reacts to post-import event.
|
||||
*
|
||||
* @param \Drupal\Migrate\Event\MigrateImportEvent $event
|
||||
* The migration event.
|
||||
* @param string $name
|
||||
* The event name.
|
||||
*/
|
||||
public function postImportEventRecorder(MigrateImportEvent $event, $name) {
|
||||
$this->state->set('migrate_events_test.post_import_event', array(
|
||||
'event_name' => $name,
|
||||
'migration' => $event->getMigration(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reacts to pre-row-save event.
|
||||
*
|
||||
* @param \Drupal\Migrate\Event\MigratePreRowSaveEvent $event
|
||||
* The migration event.
|
||||
* @param string $name
|
||||
* The event name.
|
||||
*/
|
||||
public function preRowSaveEventRecorder(MigratePreRowSaveEvent $event, $name) {
|
||||
$this->state->set('migrate_events_test.pre_row_save_event', array(
|
||||
'event_name' => $name,
|
||||
'migration' => $event->getMigration(),
|
||||
'row' => $event->getRow(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reacts to post-row-save event.
|
||||
*
|
||||
* @param \Drupal\Migrate\Event\MigratePostRowSaveEvent $event
|
||||
* The migration event.
|
||||
* @param string $name
|
||||
* The event name.
|
||||
*/
|
||||
public function postRowSaveEventRecorder(MigratePostRowSaveEvent $event, $name) {
|
||||
$this->state->set('migrate_events_test.post_row_save_event', array(
|
||||
'event_name' => $name,
|
||||
'migration' => $event->getMigration(),
|
||||
'row' => $event->getRow(),
|
||||
'destination_id_values' => $event->getDestinationIdValues(),
|
||||
));
|
||||
}
|
||||
|
||||
}
|
89
core/modules/migrate/src/Tests/MigrateInterruptionTest.php
Normal file
89
core/modules/migrate/src/Tests/MigrateInterruptionTest.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Tests\MigrateInterruptionTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Tests;
|
||||
|
||||
use Drupal\migrate\Entity\Migration;
|
||||
use Drupal\migrate\Event\MigratePostRowSaveEvent;
|
||||
use Drupal\migrate\MigrateMessage;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Event\MigrateEvents;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\simpletest\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests interruptions triggered during migrations.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class MigrateInterruptionTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['migrate', 'migrate_events_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
\Drupal::service('event_dispatcher')->addListener(MigrateEvents::POST_ROW_SAVE,
|
||||
array($this, 'postRowSaveEventRecorder'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests migration interruptions.
|
||||
*/
|
||||
public function testMigrateEvents() {
|
||||
// Run a simple little migration, which should trigger one of each event
|
||||
// other than map_delete.
|
||||
$config = [
|
||||
'id' => 'sample_data',
|
||||
'migration_tags' => ['Interruption test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => [
|
||||
['data' => 'dummy value'],
|
||||
['data' => 'dummy value2'],
|
||||
],
|
||||
'ids' => [
|
||||
'data' => ['type' => 'string'],
|
||||
],
|
||||
],
|
||||
'process' => ['value' => 'data'],
|
||||
'destination' => ['plugin' => 'dummy'],
|
||||
];
|
||||
|
||||
$migration = Migration::create($config);
|
||||
|
||||
/** @var MigrationInterface $migration */
|
||||
$executable = new MigrateExecutable($migration, new MigrateMessage);
|
||||
// When the import runs, the first row imported will trigger an interruption.
|
||||
$result = $executable->import();
|
||||
|
||||
$this->assertEqual($result, MigrationInterface::RESULT_INCOMPLETE);
|
||||
|
||||
// The status should have been reset to IDLE.
|
||||
$this->assertEqual($migration->getStatus(), MigrationInterface::STATUS_IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reacts to post-row-save event.
|
||||
*
|
||||
* @param \Drupal\Migrate\Event\MigratePostRowSaveEvent $event
|
||||
* The migration event.
|
||||
* @param string $name
|
||||
* The event name.
|
||||
*/
|
||||
public function postRowSaveEventRecorder(MigratePostRowSaveEvent $event, $name) {
|
||||
$event->getMigration()->interruptMigration(MigrationInterface::RESULT_INCOMPLETE);
|
||||
}
|
||||
|
||||
}
|
74
core/modules/migrate/src/Tests/MigrateSkipRowTest.php
Normal file
74
core/modules/migrate/src/Tests/MigrateSkipRowTest.php
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Tests\MigrateSkipRowTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Tests;
|
||||
|
||||
use Drupal\migrate\Entity\Migration;
|
||||
use Drupal\migrate\MigrateMessage;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\simpletest\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests row skips triggered during hook_migrate_prepare_row().
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class MigrateSkipRowTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['migrate', 'migrate_prepare_row_test'];
|
||||
|
||||
/**
|
||||
* Tests migration interruptions.
|
||||
*/
|
||||
public function testPrepareRowSkip() {
|
||||
// Run a simple little migration with two data rows which should be skipped
|
||||
// in different ways.
|
||||
$config = [
|
||||
'id' => 'sample_data',
|
||||
'migration_tags' => ['prepare_row test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => [
|
||||
['id' => '1', 'data' => 'skip_and_record'],
|
||||
['id' => '2', 'data' => 'skip_and_dont_record']
|
||||
],
|
||||
'ids' => [
|
||||
'id' => ['type' => 'string'],
|
||||
],
|
||||
],
|
||||
'process' => ['value' => 'data'],
|
||||
'destination' => [
|
||||
'plugin' => 'config',
|
||||
'config_name' => 'migrate_test.settings',
|
||||
],
|
||||
'load' => ['plugin' => 'null'],
|
||||
];
|
||||
|
||||
$migration = Migration::create($config);
|
||||
|
||||
$executable = new MigrateExecutable($migration, new MigrateMessage);
|
||||
$result = $executable->import();
|
||||
$this->assertEqual($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([1]);
|
||||
$this->assertEqual(MigrateIdMapInterface::STATUS_IGNORED, $map_row['source_row_status']);
|
||||
// The second row is not recorded in the map.
|
||||
$map_row = $id_map_plugin->getRowBySource([2]);
|
||||
$this->assertFalse($map_row);
|
||||
|
||||
}
|
||||
|
||||
}
|
56
core/modules/migrate/src/Tests/MigrateStatusTest.php
Normal file
56
core/modules/migrate/src/Tests/MigrateStatusTest.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Tests\MigrateStatusTest
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Tests;
|
||||
|
||||
use Drupal\migrate\Entity\Migration;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
|
||||
/**
|
||||
* Test migration status tracking.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class MigrateStatusTest extends MigrateTestBase {
|
||||
|
||||
/**
|
||||
* Test different connection types.
|
||||
*/
|
||||
public function testStatus() {
|
||||
// Create a minimally valid migration.
|
||||
$configuration = [
|
||||
'id' => 'migration_status_test',
|
||||
'migration_tags' => ['Testing'],
|
||||
'source' => ['plugin' => 'empty'],
|
||||
'destination' => [
|
||||
'plugin' => 'config',
|
||||
'config_name' => 'migrate_test.settings',
|
||||
],
|
||||
'process' => ['foo' => 'bar'],
|
||||
];
|
||||
$migration = Migration::create($configuration);
|
||||
$migration->save();
|
||||
|
||||
// Default status is idle.
|
||||
$status = $migration->getStatus();
|
||||
$this->assertIdentical($status, MigrationInterface::STATUS_IDLE);
|
||||
|
||||
// Test setting and retrieving all known status values.
|
||||
$status_list = array(
|
||||
MigrationInterface::STATUS_IDLE,
|
||||
MigrationInterface::STATUS_IMPORTING,
|
||||
MigrationInterface::STATUS_ROLLING_BACK,
|
||||
MigrationInterface::STATUS_STOPPING,
|
||||
MigrationInterface::STATUS_DISABLED,
|
||||
);
|
||||
foreach ($status_list as $status) {
|
||||
$migration->setStatus($status);
|
||||
$this->assertIdentical($migration->getStatus(), $status);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -59,7 +59,28 @@ abstract class MigrateTestBase extends KernelTestBase implements MigrateMessageI
|
|||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->createMigrationConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the database connection to the prefixed one.
|
||||
*
|
||||
* @todo Remove when we don't use global. https://www.drupal.org/node/2552791
|
||||
*/
|
||||
private function createMigrationConnection() {
|
||||
// If the backup already exists, something went terribly wrong.
|
||||
// This case is possible, because database connection info is a static
|
||||
// global state construct on the Database class, which at least persists
|
||||
// for all test methods executed in one PHP process.
|
||||
if (Database::getConnectionInfo('simpletest_original_migrate')) {
|
||||
throw new \RuntimeException("Bad Database connection state: 'simpletest_original_migrate' connection key already exists. Broken test?");
|
||||
}
|
||||
|
||||
// Clone the current connection and replace the current prefix.
|
||||
$connection_info = Database::getConnectionInfo('migrate');
|
||||
if ($connection_info) {
|
||||
Database::renameConnection('migrate', 'simpletest_original_migrate');
|
||||
}
|
||||
$connection_info = Database::getConnectionInfo('default');
|
||||
foreach ($connection_info as $target => $value) {
|
||||
$prefix = is_array($value['prefix']) ? $value['prefix']['default'] : $value['prefix'];
|
||||
|
@ -78,8 +99,24 @@ abstract class MigrateTestBase extends KernelTestBase implements MigrateMessageI
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function tearDown() {
|
||||
Database::removeConnection('migrate');
|
||||
$this->cleanupMigrateConnection();
|
||||
parent::tearDown();
|
||||
$this->databaseDumpFiles = [];
|
||||
$this->collectMessages = FALSE;
|
||||
unset($this->migration, $this->migrateMessages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the test migrate connection.
|
||||
*
|
||||
* @todo Remove when we don't use global. https://www.drupal.org/node/2552791
|
||||
*/
|
||||
private function cleanupMigrateConnection() {
|
||||
Database::removeConnection('migrate');
|
||||
$original_connection_info = Database::getConnectionInfo('simpletest_original_migrate');
|
||||
if ($original_connection_info) {
|
||||
Database::renameConnection('simpletest_original_migrate', 'migrate');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,20 +150,19 @@ abstract class MigrateTestBase extends KernelTestBase implements MigrateMessageI
|
|||
* ids.
|
||||
*/
|
||||
protected function prepareMigrations(array $id_mappings) {
|
||||
/** @var \Drupal\migrate\Entity\MigrationInterface[] $migrations */
|
||||
$migrations = entity_load_multiple('migration', array_keys($id_mappings));
|
||||
foreach ($id_mappings as $migration_id => $data) {
|
||||
$migration = $migrations[$migration_id];
|
||||
// Use loadMultiple() here in order to load all variants.
|
||||
foreach (Migration::loadMultiple([$migration_id]) as $migration) {
|
||||
// Mark the dependent migrations as complete.
|
||||
$migration->setMigrationResult(MigrationInterface::RESULT_COMPLETED);
|
||||
|
||||
// Mark the dependent migrations as complete.
|
||||
$migration->setMigrationResult(MigrationInterface::RESULT_COMPLETED);
|
||||
|
||||
$id_map = $migration->getIdMap();
|
||||
$id_map->setMessage($this);
|
||||
$source_ids = $migration->getSourcePlugin()->getIds();
|
||||
foreach ($data as $id_mapping) {
|
||||
$row = new Row(array_combine(array_keys($source_ids), $id_mapping[0]), $source_ids);
|
||||
$id_map->saveIdMapping($row, $id_mapping[1]);
|
||||
$id_map = $migration->getIdMap();
|
||||
$id_map->setMessage($this);
|
||||
$source_ids = $migration->getSourcePlugin()->getIds();
|
||||
foreach ($data as $id_mapping) {
|
||||
$row = new Row(array_combine(array_keys($source_ids), $id_mapping[0]), $source_ids);
|
||||
$id_map->saveIdMapping($row, $id_mapping[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
45
core/modules/migrate/src/Tests/MigrationTest.php
Normal file
45
core/modules/migrate/src/Tests/MigrationTest.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate\Tests;
|
||||
|
||||
use Drupal\migrate\Entity\Migration;
|
||||
use Drupal\simpletest\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests the migration entity.
|
||||
*
|
||||
* @group migrate
|
||||
* @coversDefaultClass \Drupal\migrate\Entity\Migration
|
||||
*/
|
||||
class MigrationTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Enable field because we're using one of its source plugins.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['migrate', 'field'];
|
||||
|
||||
/**
|
||||
* Tests Migration::set()
|
||||
*
|
||||
* @covers ::set()
|
||||
*/
|
||||
public function testSetInvalidation() {
|
||||
$migration = Migration::create([
|
||||
'source' => ['plugin' => 'empty'],
|
||||
'destination' => ['plugin' => 'entity:entity_view_mode'],
|
||||
]);
|
||||
$this->assertEqual('empty', $migration->getSourcePlugin()->getPluginId());
|
||||
$this->assertEqual('entity:entity_view_mode', $migration->getDestinationPlugin()->getPluginId());
|
||||
|
||||
// Test the source plugin is invalidated.
|
||||
$migration->set('source', ['plugin' => 'd6_field']);
|
||||
$this->assertEqual('d6_field', $migration->getSourcePlugin()->getPluginId());
|
||||
|
||||
// Test the destination plugin is invalidated.
|
||||
$migration->set('destination', ['plugin' => 'null']);
|
||||
$this->assertEqual('null', $migration->getDestinationPlugin()->getPluginId());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
name: 'Migrate events test'
|
||||
type: module
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate_events_test\Plugin\migrate\destination\DummyDestination.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate_events_test\Plugin\migrate\destination;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Plugin\migrate\destination\DestinationBase;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* @MigrateDestination(
|
||||
* id = "dummy",
|
||||
* requirements_met = true
|
||||
* )
|
||||
*/
|
||||
class DummyDestination extends DestinationBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['value']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields(MigrationInterface $migration = NULL) {
|
||||
return ['value' => 'Dummy value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function import(Row $row, array $old_destination_id_values = array()) {
|
||||
return ['value' => $row->getDestinationProperty('value')];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
name: 'Migrate module prepareRow tests'
|
||||
type: module
|
||||
description: 'Support module for source plugin prepareRow testing.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test module for testing the migration source plugin prepareRow() exception
|
||||
* handling.
|
||||
*/
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
use Drupal\migrate\Plugin\MigrateSourceInterface;
|
||||
use Drupal\migrate\Row;
|
||||
|
||||
/**
|
||||
* Implements hook_migrate_prepare_row().
|
||||
*/
|
||||
function migrate_prepare_row_test_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) {
|
||||
// Test both options for save_to_map.
|
||||
$data = $row->getSourceProperty('data');
|
||||
if ($data == 'skip_and_record') {
|
||||
throw new MigrateSkipRowException('', TRUE);
|
||||
}
|
||||
elseif ($data == 'skip_and_dont_record') {
|
||||
throw new MigrateSkipRowException('', FALSE);
|
||||
}
|
||||
}
|
|
@ -50,11 +50,9 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
parent::setUp();
|
||||
$this->migration = $this->getMigration();
|
||||
$this->message = $this->getMock('Drupal\migrate\MigrateMessageInterface');
|
||||
|
||||
$this->executable = new TestMigrateExecutable($this->migration, $this->message);
|
||||
$event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||
$this->executable = new TestMigrateExecutable($this->migration, $this->message, $event_dispatcher);
|
||||
$this->executable->setStringTranslation($this->getStringTranslationStub());
|
||||
$this->executable->setTimeThreshold(0.1);
|
||||
$this->executable->limit = array('unit' => 'second', 'value' => 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,11 +118,6 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
->will($this->returnValue($destination));
|
||||
|
||||
$this->assertSame(MigrationInterface::RESULT_COMPLETED, $this->executable->import());
|
||||
|
||||
$this->assertSame(1, $this->executable->getSuccessesSinceFeedback());
|
||||
$this->assertSame(1, $this->executable->getTotalSuccesses());
|
||||
$this->assertSame(1, $this->executable->getTotalProcessed());
|
||||
$this->assertSame(1, $this->executable->getProcessedSinceFeedback());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,11 +163,6 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
->method('saveIdMapping');
|
||||
|
||||
$this->assertSame(MigrationInterface::RESULT_COMPLETED, $this->executable->import());
|
||||
|
||||
$this->assertSame(1, $this->executable->getSuccessesSinceFeedback());
|
||||
$this->assertSame(1, $this->executable->getTotalSuccesses());
|
||||
$this->assertSame(1, $this->executable->getTotalProcessed());
|
||||
$this->assertSame(1, $this->executable->getProcessedSinceFeedback());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -346,44 +334,6 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
$this->assertSame(MigrationInterface::RESULT_COMPLETED, $this->executable->import());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests time limit option method.
|
||||
*/
|
||||
public function testTimeOptionExceeded() {
|
||||
// Assert time limit of one second (test configuration default) is exceeded.
|
||||
$this->executable->setTimeElapsed(1);
|
||||
$this->assertTrue($this->executable->timeOptionExceeded());
|
||||
// Assert time limit not exceeded.
|
||||
$this->executable->limit = array('unit' => 'seconds', 'value' => (int) $_SERVER['REQUEST_TIME'] - 3600);
|
||||
$this->assertFalse($this->executable->timeOptionExceeded());
|
||||
// Assert no time limit.
|
||||
$this->executable->limit = array();
|
||||
$this->assertFalse($this->executable->timeOptionExceeded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests get time limit method.
|
||||
*/
|
||||
public function testGetTimeLimit() {
|
||||
// Assert time limit has a unit of one second (test configuration default).
|
||||
$limit = $this->executable->limit;
|
||||
$this->assertArrayHasKey('unit', $limit);
|
||||
$this->assertSame('second', $limit['unit']);
|
||||
$this->assertSame($limit['value'], $this->executable->getTimeLimit());
|
||||
// Assert time limit has a unit of multiple seconds.
|
||||
$this->executable->limit = array('unit' => 'seconds', 'value' => 30);
|
||||
$limit = $this->executable->limit;
|
||||
$this->assertArrayHasKey('unit', $limit);
|
||||
$this->assertSame('seconds', $limit['unit']);
|
||||
$this->assertSame($limit['value'], $this->executable->getTimeLimit());
|
||||
// Assert no time limit.
|
||||
$this->executable->limit = array();
|
||||
$limit = $this->executable->limit;
|
||||
$this->assertArrayNotHasKey('unit', $limit);
|
||||
$this->assertArrayNotHasKey('value', $limit);
|
||||
$this->assertNull($this->executable->getTimeLimit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests saving of queued messages.
|
||||
*/
|
||||
|
@ -435,22 +385,6 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
$this->assertAttributeEquals($expected_messages, 'queuedMessages', $this->executable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests maximum execution time (max_execution_time) of an import.
|
||||
*/
|
||||
public function testMaxExecTimeExceeded() {
|
||||
// Assert no max_execution_time value.
|
||||
$this->executable->setMaxExecTime(0);
|
||||
$this->assertFalse($this->executable->maxExecTimeExceeded());
|
||||
// Assert default max_execution_time value does not exceed.
|
||||
$this->executable->setMaxExecTime(30);
|
||||
$this->assertFalse($this->executable->maxExecTimeExceeded());
|
||||
// Assert max_execution_time value is exceeded.
|
||||
$this->executable->setMaxExecTime(1);
|
||||
$this->executable->setTimeElapsed(2);
|
||||
$this->assertTrue($this->executable->maxExecTimeExceeded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the processRow method.
|
||||
*/
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\Tests\migrate\Unit;
|
||||
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
|
@ -139,10 +140,12 @@ class MigrateSourceTest extends MigrateTestCase {
|
|||
* Test that the source count is correct.
|
||||
*/
|
||||
public function testCount() {
|
||||
|
||||
// Mock the cache to validate set() receives appropriate arguments.
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('cache.migrate', 'Drupal\Core\Cache\NullBackend')
|
||||
->setArguments(['migrate']);
|
||||
$cache = $this->getMock(CacheBackendInterface::class);
|
||||
$cache->expects($this->any())->method('set')
|
||||
->with($this->isType('string'), $this->isType('int'), $this->isType('int'));
|
||||
$container->set('cache.migrate', $cache);
|
||||
\Drupal::setContainer($container);
|
||||
|
||||
// Test that the basic count works.
|
||||
|
@ -168,16 +171,6 @@ class MigrateSourceTest extends MigrateTestCase {
|
|||
$this->assertNull($source->current(), 'No row is available when prepareRow() is false.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the when a source id is in the idList, we don't get a row.
|
||||
*/
|
||||
public function testIdInList() {
|
||||
$source = $this->getSource([], ['idlist' => ['test_sourceid1']]);
|
||||
$source->rewind();
|
||||
|
||||
$this->assertNull($source->current(), 'No row is available because id was in idList.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that $row->needsUpdate() works as expected.
|
||||
*/
|
||||
|
@ -238,8 +231,11 @@ class MigrateSourceTest extends MigrateTestCase {
|
|||
* The migrate executable.
|
||||
*/
|
||||
protected function getMigrateExecutable($migration) {
|
||||
/** @var \Drupal\migrate\MigrateMessageInterface $message */
|
||||
$message = $this->getMock('Drupal\migrate\MigrateMessageInterface');
|
||||
return new MigrateExecutable($migration, $message);
|
||||
/** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
|
||||
$event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||
return new MigrateExecutable($migration, $message, $event_dispatcher);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -181,31 +181,33 @@ class MigrateSqlIdMapEnsureTablesTest extends MigrateTestCase {
|
|||
->getMock();
|
||||
$database->expects($this->any())
|
||||
->method('schema')
|
||||
->will($this->returnValue($schema));
|
||||
->willReturn($schema);
|
||||
$migration = $this->getMigration();
|
||||
$plugin = $this->getMock('Drupal\migrate\Plugin\MigrateSourceInterface');
|
||||
$plugin->expects($this->any())
|
||||
->method('getIds')
|
||||
->will($this->returnValue(array(
|
||||
->willReturn(array(
|
||||
'source_id_property' => array(
|
||||
'type' => 'integer',
|
||||
),
|
||||
)));
|
||||
));
|
||||
$migration->expects($this->any())
|
||||
->method('getSourcePlugin')
|
||||
->will($this->returnValue($plugin));
|
||||
->willReturn($plugin);
|
||||
$plugin = $this->getMock('Drupal\migrate\Plugin\MigrateSourceInterface');
|
||||
$plugin->expects($this->any())
|
||||
->method('getIds')
|
||||
->will($this->returnValue(array(
|
||||
->willReturn(array(
|
||||
'destination_id_property' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
)));
|
||||
));
|
||||
$migration->expects($this->any())
|
||||
->method('getDestinationPlugin')
|
||||
->will($this->returnValue($plugin));
|
||||
$map = new TestSqlIdMap($database, array(), 'sql', array(), $migration);
|
||||
->willReturn($plugin);
|
||||
/** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher */
|
||||
$event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||
$map = new TestSqlIdMap($database, array(), 'sql', array(), $migration, $event_dispatcher);
|
||||
$map->getDatabase();
|
||||
}
|
||||
|
||||
|
|
|
@ -102,8 +102,9 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
$migration
|
||||
->method('getDestinationPlugin')
|
||||
->willReturn($plugin);
|
||||
$event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||
|
||||
$id_map = new TestSqlIdMap($this->database, [], 'sql', [], $migration);
|
||||
$id_map = new TestSqlIdMap($this->database, [], 'sql', [], $migration, $event_dispatcher);
|
||||
$migration
|
||||
->method('getIdMap')
|
||||
->willReturn($id_map);
|
||||
|
@ -286,25 +287,34 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
|
||||
foreach ($expected_results as $key => $expected_result) {
|
||||
$id_map->saveMessage([$key], $message, $expected_result['level']);
|
||||
$message_row = $this->database->select($id_map->messageTableName(), 'message')
|
||||
->fields('message')
|
||||
->condition('level', $expected_result['level'])
|
||||
->condition('message', $expected_result['message'])
|
||||
->execute()
|
||||
->fetchAssoc();
|
||||
$this->assertEquals($expected_result['message'], $message_row['message'], 'Message from database was read.');
|
||||
}
|
||||
|
||||
foreach ($id_map->getMessageIterator() as $message_row) {
|
||||
$key = $message_row->sourceid1;
|
||||
$this->assertEquals($expected_results[$key]['message'], $message_row->message);
|
||||
$this->assertEquals($expected_results[$key]['level'], $message_row->level);
|
||||
}
|
||||
|
||||
// Insert with default level.
|
||||
$message_default = 'Hello world default.';
|
||||
$id_map->saveMessage([5], $message_default);
|
||||
$message_row = $this->database->select($id_map->messageTableName(), 'message')
|
||||
->fields('message')
|
||||
->condition('level', MigrationInterface::MESSAGE_ERROR)
|
||||
->condition('message', $message_default)
|
||||
->execute()
|
||||
->fetchAssoc();
|
||||
$this->assertEquals($message_default, $message_row['message'], 'Message from database was read.');
|
||||
$messages = $id_map->getMessageIterator([5]);
|
||||
$count = 0;
|
||||
foreach ($messages as $key => $message_row) {
|
||||
$count = 1;
|
||||
$this->assertEquals($message_default, $message_row->message);
|
||||
$this->assertEquals(MigrationInterface::MESSAGE_ERROR, $message_row->level);
|
||||
}
|
||||
$this->assertEquals($count, 1);
|
||||
|
||||
// Retrieve messages with a specific level.
|
||||
$messages = $id_map->getMessageIterator([], MigrationInterface::MESSAGE_WARNING);
|
||||
$count = 0;
|
||||
foreach ($messages as $key => $message_row) {
|
||||
$count = 1;
|
||||
$this->assertEquals(MigrationInterface::MESSAGE_WARNING, $message_row->level);
|
||||
}
|
||||
$this->assertEquals($count, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Drupal\Tests\migrate\Unit;
|
|||
|
||||
use Drupal\Core\Database\Driver\sqlite\Connection;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -18,6 +19,13 @@ abstract class MigrateTestCase extends UnitTestCase {
|
|||
|
||||
protected $migrationConfiguration = [];
|
||||
|
||||
/**
|
||||
* Local store for mocking setStatus()/getStatus().
|
||||
*
|
||||
* @var \Drupal\migrate\Entity\MigrationInterface::STATUS_*
|
||||
*/
|
||||
protected $migrationStatus = MigrationInterface::STATUS_IDLE;
|
||||
|
||||
/**
|
||||
* Retrieve a mocked migration.
|
||||
*
|
||||
|
@ -28,29 +36,54 @@ abstract class MigrateTestCase extends UnitTestCase {
|
|||
$this->migrationConfiguration += ['migrationClass' => 'Drupal\migrate\Entity\Migration'];
|
||||
$this->idMap = $this->getMock('Drupal\migrate\Plugin\MigrateIdMapInterface');
|
||||
|
||||
$this->idMap->expects($this->any())
|
||||
$this->idMap
|
||||
->method('getQualifiedMapTableName')
|
||||
->will($this->returnValue('test_map'));
|
||||
->willReturn('test_map');
|
||||
|
||||
$migration = $this->getMockBuilder($this->migrationConfiguration['migrationClass'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$migration->method('checkRequirements')
|
||||
->willReturn(TRUE);
|
||||
|
||||
$migration->method('getIdMap')
|
||||
->willReturn($this->idMap);
|
||||
|
||||
// We need the state to be toggled throughout the test so we store the value
|
||||
// on the test class and use a return callback.
|
||||
$migration->expects($this->any())
|
||||
->method('checkRequirements')
|
||||
->will($this->returnValue(TRUE));
|
||||
->method('getStatus')
|
||||
->willReturnCallback(function() {
|
||||
return $this->migrationStatus;
|
||||
});
|
||||
$migration->expects($this->any())
|
||||
->method('getIdMap')
|
||||
->will($this->returnValue($this->idMap));
|
||||
->method('setStatus')
|
||||
->willReturnCallback(function($status) {
|
||||
$this->migrationStatus = $status;
|
||||
});
|
||||
|
||||
$migration->method('getMigrationDependencies')
|
||||
->willReturn([
|
||||
'required' => [],
|
||||
'optional' => [],
|
||||
]);
|
||||
|
||||
$configuration = &$this->migrationConfiguration;
|
||||
$migration->expects($this->any())->method('get')->will($this->returnCallback(function ($argument) use (&$configuration) {
|
||||
return isset($configuration[$argument]) ? $configuration[$argument] : '';
|
||||
}));
|
||||
$migration->expects($this->any())->method('set')->will($this->returnCallback(function ($argument, $value) use (&$configuration) {
|
||||
|
||||
$migration->method('get')
|
||||
->willReturnCallback(function ($argument) use (&$configuration) {
|
||||
return isset($configuration[$argument]) ? $configuration[$argument] : '';
|
||||
});
|
||||
|
||||
$migration->method('set')
|
||||
->willReturnCallback(function ($argument, $value) use (&$configuration) {
|
||||
$configuration[$argument] = $value;
|
||||
}));
|
||||
$migration->expects($this->any())
|
||||
->method('id')
|
||||
->will($this->returnValue($configuration['id']));
|
||||
});
|
||||
|
||||
$migration->method('id')
|
||||
->willReturn($configuration['id']);
|
||||
|
||||
return $migration;
|
||||
}
|
||||
|
||||
|
|
112
core/modules/migrate/tests/src/Unit/MigrationStorageTest.php
Normal file
112
core/modules/migrate/tests/src/Unit/MigrationStorageTest.php
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\migrate\Unit\MigrationStorageTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\migrate\Unit;
|
||||
|
||||
use Drupal\Component\Uuid\UuidInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\Query\QueryFactoryInterface;
|
||||
use Drupal\Core\Entity\Query\QueryInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\migrate\MigrationStorage;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\migrate\MigrationStorage
|
||||
* @group migrate
|
||||
*/
|
||||
class MigrationStorageTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\Tests\migrate\Unit\TestMigrationStorage
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\Query\QueryInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $query;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->query = $this->getMock(QueryInterface::class);
|
||||
$this->query->method('condition')
|
||||
->willReturnSelf();
|
||||
|
||||
$query_factory = $this->getMock(QueryFactoryInterface::class);
|
||||
$query_factory->method('get')
|
||||
->willReturn($this->query);
|
||||
|
||||
$this->storage = new TestMigrationStorage(
|
||||
$this->getMock(EntityTypeInterface::class),
|
||||
$this->getMock(ConfigFactoryInterface::class),
|
||||
$this->getMock(UuidInterface::class),
|
||||
$this->getMock(LanguageManagerInterface::class),
|
||||
$query_factory
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getVariantIds() when variants exist.
|
||||
*
|
||||
* @covers ::getVariantIds
|
||||
*/
|
||||
public function testGetVariantIdsWithVariants() {
|
||||
$this->query->method('execute')
|
||||
->willReturn(['d6_node__page', 'd6_node__article']);
|
||||
|
||||
$ids = $this->storage->getVariantIds(['d6_node:*', 'd6_user']);
|
||||
$this->assertSame(['d6_node__page', 'd6_node__article', 'd6_user'], $ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getVariantIds() when no variants exist.
|
||||
*
|
||||
* @covers ::getVariantIds
|
||||
*/
|
||||
public function testGetVariantIdsNoVariants() {
|
||||
$this->query->method('execute')
|
||||
->willReturn([]);
|
||||
|
||||
$ids = $this->storage->getVariantIds(['d6_node:*', 'd6_user']);
|
||||
$this->assertSame(['d6_user'], $ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getVariantIds() when no variants exist and there are no static
|
||||
* (non-variant) dependencies.
|
||||
*
|
||||
* @covers ::getVariantIds
|
||||
*/
|
||||
public function testGetVariantIdsNoVariantsOrStaticDependencies() {
|
||||
$this->query->method('execute')
|
||||
->willReturn([]);
|
||||
|
||||
$ids = $this->storage->getVariantIds(['d6_node:*', 'd6_node_revision:*']);
|
||||
$this->assertSame([], $ids);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test version of \Drupal\migrate\MigrationStorage.
|
||||
*
|
||||
* Exposes protected methods for testing.
|
||||
*/
|
||||
class TestMigrationStorage extends MigrationStorage {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVariantIds(array $ids) {
|
||||
return parent::getVariantIds($ids);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,13 +15,6 @@ use Drupal\migrate\MigrateExecutable;
|
|||
*/
|
||||
class TestMigrateExecutable extends MigrateExecutable {
|
||||
|
||||
/**
|
||||
* The (fake) number of seconds elapsed since the start of the test.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $timeElapsed;
|
||||
|
||||
/**
|
||||
* The fake memory usage in bytes.
|
||||
*
|
||||
|
@ -46,86 +39,6 @@ class TestMigrateExecutable extends MigrateExecutable {
|
|||
$this->stringTranslation = $string_translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows access to protected timeOptionExceeded method.
|
||||
*
|
||||
* @return bool
|
||||
* A threshold exceeded value.
|
||||
*/
|
||||
public function timeOptionExceeded() {
|
||||
return parent::timeOptionExceeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows access to set protected maxExecTime property.
|
||||
*
|
||||
* @param int $max_exec_time
|
||||
* The value to set.
|
||||
*/
|
||||
public function setMaxExecTime($max_exec_time) {
|
||||
$this->maxExecTime = $max_exec_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows access to protected maxExecTime property.
|
||||
*
|
||||
* @return int
|
||||
* The value of the protected property.
|
||||
*/
|
||||
public function getMaxExecTime() {
|
||||
return $this->maxExecTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows access to protected successesSinceFeedback property.
|
||||
*
|
||||
* @return int
|
||||
* The value of the protected property.
|
||||
*/
|
||||
public function getSuccessesSinceFeedback() {
|
||||
return $this->successesSinceFeedback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows access to protected totalSuccesses property.
|
||||
*
|
||||
* @return int
|
||||
* The value of the protected property.
|
||||
*/
|
||||
public function getTotalSuccesses() {
|
||||
return $this->totalSuccesses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows access to protected totalProcessed property.
|
||||
*
|
||||
* @return int
|
||||
* The value of the protected property.
|
||||
*/
|
||||
public function getTotalProcessed() {
|
||||
return $this->totalProcessed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows access to protected processedSinceFeedback property.
|
||||
*
|
||||
* @return int
|
||||
* The value of the protected property.
|
||||
*/
|
||||
public function getProcessedSinceFeedback() {
|
||||
return $this->processedSinceFeedback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows access to protected maxExecTimeExceeded method.
|
||||
*
|
||||
* @return bool
|
||||
* The threshold exceeded value.
|
||||
*/
|
||||
public function maxExecTimeExceeded() {
|
||||
return parent::maxExecTimeExceeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows access to set protected source property.
|
||||
*
|
||||
|
@ -146,23 +59,6 @@ class TestMigrateExecutable extends MigrateExecutable {
|
|||
$this->sourceIdValues = $source_id_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows setting a fake elapsed time.
|
||||
*
|
||||
* @param int $time
|
||||
* The time in seconds.
|
||||
*/
|
||||
public function setTimeElapsed($time) {
|
||||
$this->timeElapsed = $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTimeElapsed() {
|
||||
return $this->timeElapsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -231,16 +127,6 @@ class TestMigrateExecutable extends MigrateExecutable {
|
|||
$this->memoryThreshold = $threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time threshold.
|
||||
*
|
||||
* @param float $threshold
|
||||
* The new threshold.
|
||||
*/
|
||||
public function setTimeThreshold($threshold) {
|
||||
$this->timeThreshold = $threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -11,6 +11,7 @@ use Drupal\Core\Database\Connection;
|
|||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Plugin\migrate\id_map\Sql;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* Defines a SQL ID map for use in tests.
|
||||
|
@ -31,9 +32,9 @@ class TestSqlIdMap extends Sql implements \Iterator {
|
|||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* The migration to do.
|
||||
*/
|
||||
public function __construct(Connection $database, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
|
||||
public function __construct(Connection $database, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EventDispatcherInterface $event_dispatcher) {
|
||||
$this->database = $database;
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $event_dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,4 +51,13 @@ class ExtractTest extends MigrateProcessTestCase {
|
|||
$this->plugin->transform(array('bar' => 'foo'), $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests unsuccessful extraction.
|
||||
*/
|
||||
public function testExtractFailDefault() {
|
||||
$plugin = new Extract(['index' => ['foo'], 'default' => 'test'], 'map', []);
|
||||
$value = $plugin->transform(['bar' => 'foo'], $this->migrateExecutable, $this->row, 'destinationproperty');
|
||||
$this->assertSame($value, 'test', '');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,7 +61,8 @@ class IteratorTest extends MigrateTestCase {
|
|||
$migration->expects($this->at(2))
|
||||
->method('getProcessPlugins')
|
||||
->will($this->returnValue($key_plugin));
|
||||
$migrate_executable = new MigrateExecutable($migration, $this->getMock('Drupal\migrate\MigrateMessageInterface'));
|
||||
$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 = array(
|
||||
|
|
Reference in a new issue