Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663
This commit is contained in:
parent
eb34d130a8
commit
f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions
|
@ -4,4 +4,3 @@ description: 'Handles migrations'
|
|||
package: Core (Experimental)
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
;configure: admin/structure/migrate
|
||||
|
|
|
@ -15,7 +15,7 @@ function migrate_help($route_name, RouteMatchInterface $route_match) {
|
|||
case 'help.page.migrate':
|
||||
$output = '<h3>' . t('About') . '</h3>';
|
||||
$output .= '<p>';
|
||||
$output .= t('The Migrate module provides a framework for migrating data, usually from an external source into your site. It does not provide a user interface. For more information, see the <a href="!migrate">online documentation for the Migrate module</a>.', array('!migrate' => 'https://www.drupal.org/documentation/modules/migrate'));
|
||||
$output .= t('The Migrate module provides a framework for migrating data, usually from an external source into your site. It does not provide a user interface. For more information, see the <a href=":migrate">online documentation for the Migrate module</a>.', array(':migrate' => 'https://www.drupal.org/documentation/modules/migrate'));
|
||||
$output .= '</p>';
|
||||
return $output;
|
||||
}
|
||||
|
|
|
@ -83,13 +83,6 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
|
|||
*/
|
||||
protected $process;
|
||||
|
||||
/**
|
||||
* The configuration describing the load plugins.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $load;
|
||||
|
||||
/**
|
||||
* The cached process plugins.
|
||||
*
|
||||
|
@ -394,7 +387,7 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
|
|||
$missing_migrations = array_diff($this->requirements, array_keys($required_migrations));
|
||||
// Check if the dependencies are in good shape.
|
||||
foreach ($required_migrations as $migration_id => $required_migration) {
|
||||
if (!$required_migration->isComplete()) {
|
||||
if (!$required_migration->allRowsProcessed()) {
|
||||
$missing_migrations[] = $migration_id;
|
||||
}
|
||||
}
|
||||
|
@ -446,15 +439,15 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMigrationResult($result) {
|
||||
\Drupal::keyValue('migrate_result')->set($this->id(), $result);
|
||||
public function getInterruptionResult() {
|
||||
return \Drupal::keyValue('migrate_interruption_result')->get($this->id(), static::RESULT_INCOMPLETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMigrationResult() {
|
||||
return \Drupal::keyValue('migrate_result')->get($this->id(), static::RESULT_INCOMPLETE);
|
||||
public function clearInterruptionResult() {
|
||||
\Drupal::keyValue('migrate_interruption_result')->delete($this->id());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -462,14 +455,24 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
|
|||
*/
|
||||
public function interruptMigration($result) {
|
||||
$this->setStatus(MigrationInterface::STATUS_STOPPING);
|
||||
$this->setMigrationResult($result);
|
||||
\Drupal::keyValue('migrate_interruption_result')->set($this->id(), $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isComplete() {
|
||||
return $this->getMigrationResult() === static::RESULT_COMPLETED;
|
||||
public function allRowsProcessed() {
|
||||
$source_count = $this->getSourcePlugin()->count();
|
||||
// If the source is uncountable, we have no way of knowing if it's
|
||||
// complete, so stipulate that it is.
|
||||
if ($source_count < 0) {
|
||||
return TRUE;
|
||||
}
|
||||
$processed_count = $this->getIdMap()->processedCount();
|
||||
// We don't use == because in some circumstances (like unresolved stubs
|
||||
// being created), the processed count may be higher than the available
|
||||
// source rows.
|
||||
return $source_count <= $processed_count;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -587,6 +590,6 @@ class Migration extends ConfigEntityBase implements MigrationInterface, Requirem
|
|||
$this->addDependency('config', $this->getEntityType()->getConfigPrefix() . '.' . $dependency);
|
||||
}
|
||||
|
||||
return $this->dependencies;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,12 +159,12 @@ interface MigrationInterface extends ConfigEntityInterface {
|
|||
public function saveHighWater($high_water);
|
||||
|
||||
/**
|
||||
* Check if this migration is complete.
|
||||
* Check if all source rows from this migration have been processed.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if this migration is complete otherwise FALSE.
|
||||
*/
|
||||
public function isComplete();
|
||||
public function allRowsProcessed();
|
||||
|
||||
/**
|
||||
* Set the current migration status.
|
||||
|
@ -191,20 +191,17 @@ interface MigrationInterface extends ConfigEntityInterface {
|
|||
public function getStatusLabel();
|
||||
|
||||
/**
|
||||
* Set the migration result.
|
||||
*
|
||||
* @param int $result
|
||||
* One of the RESULT_* constants.
|
||||
*/
|
||||
public function setMigrationResult($result);
|
||||
|
||||
/**
|
||||
* Get the current migration result.
|
||||
* Get the result to return upon interruption.
|
||||
*
|
||||
* @return int
|
||||
* The current migration result. Defaults to RESULT_INCOMPLETE.
|
||||
* The current interruption result. Defaults to RESULT_INCOMPLETE.
|
||||
*/
|
||||
public function getMigrationResult();
|
||||
public function getInterruptionResult();
|
||||
|
||||
/**
|
||||
* Clears the result to return upon interruption.
|
||||
*/
|
||||
public function clearInterruptionResult();
|
||||
|
||||
/**
|
||||
* Signal that the migration should be interrupted with the specified result
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace Drupal\migrate\Event;
|
|||
* @see \Drupal\migrate\Event\MigrateImportEvent
|
||||
* @see \Drupal\migrate\Event\MigratePreRowSaveEvent
|
||||
* @see \Drupal\migrate\Event\MigratePostRowSaveEvent
|
||||
* @see \Drupal\migrate\Event\MigrateRollbackEvent
|
||||
* @see \Drupal\migrate\Event\MigrateRowDeleteEvent
|
||||
*/
|
||||
final class MigrateEvents {
|
||||
|
||||
|
@ -108,4 +110,64 @@ final class MigrateEvents {
|
|||
*/
|
||||
const POST_ROW_SAVE = 'migrate.post_row_save';
|
||||
|
||||
/**
|
||||
* Name of the event fired when beginning a migration rollback operation.
|
||||
*
|
||||
* This event allows modules to perform an action whenever a migration
|
||||
* rollback operation is about to begin. The event listener method receives a
|
||||
* \Drupal\migrate\Event\MigrateRollbackEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigrateRollbackEvent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PRE_ROLLBACK = 'migrate.pre_rollback';
|
||||
|
||||
/**
|
||||
* Name of the event fired when finishing a migration rollback operation.
|
||||
*
|
||||
* This event allows modules to perform an action whenever a migration
|
||||
* rollback operation is completing. The event listener method receives a
|
||||
* \Drupal\migrate\Event\MigrateRollbackEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigrateRollbackEvent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const POST_ROLLBACK = 'migrate.post_rollback';
|
||||
|
||||
/**
|
||||
* Name of the event fired when about to delete a single item.
|
||||
*
|
||||
* This event allows modules to perform an action whenever a specific item
|
||||
* is about to be deleted by the destination plugin. The event listener method
|
||||
* receives a \Drupal\migrate\Event\MigrateRowDeleteEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigrateRowDeleteEvent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PRE_ROW_DELETE = 'migrate.pre_row_delete';
|
||||
|
||||
/**
|
||||
* Name of the event fired just after a single item has been deleted.
|
||||
*
|
||||
* This event allows modules to perform an action whenever a specific item
|
||||
* has been deleted by the destination plugin. The event listener method
|
||||
* receives a \Drupal\migrate\Event\MigrateRowDeleteEvent instance.
|
||||
*
|
||||
* @Event
|
||||
*
|
||||
* @see \Drupal\migrate\Event\MigrateRowDeleteEvent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const POST_ROW_DELETE = 'migrate.post_row_delete';
|
||||
|
||||
}
|
||||
|
|
45
core/modules/migrate/src/Event/MigrateRollbackEvent.php
Normal file
45
core/modules/migrate/src/Event/MigrateRollbackEvent.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Event\MigrateRollbackEvent.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Event;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Wraps a pre- or post-rollback event for event listeners.
|
||||
*/
|
||||
class MigrateRollbackEvent extends Event {
|
||||
|
||||
/**
|
||||
* Migration entity.
|
||||
*
|
||||
* @var \Drupal\migrate\Entity\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* Constructs an rollback 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/MigrateRowDeleteEvent.php
Normal file
65
core/modules/migrate/src/Event/MigrateRowDeleteEvent.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Event\MigrateRowDeleteEvent.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Event;
|
||||
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Wraps a row deletion event for event listeners.
|
||||
*/
|
||||
class MigrateRowDeleteEvent extends Event {
|
||||
|
||||
/**
|
||||
* Migration entity.
|
||||
*
|
||||
* @var \Drupal\migrate\Entity\MigrationInterface
|
||||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* Values representing the destination ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $destinationIdValues;
|
||||
|
||||
/**
|
||||
* Constructs a row deletion event object.
|
||||
*
|
||||
* @param \Drupal\migrate\Entity\MigrationInterface $migration
|
||||
* Migration entity.
|
||||
* @param array $destination_id_values
|
||||
* Values represent the destination ID.
|
||||
*/
|
||||
public function __construct(MigrationInterface $migration, $destination_id_values) {
|
||||
$this->migration = $migration;
|
||||
$this->destinationIdValues = $destination_id_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the migration entity.
|
||||
*
|
||||
* @return \Drupal\migrate\Entity\MigrationInterface
|
||||
* The migration being rolled back.
|
||||
*/
|
||||
public function getMigration() {
|
||||
return $this->migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the destination ID values.
|
||||
*
|
||||
* @return array
|
||||
* The destination ID as an array.
|
||||
*/
|
||||
public function getDestinationIdValues() {
|
||||
return $this->destinationIdValues;
|
||||
}
|
||||
|
||||
}
|
|
@ -60,6 +60,10 @@ class RequirementsException extends \RuntimeException {
|
|||
public function getRequirementsString() {
|
||||
$output = '';
|
||||
foreach ($this->requirements as $requirement_type => $requirements) {
|
||||
if (!is_array($requirements)) {
|
||||
$requirements = array($requirements);
|
||||
}
|
||||
|
||||
foreach ($requirements as $value) {
|
||||
$output .= "$requirement_type: $value. ";
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ use Drupal\migrate\Event\MigrateEvents;
|
|||
use Drupal\migrate\Event\MigrateImportEvent;
|
||||
use Drupal\migrate\Event\MigratePostRowSaveEvent;
|
||||
use Drupal\migrate\Event\MigratePreRowSaveEvent;
|
||||
use Drupal\migrate\Event\MigrateRollbackEvent;
|
||||
use Drupal\migrate\Event\MigrateRowDeleteEvent;
|
||||
use Drupal\migrate\Exception\RequirementsException;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
@ -41,17 +43,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
*/
|
||||
protected $sourceRowStatus;
|
||||
|
||||
/**
|
||||
* The queued messages not yet saved.
|
||||
*
|
||||
* Each element in the array is an array with two keys:
|
||||
* - 'message': The message string.
|
||||
* - 'level': The level, a MigrationInterface::MESSAGE_* constant.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $queuedMessages = array();
|
||||
|
||||
/**
|
||||
* The ratio of the memory limit at which an operation will be interrupted.
|
||||
*
|
||||
|
@ -87,15 +78,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
*/
|
||||
protected $counts = array();
|
||||
|
||||
/**
|
||||
* The maximum number of items to pass in a single call during a rollback.
|
||||
*
|
||||
* For use in bulkRollback(). Can be overridden in derived class constructor.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $rollbackBatchSize = 50;
|
||||
|
||||
/**
|
||||
* The object currently being constructed.
|
||||
*
|
||||
|
@ -159,8 +141,8 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
break;
|
||||
default:
|
||||
$limit = PHP_INT_MAX;
|
||||
$this->message->display($this->t('Invalid PHP memory_limit !limit, setting to unlimited.',
|
||||
array('!limit' => $limit)));
|
||||
$this->message->display($this->t('Invalid PHP memory_limit @limit, setting to unlimited.',
|
||||
array('@limit' => $limit)));
|
||||
}
|
||||
}
|
||||
$this->memoryLimit = $limit;
|
||||
|
@ -178,10 +160,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
protected function getSource() {
|
||||
if (!isset($this->source)) {
|
||||
$this->source = $this->migration->getSourcePlugin();
|
||||
|
||||
// @TODO, find out how to remove this.
|
||||
// @see https://www.drupal.org/node/2443617
|
||||
$this->source->migrateExecutable = $this;
|
||||
}
|
||||
return $this->source;
|
||||
}
|
||||
|
@ -237,7 +215,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->t('Migration failed with source plugin exception: @e', array('@e' => $e->getMessage())), 'error');
|
||||
$this->migration->setStatus(MigrationInterface::STATUS_IDLE);
|
||||
return MigrationInterface::RESULT_FAILED;
|
||||
}
|
||||
|
@ -245,16 +223,17 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
$destination = $this->migration->getDestinationPlugin();
|
||||
while ($source->valid()) {
|
||||
$row = $source->current();
|
||||
if ($this->sourceIdValues = $row->getSourceIdValues()) {
|
||||
// Wipe old messages, and save any new messages.
|
||||
$id_map->delete($this->sourceIdValues, TRUE);
|
||||
$this->saveQueuedMessages();
|
||||
}
|
||||
$this->sourceIdValues = $row->getSourceIdValues();
|
||||
|
||||
try {
|
||||
$this->processRow($row);
|
||||
$save = TRUE;
|
||||
}
|
||||
catch (MigrateException $e) {
|
||||
$this->migration->getIdMap()->saveIdMapping($row, array(), $e->getStatus(), $this->rollbackAction);
|
||||
$this->saveMessage($e->getMessage(), $e->getLevel());
|
||||
$save = FALSE;
|
||||
}
|
||||
catch (MigrateSkipRowException $e) {
|
||||
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED, $this->rollbackAction);
|
||||
$save = FALSE;
|
||||
|
@ -283,7 +262,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
catch (MigrateException $e) {
|
||||
$this->migration->getIdMap()->saveIdMapping($row, array(), $e->getStatus(), $this->rollbackAction);
|
||||
$this->saveMessage($e->getMessage(), $e->getLevel());
|
||||
$this->message->display($e->getMessage(), 'error');
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$this->migration->getIdMap()->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_FAILED, $this->rollbackAction);
|
||||
|
@ -305,7 +283,8 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
|
||||
// If anyone has requested we stop, return the requested result.
|
||||
if ($this->migration->getStatus() == MigrationInterface::STATUS_STOPPING) {
|
||||
$return = $this->migration->getMigrationResult();
|
||||
$return = $this->migration->getInterruptionResult();
|
||||
$this->migration->clearInterruptionResult();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -314,19 +293,76 @@ 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->t('Migration failed with source plugin exception: @e',
|
||||
array('@e' => $e->getMessage())), 'error');
|
||||
$this->migration->setStatus(MigrationInterface::STATUS_IDLE);
|
||||
return MigrationInterface::RESULT_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
$this->migration->setMigrationResult($return);
|
||||
$this->getEventDispatcher()->dispatch(MigrateEvents::POST_IMPORT, new MigrateImportEvent($this->migration));
|
||||
$this->migration->setStatus(MigrationInterface::STATUS_IDLE);
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollback() {
|
||||
// Only begin the rollback 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', ['@id' => $this->migration->id(), '@status' => $this->t($this->migration->getStatusLabel())]), 'error');
|
||||
return MigrationInterface::RESULT_FAILED;
|
||||
}
|
||||
|
||||
// Announce that rollback is about to happen.
|
||||
$this->getEventDispatcher()->dispatch(MigrateEvents::PRE_ROLLBACK, new MigrateRollbackEvent($this->migration));
|
||||
|
||||
// Optimistically assume things are going to work out; if not, $return will be
|
||||
// updated to some other status.
|
||||
$return = MigrationInterface::RESULT_COMPLETED;
|
||||
|
||||
$this->migration->setStatus(MigrationInterface::STATUS_ROLLING_BACK);
|
||||
$id_map = $this->migration->getIdMap();
|
||||
$destination = $this->migration->getDestinationPlugin();
|
||||
|
||||
// Loop through each row in the map, and try to roll it back.
|
||||
foreach ($id_map as $map_row) {
|
||||
$destination_key = $id_map->currentDestination();
|
||||
if ($destination_key) {
|
||||
$this->getEventDispatcher()
|
||||
->dispatch(MigrateEvents::PRE_ROW_DELETE, new MigrateRowDeleteEvent($this->migration, $destination_key));
|
||||
$destination->rollback($destination_key);
|
||||
$this->getEventDispatcher()
|
||||
->dispatch(MigrateEvents::POST_ROW_DELETE, new MigrateRowDeleteEvent($this->migration, $destination_key));
|
||||
// We're now done with this row, so remove it from the map.
|
||||
$id_map->deleteDestination($destination_key);
|
||||
}
|
||||
|
||||
// Check for memory exhaustion.
|
||||
if (($return = $this->checkStatus()) != MigrationInterface::RESULT_COMPLETED) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If anyone has requested we stop, return the requested result.
|
||||
if ($this->migration->getStatus() == MigrationInterface::STATUS_STOPPING) {
|
||||
$return = $this->migration->getInterruptionResult();
|
||||
$this->migration->clearInterruptionResult();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If rollback completed successfully, reset the high water mark.
|
||||
if ($return == MigrationInterface::RESULT_COMPLETED) {
|
||||
$this->migration->saveHighWater(NULL);
|
||||
}
|
||||
|
||||
// Notify modules that rollback attempt was complete.
|
||||
$this->getEventDispatcher()->dispatch(MigrateEvents::POST_ROLLBACK, new MigrateRollbackEvent($this->migration));
|
||||
$this->migration->setStatus(MigrationInterface::STATUS_IDLE);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -395,23 +431,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
$this->migration->getIdMap()->saveMessage($this->sourceIdValues, $message, $level);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function queueMessage($message, $level = MigrationInterface::MESSAGE_ERROR) {
|
||||
$this->queuedMessages[] = array('message' => $message, 'level' => $level);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function saveQueuedMessages() {
|
||||
foreach ($this->queuedMessages as $queued_message) {
|
||||
$this->saveMessage($queued_message['message'], $queued_message['level']);
|
||||
}
|
||||
$this->queuedMessages = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an Exception object and both saves and displays it.
|
||||
*
|
||||
|
@ -458,10 +477,10 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
}
|
||||
if ($pct_memory > $threshold) {
|
||||
$this->message->display(
|
||||
$this->t('Memory usage is !usage (!pct% of limit !limit), reclaiming memory.',
|
||||
array('!pct' => round($pct_memory*100),
|
||||
'!usage' => $this->formatSize($usage),
|
||||
'!limit' => $this->formatSize($this->memoryLimit))),
|
||||
$this->t('Memory usage is @usage (@pct% of limit @limit), reclaiming memory.',
|
||||
array('@pct' => round($pct_memory*100),
|
||||
'@usage' => $this->formatSize($usage),
|
||||
'@limit' => $this->formatSize($this->memoryLimit))),
|
||||
'warning');
|
||||
$usage = $this->attemptMemoryReclaim();
|
||||
$pct_memory = $usage / $this->memoryLimit;
|
||||
|
@ -469,19 +488,19 @@ class MigrateExecutable implements MigrateExecutableInterface {
|
|||
// coming back here and trimming a tiny amount
|
||||
if ($pct_memory > (0.90 * $threshold)) {
|
||||
$this->message->display(
|
||||
$this->t('Memory usage is now !usage (!pct% of limit !limit), not enough reclaimed, starting new batch',
|
||||
array('!pct' => round($pct_memory*100),
|
||||
'!usage' => $this->formatSize($usage),
|
||||
'!limit' => $this->formatSize($this->memoryLimit))),
|
||||
$this->t('Memory usage is now @usage (@pct% of limit @limit), not enough reclaimed, starting new batch',
|
||||
array('@pct' => round($pct_memory*100),
|
||||
'@usage' => $this->formatSize($usage),
|
||||
'@limit' => $this->formatSize($this->memoryLimit))),
|
||||
'warning');
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
$this->message->display(
|
||||
$this->t('Memory usage is now !usage (!pct% of limit !limit), reclaimed enough, continuing',
|
||||
array('!pct' => round($pct_memory*100),
|
||||
'!usage' => $this->formatSize($usage),
|
||||
'!limit' => $this->formatSize($this->memoryLimit))),
|
||||
$this->t('Memory usage is now @usage (@pct% of limit @limit), reclaimed enough, continuing',
|
||||
array('@pct' => round($pct_memory*100),
|
||||
'@usage' => $this->formatSize($usage),
|
||||
'@limit' => $this->formatSize($this->memoryLimit))),
|
||||
'warning');
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,11 @@ interface MigrateExecutableInterface {
|
|||
*/
|
||||
public function import();
|
||||
|
||||
/**
|
||||
* Performs a rollback operation - remove previously-imported items.
|
||||
*/
|
||||
public function rollback();
|
||||
|
||||
/**
|
||||
* Processes a row.
|
||||
*
|
||||
|
@ -46,18 +51,4 @@ interface MigrateExecutableInterface {
|
|||
*/
|
||||
public function saveMessage($message, $level = MigrationInterface::MESSAGE_ERROR);
|
||||
|
||||
/**
|
||||
* Queues messages to be later saved through the map class.
|
||||
*
|
||||
* @param string $message
|
||||
* The message to record.
|
||||
* @param int $level
|
||||
* (optional) Message severity (defaults to MESSAGE_ERROR).
|
||||
*/
|
||||
public function queueMessage($message, $level = MigrationInterface::MESSAGE_ERROR);
|
||||
|
||||
/**
|
||||
* Saves any messages we've queued up to the message table.
|
||||
*/
|
||||
public function saveQueuedMessages();
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ interface MigrateDestinationInterface extends PluginInspectionInterface {
|
|||
* Import the row.
|
||||
*
|
||||
* Derived classes must implement import(), to construct one new object
|
||||
* (pre-populated) using ID mappings in the Migration).
|
||||
* (pre-populated) using ID mappings in the Migration.
|
||||
*
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row object.
|
||||
|
@ -72,11 +72,15 @@ interface MigrateDestinationInterface extends PluginInspectionInterface {
|
|||
public function import(Row $row, array $old_destination_id_values = array());
|
||||
|
||||
/**
|
||||
* Delete the specified IDs from the target Drupal.
|
||||
* Delete the specified destination object from the target Drupal.
|
||||
*
|
||||
* @param array $destination_identifiers
|
||||
* The destination ids to delete.
|
||||
* @param array $destination_identifier
|
||||
* The ID of the destination object to delete.
|
||||
*/
|
||||
public function rollbackMultiple(array $destination_identifiers);
|
||||
public function rollback(array $destination_identifier);
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function supportsRollback();
|
||||
}
|
||||
|
|
|
@ -26,21 +26,29 @@ use Drupal\migrate\Entity\MigrationInterface;
|
|||
class MigrateDestinationPluginManager extends MigratePluginManager {
|
||||
|
||||
/**
|
||||
* The theme handler
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ThemeHandlerInterface
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $themeHandler;
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* An associative array where the keys are the enabled modules and themes.
|
||||
* Constructs a MigrateDestinationPluginManager object.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $providers;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param string $type
|
||||
* The type of the plugin: row, source, process, destination, entity_field,
|
||||
* id_map.
|
||||
* @param \Traversable $namespaces
|
||||
* An object that implements \Traversable which contains the root paths
|
||||
* keyed by the corresponding namespace to look for plugin implementations.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
|
||||
* Cache backend instance to use.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler to invoke the alter hook with.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param string $annotation
|
||||
* The annotation class name.
|
||||
*/
|
||||
public function __construct($type, \Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EntityManagerInterface $entity_manager, $annotation = 'Drupal\migrate\Annotation\MigrateDestination') {
|
||||
parent::__construct($type, $namespaces, $cache_backend, $module_handler, $annotation);
|
||||
|
|
|
@ -57,7 +57,7 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
|
|||
* Saves a message related to a source record in the migration message table.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The source identifier values of the record in error.
|
||||
* The source identifier keyed values of the record, e.g. ['nid' => 5].
|
||||
* @param string $message
|
||||
* The message to record.
|
||||
* @param int $level
|
||||
|
@ -69,7 +69,7 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
|
|||
* 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.
|
||||
* (optional) The source identifier keyed values of the record, e.g. ['nid' => 5].
|
||||
* If empty, all messages are retrieved.
|
||||
* @param int $level
|
||||
* (optional) Message severity. If NULL, retrieve messages of all severities.
|
||||
|
@ -134,7 +134,7 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
|
|||
* Deletes the map and message entries for a given source record.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The source identifier values of the record to delete.
|
||||
* The source identifier keyed values of the record, e.g. ['nid' => 5].
|
||||
* @param bool $messages_only
|
||||
* TRUE to only delete the migrate messages.
|
||||
*/
|
||||
|
@ -144,19 +144,10 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
|
|||
* Deletes the map and message table entries for a given destination row.
|
||||
*
|
||||
* @param array $destination_id_values
|
||||
* The destination identifier values we should do the deletes for.
|
||||
* The destination identifier key value pairs we should do the deletes for.
|
||||
*/
|
||||
public function deleteDestination(array $destination_id_values);
|
||||
|
||||
/**
|
||||
* Deletes the map and message entries for a set of given source records.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The identifier values of the sources we should do the deletes for. Each
|
||||
* array member is an array of identifier values for one source row.
|
||||
*/
|
||||
public function deleteBulk(array $source_id_values);
|
||||
|
||||
/**
|
||||
* Clears all messages from the map.
|
||||
*/
|
||||
|
@ -166,7 +157,7 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
|
|||
* Retrieves a row from the map table based on source identifier values.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The source identifier values of the record to retrieve.
|
||||
* The source identifier keyed values of the record, e.g. ['nid' => 5].
|
||||
*
|
||||
* @return array
|
||||
* The raw row data as an associative array.
|
||||
|
@ -177,7 +168,7 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
|
|||
* Retrieves a row by the destination identifiers.
|
||||
*
|
||||
* @param array $destination_id_values
|
||||
* The destination identifier values of the record to retrieve.
|
||||
* The destination identifier keyed values of the record, e.g. ['nid' => 5].
|
||||
*
|
||||
* @return array
|
||||
* The row(s) of data.
|
||||
|
@ -202,27 +193,36 @@ interface MigrateIdMapInterface extends \Iterator, PluginInspectionInterface {
|
|||
* (possibly multi-field) source identifier value mapped to it.
|
||||
*
|
||||
* @param array $destination_id_values
|
||||
* The destination identifier values of the record.
|
||||
* The destination identifier keyed values of the record, e.g. ['nid' => 5].
|
||||
*
|
||||
* @return array
|
||||
* The source identifier values of the record, or NULL on failure.
|
||||
* The source identifier keyed values of the record, e.g. ['nid' => 5], or
|
||||
* an empty array on failure.
|
||||
*/
|
||||
public function lookupSourceID(array $destination_id_values);
|
||||
|
||||
/**
|
||||
* Looks up the destination identifier.
|
||||
* Looks up the destination identifier corresponding to a source key.
|
||||
*
|
||||
* Given a (possibly multi-field) source identifier value, return the
|
||||
* (possibly multi-field) destination identifier value it is mapped to.
|
||||
*
|
||||
* @param array $source_id_values
|
||||
* The source identifier values of the record.
|
||||
* The source identifier keyed values of the record, e.g. ['nid' => 5].
|
||||
*
|
||||
* @return array
|
||||
* The destination identifier values of the record, or NULL on failure.
|
||||
*/
|
||||
public function lookupDestinationId(array $source_id_values);
|
||||
|
||||
/**
|
||||
* Looks up the destination identifier currently being iterated.
|
||||
*
|
||||
* @return array
|
||||
* The destination identifier values of the record, or NULL on failure.
|
||||
*/
|
||||
public function currentDestination();
|
||||
|
||||
/**
|
||||
* Removes any persistent storage used by this map.
|
||||
*
|
||||
|
|
|
@ -30,17 +30,6 @@ interface MigrateSourceInterface extends \Countable, \Iterator, PluginInspection
|
|||
*/
|
||||
public function fields();
|
||||
|
||||
/**
|
||||
* Returns the iterator that will yield the row arrays to be processed.
|
||||
*
|
||||
* @return \Iterator
|
||||
* The iterator object.
|
||||
*
|
||||
* @throws \Exception
|
||||
* Cannot obtain a valid iterator.
|
||||
*/
|
||||
public function getIterator();
|
||||
|
||||
/**
|
||||
* Add additional data to the row.
|
||||
*
|
||||
|
|
|
@ -24,7 +24,7 @@ abstract class BuilderBase extends PluginBase implements MigrateBuilderInterface
|
|||
* @param array $configuration
|
||||
* (optional) Additional configuration for the plugin.
|
||||
*
|
||||
* @return \Drupal\migrate\Plugin\MigrateSourceInterface
|
||||
* @return \Drupal\migrate\Plugin\MigrateSourceInterface|\Drupal\migrate\Plugin\RequirementsInterface
|
||||
* The fully initialized source plugin.
|
||||
*/
|
||||
protected function getSourcePlugin($plugin_id, array $configuration = []) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Plugin\migrate\destination\Config.
|
||||
|
@ -13,10 +14,8 @@ use Drupal\Core\Config\ConfigFactoryInterface;
|
|||
use Drupal\Core\Entity\DependencyTrait;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Config\Config as ConfigObject;
|
||||
|
||||
/**
|
||||
* Persist data to the config system.
|
||||
|
@ -80,19 +79,7 @@ class Config extends DestinationBase implements ContainerFactoryPluginInterface,
|
|||
}
|
||||
}
|
||||
$this->config->save();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception because config can not be rolled back.
|
||||
*
|
||||
* @param array $destination_keys
|
||||
* The array of destination ids to roll back.
|
||||
*
|
||||
* @throws \Drupal\migrate\MigrateException
|
||||
*/
|
||||
public function rollbackMultiple(array $destination_keys) {
|
||||
throw new MigrateException('Configuration can not be rolled back');
|
||||
return [$this->config->getName()];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,7 +93,8 @@ class Config extends DestinationBase implements ContainerFactoryPluginInterface,
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
return array();
|
||||
$ids['config_name']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,13 @@ use Drupal\migrate\Plugin\RequirementsInterface;
|
|||
*/
|
||||
abstract class DestinationBase extends PluginBase implements MigrateDestinationInterface, RequirementsInterface {
|
||||
|
||||
/**
|
||||
* Indicates whether the destination can be rolled back.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $supportsRollback = FALSE;
|
||||
|
||||
/**
|
||||
* The migration.
|
||||
*
|
||||
|
@ -62,8 +69,14 @@ abstract class DestinationBase extends PluginBase implements MigrateDestinationI
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollbackMultiple(array $destination_identifiers) {
|
||||
public function rollback(array $destination_identifier) {
|
||||
// By default we do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsRollback() {
|
||||
return $this->supportsRollback;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ abstract class Entity extends DestinationBase implements ContainerFactoryPluginI
|
|||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
$this->storage = $storage;
|
||||
$this->bundles = $bundles;
|
||||
$this->supportsRollback = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,12 +114,11 @@ abstract class Entity extends DestinationBase implements ContainerFactoryPluginI
|
|||
$this->updateEntity($entity, $row);
|
||||
}
|
||||
else {
|
||||
$values = $row->getDestination();
|
||||
// Stubs might not have the bundle specified.
|
||||
// Stubs might need some required fields filled in.
|
||||
if ($row->isStub()) {
|
||||
$values = $this->processStubValues($values);
|
||||
$this->processStubRow($row);
|
||||
}
|
||||
$entity = $this->storage->create($values);
|
||||
$entity = $this->storage->create($row->getDestination());
|
||||
$entity->enforceIsNew();
|
||||
}
|
||||
return $entity;
|
||||
|
@ -139,21 +139,14 @@ abstract class Entity extends DestinationBase implements ContainerFactoryPluginI
|
|||
/**
|
||||
* Process the stub values.
|
||||
*
|
||||
* @param array $values
|
||||
* An array of destination values.
|
||||
*
|
||||
* @return array
|
||||
* The processed stub values.
|
||||
* @param \Drupal\migrate\Row $row
|
||||
* The row of data.
|
||||
*/
|
||||
protected function processStubValues(array $values) {
|
||||
$values = array_intersect_key($values, $this->getIds());
|
||||
|
||||
protected function processStubRow(Row $row) {
|
||||
$bundle_key = $this->getKey('bundle');
|
||||
if ($bundle_key && !isset($values[$bundle_key])) {
|
||||
$values[$bundle_key] = reset($this->bundles);
|
||||
if ($bundle_key && empty($row->getDestinationProperty($bundle_key))) {
|
||||
$row->setDestinationProperty($bundle_key, reset($this->bundles));
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,6 +164,17 @@ abstract class Entity extends DestinationBase implements ContainerFactoryPluginI
|
|||
return $this->storage->getEntityType()->getKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rollback(array $destination_identifier) {
|
||||
// Delete the specified entity from Drupal if it exists.
|
||||
$entity = $this->storage->load(reset($destination_identifier));
|
||||
if ($entity) {
|
||||
$entity->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -43,8 +43,6 @@ class EntityContentBase extends Entity {
|
|||
* The storage for this entity type.
|
||||
* @param array $bundles
|
||||
* The list of bundles this entity type has.
|
||||
* @param \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager
|
||||
* The plugin manager.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager service.
|
||||
*/
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
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;
|
||||
|
@ -428,8 +426,8 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
public function getRowBySource(array $source_id_values) {
|
||||
$query = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map');
|
||||
foreach ($this->sourceIdFields() as $source_id) {
|
||||
$query = $query->condition("map.$source_id", array_shift($source_id_values), '=');
|
||||
foreach ($this->sourceIdFields() as $field_name => $source_id) {
|
||||
$query->condition("map.$source_id", $source_id_values[$field_name], '=');
|
||||
}
|
||||
$result = $query->execute();
|
||||
return $result->fetchAssoc();
|
||||
|
@ -441,8 +439,8 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
public function getRowByDestination(array $destination_id_values) {
|
||||
$query = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map');
|
||||
foreach ($this->destinationIdFields() as $destination_id) {
|
||||
$query = $query->condition("map.$destination_id", array_shift($destination_id_values), '=');
|
||||
foreach ($this->destinationIdFields() as $field_name => $destination_id) {
|
||||
$query->condition("map.$destination_id", $destination_id_values[$field_name], '=');
|
||||
}
|
||||
$result = $query->execute();
|
||||
return $result->fetchAssoc();
|
||||
|
@ -467,28 +465,36 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lookupSourceID(array $destination_id) {
|
||||
$query = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map', $this->sourceIdFields());
|
||||
foreach ($this->destinationIdFields() as $key_name) {
|
||||
$query = $query->condition("map.$key_name", array_shift($destination_id), '=');
|
||||
public function lookupSourceID(array $destination_id_values) {
|
||||
$source_id_fields = $this->sourceIdFields();
|
||||
$query = $this->getDatabase()->select($this->mapTableName(), 'map');
|
||||
foreach ($source_id_fields as $source_field_name => $idmap_field_name) {
|
||||
$query->addField('map', $idmap_field_name, $source_field_name);
|
||||
}
|
||||
foreach ($this->destinationIdFields() as $field_name => $destination_id) {
|
||||
$query->condition("map.$destination_id", $destination_id_values[$field_name], '=');
|
||||
}
|
||||
$result = $query->execute();
|
||||
$source_id = $result->fetchAssoc();
|
||||
return array_values($source_id ?: array());
|
||||
return $result->fetchAssoc() ?: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lookupDestinationId(array $source_id) {
|
||||
if (empty($source_id)) {
|
||||
public function lookupDestinationId(array $source_id_values) {
|
||||
if (empty($source_id_values)) {
|
||||
return array();
|
||||
}
|
||||
$query = $this->getDatabase()->select($this->mapTableName(), 'map')
|
||||
->fields('map', $this->destinationIdFields());
|
||||
foreach ($this->sourceIdFields() as $key_name) {
|
||||
$query = $query->condition("map.$key_name", array_shift($source_id), '=');
|
||||
|
||||
// When looking up the destination ID we require an array with both the
|
||||
// source key and value, e.g. ['nid' => 41]. However, the Migration process
|
||||
// plugin doesn't currently have a way to get the source key so we presume
|
||||
// the values have been passed through in the correct order.
|
||||
$have_keys = !isset($source_id_values[0]);
|
||||
foreach ($this->sourceIdFields() as $field_name => $source_id) {
|
||||
$query->condition("map.$source_id", $have_keys ? $source_id_values[$field_name] : array_shift($source_id_values), '=');
|
||||
}
|
||||
$result = $query->execute();
|
||||
$destination_id = $result->fetchAssoc();
|
||||
|
@ -507,8 +513,8 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
// A NULL key value will fail.
|
||||
if (!isset($source_id_values[$field_name])) {
|
||||
$this->message->display(t(
|
||||
'Could not save to map table due to NULL value for key field !field',
|
||||
array('!field' => $field_name)), 'error');
|
||||
'Could not save to map table due to NULL value for key field @field',
|
||||
array('@field' => $field_name)), 'error');
|
||||
return;
|
||||
}
|
||||
$keys[$key_name] = $source_id_values[$field_name];
|
||||
|
@ -544,13 +550,12 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function saveMessage(array $source_id_values, $message, $level = MigrationInterface::MESSAGE_ERROR) {
|
||||
$count = 1;
|
||||
foreach ($source_id_values as $id_value) {
|
||||
$fields['sourceid' . $count++] = $id_value;
|
||||
foreach ($this->sourceIdFields() as $field_name => $source_id) {
|
||||
// If any key value is not set, we can't save.
|
||||
if (!isset($id_value)) {
|
||||
if (!isset($source_id_values[$field_name])) {
|
||||
return;
|
||||
}
|
||||
$fields[$source_id] = $source_id_values[$field_name];
|
||||
}
|
||||
$fields['level'] = $level;
|
||||
$fields['message'] = $message;
|
||||
|
@ -565,10 +570,12 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
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);
|
||||
foreach ($this->sourceIdFields() as $field_name => $source_id) {
|
||||
if (isset($source_id_values[$field_name])) {
|
||||
$query->condition($source_id, $source_id_values[$field_name]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($level) {
|
||||
$query->condition('level', $level);
|
||||
}
|
||||
|
@ -655,13 +662,11 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
$map_query = $this->getDatabase()->delete($this->mapTableName());
|
||||
}
|
||||
$message_query = $this->getDatabase()->delete($this->messageTableName());
|
||||
$count = 1;
|
||||
foreach ($source_id_values as $id_value) {
|
||||
foreach ($this->sourceIdFields() as $field_name => $source_id) {
|
||||
if (!$messages_only) {
|
||||
$map_query->condition('sourceid' . $count, $id_value);
|
||||
$map_query->condition($source_id, $source_id_values[$field_name]);
|
||||
}
|
||||
$message_query->condition('sourceid' . $count, $id_value);
|
||||
$count++;
|
||||
$message_query->condition($source_id, $source_id_values[$field_name]);
|
||||
}
|
||||
|
||||
if (!$messages_only) {
|
||||
|
@ -675,22 +680,20 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteDestination(array $destination_id) {
|
||||
public function deleteDestination(array $destination_id_values) {
|
||||
$map_query = $this->getDatabase()->delete($this->mapTableName());
|
||||
$message_query = $this->getDatabase()->delete($this->messageTableName());
|
||||
$source_id = $this->lookupSourceID($destination_id);
|
||||
if (!empty($source_id)) {
|
||||
$count = 1;
|
||||
foreach ($destination_id as $key_value) {
|
||||
$map_query->condition('destid' . $count, $key_value);
|
||||
$count++;
|
||||
$source_id_values = $this->lookupSourceID($destination_id_values);
|
||||
if (!empty($source_id_values)) {
|
||||
foreach ($this->destinationIdFields() as $field_name => $destination_id) {
|
||||
$map_query->condition($destination_id, $destination_id_values[$field_name]);
|
||||
}
|
||||
// Notify anyone listening of the map row we're about to delete.
|
||||
$this->eventDispatcher->dispatch(MigrateEvents::MAP_DELETE, new MigrateMapDeleteEvent($this, $source_id));
|
||||
$this->eventDispatcher->dispatch(MigrateEvents::MAP_DELETE, new MigrateMapDeleteEvent($this, $source_id_values));
|
||||
$map_query->execute();
|
||||
$count = 1;
|
||||
foreach ($source_id as $key_value) {
|
||||
$message_query->condition('sourceid' . $count, $key_value);
|
||||
foreach ($this->sourceIdFields() as $field_name => $source_id) {
|
||||
$message_query->condition($source_id, $source_id_values[$field_name]);
|
||||
$count++;
|
||||
}
|
||||
$message_query->execute();
|
||||
|
@ -700,56 +703,20 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUpdate(array $source_id) {
|
||||
if (empty($source_id)) {
|
||||
public function setUpdate(array $source_id_values) {
|
||||
if (empty($source_id_values)) {
|
||||
throw new MigrateException('No source identifiers provided to update.');
|
||||
}
|
||||
$query = $this->getDatabase()
|
||||
->update($this->mapTableName())
|
||||
->fields(array('source_row_status' => MigrateIdMapInterface::STATUS_NEEDS_UPDATE));
|
||||
$count = 1;
|
||||
foreach ($source_id as $key_value) {
|
||||
$query->condition('sourceid' . $count++, $key_value);
|
||||
|
||||
foreach ($this->sourceIdFields() as $field_name => $source_id) {
|
||||
$query->condition($source_id, $source_id_values[$field_name]);
|
||||
}
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteBulk(array $source_id_values) {
|
||||
// If we have a single-column key, we can shortcut it.
|
||||
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())
|
||||
->condition('sourceid1', $sourceids, 'IN')
|
||||
->execute();
|
||||
$this->getDatabase()->delete($this->messageTableName())
|
||||
->condition('sourceid1', $sourceids, 'IN')
|
||||
->execute();
|
||||
}
|
||||
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;
|
||||
foreach ($source_id as $key_value) {
|
||||
$map_query->condition('sourceid' . $count, $key_value);
|
||||
$message_query->condition('sourceid' . $count++, $key_value);
|
||||
}
|
||||
$map_query->execute();
|
||||
$message_query->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -805,6 +772,22 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
|
|||
return serialize($this->currentKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function currentDestination() {
|
||||
if ($this->valid()) {
|
||||
$result = array();
|
||||
foreach ($this->destinationIdFields() as $destination_field_name => $idmap_field_name) {
|
||||
$result[$destination_field_name] = $this->currentRow[$idmap_field_name];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of Iterator::next().
|
||||
*
|
||||
|
|
|
@ -114,6 +114,7 @@ class Migration extends ProcessPluginBase implements ContainerFactoryPluginInter
|
|||
$destination_plugin = $migration->getDestinationPlugin(TRUE);
|
||||
// Only keep the process necessary to produce the destination ID.
|
||||
$process = $migration->get('process');
|
||||
|
||||
// We already have the source id values but need to key them for the Row
|
||||
// constructor.
|
||||
$source_ids = $migration->getSourcePlugin()->getIds();
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Drupal\migrate\Plugin\migrate\source;
|
|||
trait DummyQueryTrait {
|
||||
|
||||
/**
|
||||
* @return \Drupal\Core\Database\Query\SelectInterface
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
// Pass an arbritrary table name - the query should never be executed anyway.
|
||||
|
@ -26,4 +26,11 @@ trait DummyQueryTrait {
|
|||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -125,14 +125,6 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
*/
|
||||
protected $iterator;
|
||||
|
||||
/**
|
||||
* @TODO, find out how to remove this.
|
||||
* @see https://www.drupal.org/node/2443617
|
||||
*
|
||||
* @var MigrateExecutableInterface
|
||||
*/
|
||||
public $migrateExecutable;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -199,11 +191,8 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
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();
|
||||
if ($save_to_map) {
|
||||
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED, $this->migrateExecutable->rollbackAction);
|
||||
$this->idMap->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED);
|
||||
$this->currentRow = NULL;
|
||||
$this->currentSourceIds = NULL;
|
||||
}
|
||||
|
@ -224,7 +213,7 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
*
|
||||
* @return \Iterator
|
||||
*/
|
||||
public function getIterator() {
|
||||
protected function getIterator() {
|
||||
if (!isset($this->iterator)) {
|
||||
$this->iterator = $this->initializeIterator();
|
||||
}
|
||||
|
@ -307,6 +296,12 @@ abstract class SourcePluginBase extends PluginBase implements MigrateSourceInter
|
|||
$row->setIdMap($id_map);
|
||||
}
|
||||
|
||||
// Clear any previous messages for this row before potentially adding
|
||||
// new ones.
|
||||
if (!empty($this->currentSourceIds)) {
|
||||
$this->idMap->delete($this->currentSourceIds, TRUE);
|
||||
}
|
||||
|
||||
// Preparing the row gives source plugins the chance to skip.
|
||||
if ($this->prepareRow($row) === FALSE) {
|
||||
continue;
|
||||
|
|
|
@ -8,9 +8,12 @@
|
|||
namespace Drupal\migrate\Plugin\migrate\source;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\State\StateInterface;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Plugin\migrate\id_map\Sql;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Sources whose data may be fetched via DBTNG.
|
||||
|
@ -21,7 +24,7 @@ use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
|||
* is present, it is used as a database connection information array to define
|
||||
* the connection.
|
||||
*/
|
||||
abstract class SqlBase extends SourcePluginBase {
|
||||
abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Database\Query\SelectInterface
|
||||
|
@ -33,11 +36,32 @@ abstract class SqlBase extends SourcePluginBase {
|
|||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* State service for retrieving database info.
|
||||
*
|
||||
* @var \Drupal\Core\State\StateInterface
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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('state')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,26 +82,51 @@ abstract class SqlBase extends SourcePluginBase {
|
|||
*/
|
||||
public function getDatabase() {
|
||||
if (!isset($this->database)) {
|
||||
if (isset($this->configuration['target'])) {
|
||||
$target = $this->configuration['target'];
|
||||
// See if the database info is in state - if not, fallback to
|
||||
// configuration.
|
||||
if (isset($this->configuration['database_state_key'])) {
|
||||
$this->database = $this->setUpDatabase($this->state->get($this->configuration['database_state_key']));
|
||||
}
|
||||
else {
|
||||
$target = 'default';
|
||||
$this->database = $this->setUpDatabase($this->configuration);
|
||||
}
|
||||
if (isset($this->configuration['key'])) {
|
||||
$key = $this->configuration['key'];
|
||||
}
|
||||
else {
|
||||
$key = 'migrate';
|
||||
}
|
||||
if (isset($this->configuration['database'])) {
|
||||
Database::addConnectionInfo($key, $target, $this->configuration['database']);
|
||||
}
|
||||
$this->database = Database::getConnection($target, $key);
|
||||
}
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a connection to the referenced database, adding the connection if
|
||||
* necessary.
|
||||
*
|
||||
* @param array $database_info
|
||||
* Configuration for the source database connection. The keys are:
|
||||
* 'key' - The database connection key.
|
||||
* 'target' - The database connection target.
|
||||
* 'database' - Database configuration array as accepted by
|
||||
* Database::addConnectionInfo.
|
||||
*
|
||||
* @return \Drupal\Core\Database\Connection
|
||||
* The connection to use for this plugin's queries.
|
||||
*/
|
||||
protected function setUpDatabase(array $database_info) {
|
||||
if (isset($database_info['key'])) {
|
||||
$key = $database_info['key'];
|
||||
}
|
||||
else {
|
||||
$key = 'migrate';
|
||||
}
|
||||
if (isset($database_info['target'])) {
|
||||
$target = $database_info['target'];
|
||||
}
|
||||
else {
|
||||
$target = 'default';
|
||||
}
|
||||
if (isset($database_info['database'])) {
|
||||
Database::addConnectionInfo($key, $target, $database_info['database']);
|
||||
}
|
||||
return Database::getConnection($target, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for database select.
|
||||
*/
|
||||
|
@ -135,7 +184,7 @@ abstract class SqlBase extends SourcePluginBase {
|
|||
$delimiter = '';
|
||||
foreach ($this->getIds() as $field_name => $field_schema) {
|
||||
if (isset($field_schema['alias'])) {
|
||||
$field_name = $field_schema['alias'] . '.' . $field_name;
|
||||
$field_name = $field_schema['alias'] . '.' . $this->query->escapeField($field_name);
|
||||
}
|
||||
$map_join .= "$delimiter$field_name = map.sourceid" . $count++;
|
||||
$delimiter = ' AND ';
|
||||
|
|
167
core/modules/migrate/src/Tests/MigrateRollbackTest.php
Normal file
167
core/modules/migrate/src/Tests/MigrateRollbackTest.php
Normal file
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\migrate\Tests\MigrateRollbackTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\migrate\Tests;
|
||||
|
||||
use Drupal\migrate\Entity\Migration;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
|
||||
/**
|
||||
* Tests rolling back of imports.
|
||||
*
|
||||
* @group migrate
|
||||
*/
|
||||
class MigrateRollbackTest extends MigrateTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['field', 'taxonomy', 'text'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('taxonomy_vocabulary');
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->installConfig(['taxonomy']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rolling back configuration and content entities.
|
||||
*/
|
||||
public function testRollback() {
|
||||
// We use vocabularies to demonstrate importing and rolling back
|
||||
// configuration entities.
|
||||
$vocabulary_data_rows = [
|
||||
['id' => '1', 'name' => 'categories', 'weight' => '2'],
|
||||
['id' => '2', 'name' => 'tags', 'weight' => '1'],
|
||||
];
|
||||
$ids = ['id' => ['type' => 'integer']];
|
||||
$config = [
|
||||
'id' => 'vocabularies',
|
||||
'migration_tags' => ['Import and rollback test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => $vocabulary_data_rows,
|
||||
'ids' => $ids,
|
||||
],
|
||||
'process' => [
|
||||
'vid' => 'id',
|
||||
'name' => 'name',
|
||||
'weight' => 'weight',
|
||||
],
|
||||
'destination' => ['plugin' => 'entity:taxonomy_vocabulary'],
|
||||
];
|
||||
|
||||
$vocabulary_migration = Migration::create($config);
|
||||
$vocabulary_id_map = $vocabulary_migration->getIdMap();
|
||||
|
||||
$this->assertTrue($vocabulary_migration->getDestinationPlugin()->supportsRollback());
|
||||
|
||||
// Import and validate vocabulary config entities were created.
|
||||
$vocabulary_executable = new MigrateExecutable($vocabulary_migration, $this);
|
||||
$vocabulary_executable->import();
|
||||
foreach ($vocabulary_data_rows as $row) {
|
||||
/** @var Vocabulary $vocabulary */
|
||||
$vocabulary = Vocabulary::load($row['id']);
|
||||
$this->assertTrue($vocabulary);
|
||||
$map_row = $vocabulary_id_map->getRowBySource(['id' => $row['id']]);
|
||||
$this->assertNotNull($map_row['destid1']);
|
||||
}
|
||||
|
||||
// We use taxonomy terms to demonstrate importing and rolling back
|
||||
// content entities.
|
||||
$term_data_rows = [
|
||||
['id' => '1', 'vocab' => '1', 'name' => 'music'],
|
||||
['id' => '2', 'vocab' => '2', 'name' => 'Bach'],
|
||||
['id' => '3', 'vocab' => '2', 'name' => 'Beethoven'],
|
||||
];
|
||||
$ids = ['id' => ['type' => 'integer']];
|
||||
$config = [
|
||||
'id' => 'terms',
|
||||
'migration_tags' => ['Import and rollback test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => $term_data_rows,
|
||||
'ids' => $ids,
|
||||
],
|
||||
'process' => [
|
||||
'tid' => 'id',
|
||||
'vid' => 'vocab',
|
||||
'name' => 'name',
|
||||
],
|
||||
'destination' => ['plugin' => 'entity:taxonomy_term'],
|
||||
'migration_dependencies' => ['required' => ['vocabularies']],
|
||||
];
|
||||
|
||||
$term_migration = Migration::create($config);
|
||||
$term_id_map = $term_migration->getIdMap();
|
||||
|
||||
$this->assertTrue($term_migration->getDestinationPlugin()->supportsRollback());
|
||||
|
||||
// Import and validate term entities were created.
|
||||
$term_executable = new MigrateExecutable($term_migration, $this);
|
||||
$term_executable->import();
|
||||
foreach ($term_data_rows as $row) {
|
||||
/** @var Term $term */
|
||||
$term = Term::load($row['id']);
|
||||
$this->assertTrue($term);
|
||||
$map_row = $term_id_map->getRowBySource(['id' => $row['id']]);
|
||||
$this->assertNotNull($map_row['destid1']);
|
||||
}
|
||||
|
||||
// Rollback and verify the entities are gone.
|
||||
$term_executable->rollback();
|
||||
foreach ($term_data_rows as $row) {
|
||||
$term = Term::load($row['id']);
|
||||
$this->assertNull($term);
|
||||
$map_row = $term_id_map->getRowBySource(['id' => $row['id']]);
|
||||
$this->assertFalse($map_row);
|
||||
}
|
||||
$vocabulary_executable->rollback();
|
||||
foreach ($vocabulary_data_rows as $row) {
|
||||
$term = Vocabulary::load($row['id']);
|
||||
$this->assertNull($term);
|
||||
$map_row = $vocabulary_id_map->getRowBySource(['id' => $row['id']]);
|
||||
$this->assertFalse($map_row);
|
||||
}
|
||||
|
||||
// Test that simple configuration is not rollbackable.
|
||||
$term_setting_rows = [
|
||||
['id' => 1, 'override_selector' => '0', 'terms_per_page_admin' => '10'],
|
||||
];
|
||||
$ids = ['id' => ['type' => 'integer']];
|
||||
$config = [
|
||||
'id' => 'taxonomy_settings',
|
||||
'migration_tags' => ['Import and rollback test'],
|
||||
'source' => [
|
||||
'plugin' => 'embedded_data',
|
||||
'data_rows' => $term_setting_rows,
|
||||
'ids' => $ids,
|
||||
],
|
||||
'process' => [
|
||||
'override_selector' => 'override_selector',
|
||||
'terms_per_page_admin' => 'terms_per_page_admin',
|
||||
],
|
||||
'destination' => [
|
||||
'plugin' => 'config',
|
||||
'config_name' => 'taxonomy.settings',
|
||||
],
|
||||
'migration_dependencies' => ['required' => ['vocabularies']],
|
||||
];
|
||||
|
||||
$settings_migration = Migration::create($config);
|
||||
$this->assertFalse($settings_migration->getDestinationPlugin()->supportsRollback());
|
||||
}
|
||||
|
||||
}
|
|
@ -63,10 +63,10 @@ class MigrateSkipRowTest extends KernelTestBase {
|
|||
|
||||
$id_map_plugin = $migration->getIdMap();
|
||||
// The first row is recorded in the map as ignored.
|
||||
$map_row = $id_map_plugin->getRowBySource([1]);
|
||||
$map_row = $id_map_plugin->getRowBySource(['id' => 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]);
|
||||
$map_row = $id_map_plugin->getRowBySource(['id' => 2]);
|
||||
$this->assertFalse($map_row);
|
||||
|
||||
}
|
||||
|
|
|
@ -20,14 +20,6 @@ use Drupal\simpletest\KernelTestBase;
|
|||
*/
|
||||
abstract class MigrateTestBase extends KernelTestBase implements MigrateMessageInterface {
|
||||
|
||||
/**
|
||||
* The file path(s) to the dumped database(s) to load into the child site.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $databaseDumpFiles = array();
|
||||
|
||||
|
||||
/**
|
||||
* TRUE to collect messages instead of displaying them.
|
||||
*
|
||||
|
@ -52,6 +44,13 @@ abstract class MigrateTestBase extends KernelTestBase implements MigrateMessageI
|
|||
*/
|
||||
protected $migration;
|
||||
|
||||
/**
|
||||
* The source database connection.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $sourceDatabase;
|
||||
|
||||
public static $modules = array('migrate');
|
||||
|
||||
/**
|
||||
|
@ -60,6 +59,7 @@ abstract class MigrateTestBase extends KernelTestBase implements MigrateMessageI
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->createMigrationConnection();
|
||||
$this->sourceDatabase = Database::getConnection('default', 'migrate');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,28 +119,6 @@ abstract class MigrateTestBase extends KernelTestBase implements MigrateMessageI
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Drupal 6 database dumps to be used.
|
||||
*
|
||||
* @param array $files
|
||||
* An array of files.
|
||||
* @param string $method
|
||||
* The name of the method in the dump class to use. Defaults to load.
|
||||
*/
|
||||
protected function loadDumps(array $files, $method = 'load') {
|
||||
// Load the database from the portable PHP dump.
|
||||
// The files may be gzipped.
|
||||
foreach ($files as $file) {
|
||||
if (substr($file, -3) == '.gz') {
|
||||
$file = "compress.zlib://$file";
|
||||
require $file;
|
||||
}
|
||||
preg_match('/^namespace (.*);$/m', file_get_contents($file), $matches);
|
||||
$class = $matches[1] . '\\' . basename($file, '.php');
|
||||
(new $class(Database::getConnection('default', 'migrate')))->$method();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare any dependent migrations.
|
||||
*
|
||||
|
@ -153,9 +131,6 @@ abstract class MigrateTestBase extends KernelTestBase implements MigrateMessageI
|
|||
foreach ($id_mappings as $migration_id => $data) {
|
||||
// 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);
|
||||
|
||||
$id_map = $migration->getIdMap();
|
||||
$id_map->setMessage($this);
|
||||
$source_ids = $migration->getSourcePlugin()->getIds();
|
||||
|
@ -186,6 +161,17 @@ abstract class MigrateTestBase extends KernelTestBase implements MigrateMessageI
|
|||
(new MigrateExecutable($this->migration, $this))->import();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a set of migrations in dependency order.
|
||||
*
|
||||
* @param string[] $ids
|
||||
* Array of migration IDs, in any order.
|
||||
*/
|
||||
protected function executeMigrations(array $ids) {
|
||||
$migrations = Migration::loadMultiple($ids);
|
||||
array_walk($migrations, [$this, 'executeMigration']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -24,6 +24,7 @@ class SqlBaseTest extends MigrateTestBase {
|
|||
$sql_base = new TestSqlBase();
|
||||
|
||||
// Check the default values.
|
||||
$sql_base->setConfiguration([]);
|
||||
$this->assertIdentical($sql_base->getDatabase()->getTarget(), 'default');
|
||||
$this->assertIdentical($sql_base->getDatabase()->getKey(), 'migrate');
|
||||
|
||||
|
@ -52,6 +53,35 @@ class SqlBaseTest extends MigrateTestBase {
|
|||
// Validate the connection has been created with the right values.
|
||||
$this->assertIdentical(Database::getConnectionInfo($key)[$target], $database);
|
||||
|
||||
// Now, test this all works when using state to store db info.
|
||||
$target = 'test_state_db_target';
|
||||
$key = 'test_state_migrate_connection';
|
||||
$config = ['target' => $target, 'key' => $key];
|
||||
$database_state_key = 'migrate_sql_base_test';
|
||||
\Drupal::state()->set($database_state_key, $config);
|
||||
$sql_base->setConfiguration(['database_state_key' => $database_state_key]);
|
||||
Database::addConnectionInfo($key, $target, Database::getConnectionInfo('default')['default']);
|
||||
|
||||
// Validate we've injected our custom key and target.
|
||||
$this->assertIdentical($sql_base->getDatabase()->getTarget(), $target);
|
||||
$this->assertIdentical($sql_base->getDatabase()->getKey(), $key);
|
||||
|
||||
// Now test we can have SqlBase create the connection from an info array.
|
||||
$sql_base = new TestSqlBase();
|
||||
|
||||
$target = 'test_state_db_target2';
|
||||
$key = 'test_state_migrate_connection2';
|
||||
$database = Database::getConnectionInfo('default')['default'];
|
||||
$config = ['target' => $target, 'key' => $key, 'database' => $database];
|
||||
$database_state_key = 'migrate_sql_base_test2';
|
||||
\Drupal::state()->set($database_state_key, $config);
|
||||
$sql_base->setConfiguration(['database_state_key' => $database_state_key]);
|
||||
|
||||
// Call getDatabase() to get the connection defined.
|
||||
$sql_base->getDatabase();
|
||||
|
||||
// Validate the connection has been created with the right values.
|
||||
$this->assertIdentical(Database::getConnectionInfo($key)[$target], $database);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -68,7 +98,9 @@ class TestSqlBase extends SqlBase {
|
|||
/**
|
||||
* Override the constructor so we can create one easily.
|
||||
*/
|
||||
public function __construct() {}
|
||||
public function __construct() {
|
||||
$this->state = \Drupal::state();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the database without caching it.
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\migrate\Unit\Exception\RequirementsExceptionTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\migrate\Unit\Exception;
|
||||
|
||||
use Drupal\migrate\Exception\RequirementsException;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\migrate\Exception\RequirementsException
|
||||
* @group migration
|
||||
*/
|
||||
class RequirementsExceptionTest extends UnitTestCase {
|
||||
|
||||
protected $missingRequirements = ['random_jackson_pivot', '51_Eridani_b'];
|
||||
|
||||
/**
|
||||
* @covers ::getRequirements
|
||||
*/
|
||||
public function testGetRequirements() {
|
||||
$exception = new RequirementsException('Missing requirements ', ['requirements' => $this->missingRequirements]);
|
||||
$this->assertArrayEquals(['requirements' => $this->missingRequirements], $exception->getRequirements());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getRequirementsString
|
||||
* @dataProvider getRequirementsProvider
|
||||
*/
|
||||
public function testGetExceptionString($expected, $message, $requirements) {
|
||||
$exception = new RequirementsException($message, $requirements);
|
||||
$this->assertEquals($expected, $exception->getRequirementsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of requirements to test.
|
||||
*/
|
||||
public function getRequirementsProvider() {
|
||||
return array(
|
||||
array(
|
||||
'requirements: random_jackson_pivot.',
|
||||
'Single Requirement',
|
||||
array('requirements' => $this->missingRequirements[0]),
|
||||
),
|
||||
array(
|
||||
'requirements: random_jackson_pivot. requirements: 51_Eridani_b.',
|
||||
'Multiple Requirements',
|
||||
array('requirements' => $this->missingRequirements),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\Tests\migrate\Unit;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate\MigrateException;
|
||||
|
@ -72,7 +73,7 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
// Ensure that a message with the proper message was added.
|
||||
$this->message->expects($this->once())
|
||||
->method('display')
|
||||
->with("Migration failed with source plugin exception: $exception_message");
|
||||
->with("Migration failed with source plugin exception: " . Html::escape($exception_message));
|
||||
|
||||
$result = $this->executable->import();
|
||||
$this->assertEquals(MigrationInterface::RESULT_FAILED, $result);
|
||||
|
@ -199,10 +200,6 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
->method('getDestinationPlugin')
|
||||
->will($this->returnValue($destination));
|
||||
|
||||
$this->idMap->expects($this->once())
|
||||
->method('delete')
|
||||
->with(array('id' => 'test'), TRUE);
|
||||
|
||||
$this->idMap->expects($this->once())
|
||||
->method('saveIdMapping')
|
||||
->with($row, array(), MigrateIdMapInterface::STATUS_FAILED, NULL);
|
||||
|
@ -227,9 +224,10 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests the import method with a MigrateException being thrown.
|
||||
* Tests the import method with a MigrateException being thrown from the
|
||||
* destination.
|
||||
*/
|
||||
public function testImportWithValidRowWithMigrateException() {
|
||||
public function testImportWithValidRowWithDestinationMigrateException() {
|
||||
$exception_message = $this->getRandomGenerator()->string();
|
||||
$source = $this->getMockSource();
|
||||
|
||||
|
@ -268,10 +266,6 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
$this->idMap->expects($this->once())
|
||||
->method('saveMessage');
|
||||
|
||||
$this->message->expects($this->once())
|
||||
->method('display')
|
||||
->with($exception_message);
|
||||
|
||||
$this->idMap->expects($this->once())
|
||||
->method('lookupDestinationId')
|
||||
->with(array('id' => 'test'))
|
||||
|
@ -280,6 +274,53 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
$this->assertSame(MigrationInterface::RESULT_COMPLETED, $this->executable->import());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the import method with a MigrateException being thrown from a process
|
||||
* plugin.
|
||||
*/
|
||||
public function testImportWithValidRowWithProcesMigrateException() {
|
||||
$exception_message = $this->getRandomGenerator()->string();
|
||||
$source = $this->getMockSource();
|
||||
|
||||
$row = $this->getMockBuilder('Drupal\migrate\Row')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$row->expects($this->once())
|
||||
->method('getSourceIdValues')
|
||||
->willReturn(array('id' => 'test'));
|
||||
|
||||
$source->expects($this->once())
|
||||
->method('current')
|
||||
->willReturn($row);
|
||||
|
||||
$this->executable->setSource($source);
|
||||
|
||||
$this->migration->expects($this->once())
|
||||
->method('getProcessPlugins')
|
||||
->willThrowException(new MigrateException($exception_message));
|
||||
|
||||
$destination = $this->getMock('Drupal\migrate\Plugin\MigrateDestinationInterface');
|
||||
$destination->expects($this->never())
|
||||
->method('import');
|
||||
|
||||
$this->migration->expects($this->once())
|
||||
->method('getDestinationPlugin')
|
||||
->willReturn($destination);
|
||||
|
||||
$this->idMap->expects($this->once())
|
||||
->method('saveIdMapping')
|
||||
->with($row, array(), MigrateIdMapInterface::STATUS_FAILED, NULL);
|
||||
|
||||
$this->idMap->expects($this->once())
|
||||
->method('saveMessage');
|
||||
|
||||
$this->idMap->expects($this->never())
|
||||
->method('lookupDestinationId');
|
||||
|
||||
$this->assertSame(MigrationInterface::RESULT_COMPLETED, $this->executable->import());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the import method with a regular Exception being thrown.
|
||||
*/
|
||||
|
@ -334,57 +375,6 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
$this->assertSame(MigrationInterface::RESULT_COMPLETED, $this->executable->import());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests saving of queued messages.
|
||||
*/
|
||||
public function testSaveQueuedMessages() {
|
||||
// Assert no queued messages before save.
|
||||
$this->assertAttributeEquals(array(), 'queuedMessages', $this->executable);
|
||||
// Set required source_id_values for MigrateIdMapInterface::saveMessage().
|
||||
$expected_messages[] = array('message' => 'message 1', 'level' => MigrationInterface::MESSAGE_ERROR);
|
||||
$expected_messages[] = array('message' => 'message 2', 'level' => MigrationInterface::MESSAGE_WARNING);
|
||||
$expected_messages[] = array('message' => 'message 3', 'level' => MigrationInterface::MESSAGE_INFORMATIONAL);
|
||||
foreach ($expected_messages as $queued_message) {
|
||||
$this->executable->queueMessage($queued_message['message'], $queued_message['level']);
|
||||
}
|
||||
$this->executable->setSourceIdValues(array());
|
||||
$this->assertAttributeEquals($expected_messages, 'queuedMessages', $this->executable);
|
||||
// No asserts of saved messages since coverage exists
|
||||
// in MigrateSqlIdMapTest::saveMessage().
|
||||
$this->executable->saveQueuedMessages();
|
||||
// Assert no queued messages after save.
|
||||
$this->assertAttributeEquals(array(), 'queuedMessages', $this->executable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the queuing of messages.
|
||||
*/
|
||||
public function testQueueMessage() {
|
||||
// Assert no queued messages.
|
||||
$expected_messages = array();
|
||||
$this->assertAttributeEquals(array(), 'queuedMessages', $this->executable);
|
||||
// Assert a single (default level) queued message.
|
||||
$expected_messages[] = array(
|
||||
'message' => 'message 1',
|
||||
'level' => MigrationInterface::MESSAGE_ERROR,
|
||||
);
|
||||
$this->executable->queueMessage('message 1');
|
||||
$this->assertAttributeEquals($expected_messages, 'queuedMessages', $this->executable);
|
||||
// Assert multiple queued messages.
|
||||
$expected_messages[] = array(
|
||||
'message' => 'message 2',
|
||||
'level' => MigrationInterface::MESSAGE_WARNING,
|
||||
);
|
||||
$this->executable->queueMessage('message 2', MigrationInterface::MESSAGE_WARNING);
|
||||
$this->assertAttributeEquals($expected_messages, 'queuedMessages', $this->executable);
|
||||
$expected_messages[] = array(
|
||||
'message' => 'message 3',
|
||||
'level' => MigrationInterface::MESSAGE_INFORMATIONAL,
|
||||
);
|
||||
$this->executable->queueMessage('message 3', MigrationInterface::MESSAGE_INFORMATIONAL);
|
||||
$this->assertAttributeEquals($expected_messages, 'queuedMessages', $this->executable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the processRow method.
|
||||
*/
|
||||
|
@ -440,9 +430,6 @@ class MigrateExecutableTest extends MigrateTestCase {
|
|||
->disableOriginalConstructor()
|
||||
->setMethods(get_class_methods($class))
|
||||
->getMockForAbstractClass();
|
||||
$source->expects($this->any())
|
||||
->method('getIterator')
|
||||
->will($this->returnValue($iterator));
|
||||
$source->expects($this->once())
|
||||
->method('rewind')
|
||||
->will($this->returnValue(TRUE));
|
||||
|
|
|
@ -191,7 +191,7 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
|
||||
// Insert 4 message for later delete.
|
||||
foreach ($expected_results as $key => $expected_result) {
|
||||
$id_map->saveMessage([$key], $message);
|
||||
$id_map->saveMessage(['source_id_property' => $key], $message);
|
||||
}
|
||||
|
||||
// Truncate and check that 4 messages were deleted.
|
||||
|
@ -240,7 +240,7 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
|
||||
// Assert the row matches its original source.
|
||||
$source_id = $expected_results[MigrateIdMapInterface::STATUS_NEEDS_UPDATE]['sourceid1'];
|
||||
$test_row = $id_map->getRowBySource([$source_id]);
|
||||
$test_row = $id_map->getRowBySource(['source_id_property' => $source_id]);
|
||||
// $row_needing_update is an array of objects returned from the database,
|
||||
// but $test_row is an array, so the cast is necessary.
|
||||
$this->assertSame($test_row, (array) $row_needing_update[0]);
|
||||
|
@ -268,7 +268,7 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
foreach ($expected_results as $key => $expected_result) {
|
||||
$count = $id_map->messageCount();
|
||||
$this->assertEquals($expected_result, $count);
|
||||
$id_map->saveMessage([$key], $message);
|
||||
$id_map->saveMessage(['source_id_property' => $key], $message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,7 +286,7 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
$id_map = $this->getIdMap();
|
||||
|
||||
foreach ($expected_results as $key => $expected_result) {
|
||||
$id_map->saveMessage([$key], $message, $expected_result['level']);
|
||||
$id_map->saveMessage(['source_id_property' => $key], $message, $expected_result['level']);
|
||||
}
|
||||
|
||||
foreach ($id_map->getMessageIterator() as $message_row) {
|
||||
|
@ -297,8 +297,8 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
|
||||
// Insert with default level.
|
||||
$message_default = 'Hello world default.';
|
||||
$id_map->saveMessage([5], $message_default);
|
||||
$messages = $id_map->getMessageIterator([5]);
|
||||
$id_map->saveMessage(['source_id_property' => 5], $message_default);
|
||||
$messages = $id_map->getMessageIterator(['source_id_property' => 5]);
|
||||
$count = 0;
|
||||
foreach ($messages as $key => $message_row) {
|
||||
$count = 1;
|
||||
|
@ -334,11 +334,11 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
'destid1' => 'destination_id_value_2',
|
||||
] + $this->idMapDefaults();
|
||||
$this->saveMap($row);
|
||||
$source_id_values = [$row['sourceid1'], $row['sourceid2']];
|
||||
$source_id_values = ['source_id_property' => $row['sourceid1'], 'sourceid2' => $row['sourceid2']];
|
||||
$id_map = $this->getIdMap();
|
||||
$result_row = $id_map->getRowBySource($source_id_values);
|
||||
$this->assertSame($row, $result_row);
|
||||
$source_id_values = ['missing_value_1', 'missing_value_2'];
|
||||
$source_id_values = ['source_id_property' => 'missing_value_1', 'sourceid2' => 'missing_value_2'];
|
||||
$result_row = $id_map->getRowBySource($source_id_values);
|
||||
$this->assertFalse($result_row);
|
||||
}
|
||||
|
@ -416,12 +416,12 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
'destid1' => 'destination_id_value_2',
|
||||
] + $this->idMapDefaults();
|
||||
$this->saveMap($row);
|
||||
$dest_id_values = [$row['destid1']];
|
||||
$dest_id_values = ['destination_id_property' => $row['destid1']];
|
||||
$id_map = $this->getIdMap();
|
||||
$result_row = $id_map->getRowByDestination($dest_id_values);
|
||||
$this->assertSame($row, $result_row);
|
||||
// This value does not exist.
|
||||
$dest_id_values = ['invalid_destination_id_property'];
|
||||
$dest_id_values = ['destination_id_property' => 'invalid_destination_id_property'];
|
||||
$id_map = $this->getIdMap();
|
||||
$result_row = $id_map->getRowByDestination($dest_id_values);
|
||||
$this->assertFalse($result_row);
|
||||
|
@ -463,15 +463,15 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
$expected_result = [];
|
||||
for ($i = 1; $i <= $num_source_fields; $i++) {
|
||||
$row["sourceid$i"] = "source_id_value_$i";
|
||||
$expected_result[] = "source_id_value_$i";
|
||||
$expected_result["source_id_property_$i"] = "source_id_value_$i";
|
||||
$this->sourceIds["source_id_property_$i"] = [];
|
||||
}
|
||||
$destination_id_values = [];
|
||||
$nonexistent_id_values = [];
|
||||
for ($i = 1; $i <= $num_destination_fields; $i++) {
|
||||
$row["destid$i"] = "destination_id_value_$i";
|
||||
$destination_id_values[] = "destination_id_value_$i";
|
||||
$nonexistent_id_values[] = "nonexistent_destination_id_value_$i";
|
||||
$destination_id_values["destination_id_property_$i"] = "destination_id_value_$i";
|
||||
$nonexistent_id_values["destination_id_property_$i"] = "nonexistent_destination_id_value_$i";
|
||||
$this->destinationIds["destination_id_property_$i"] = [];
|
||||
}
|
||||
$this->saveMap($row);
|
||||
|
@ -662,7 +662,7 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
$this->queryResultTest($this->getIdMapContents(), $expected_results);
|
||||
// Mark each row as STATUS_NEEDS_UPDATE.
|
||||
foreach ($row_statuses as $status) {
|
||||
$id_map->setUpdate(['source_value_' . $status]);
|
||||
$id_map->setUpdate(['source_id_property' => 'source_value_' . $status]);
|
||||
}
|
||||
// Update expected results.
|
||||
foreach ($expected_results as $key => $value) {
|
||||
|
@ -737,7 +737,7 @@ class MigrateSqlIdMapTest extends MigrateTestCase {
|
|||
$message_table_name = $id_map->messageTableName();
|
||||
$row = new Row(['source_id_property' => 'source_value'], ['source_id_property' => []]);
|
||||
$id_map->saveIdMapping($row, ['destination_id_property' => 2]);
|
||||
$id_map->saveMessage(['source_value'], 'A message');
|
||||
$id_map->saveMessage(['source_id_property' => 'source_value'], 'A message');
|
||||
$this->assertTrue($this->database->schema()->tableExists($map_table_name),
|
||||
"$map_table_name exists");
|
||||
$this->assertTrue($this->database->schema()->tableExists($message_table_name),
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
namespace Drupal\Tests\migrate\Unit;
|
||||
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
|
||||
/**
|
||||
* Base class for Migrate module source unit tests.
|
||||
*/
|
||||
|
@ -77,6 +79,7 @@ abstract class MigrateSqlSourceTestCase extends MigrateTestCase {
|
|||
*/
|
||||
protected function setUp() {
|
||||
$module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
|
||||
$state = $this->getMock('Drupal\Core\State\StateInterface');
|
||||
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
|
||||
|
||||
$migration = $this->getMigration();
|
||||
|
@ -86,7 +89,7 @@ abstract class MigrateSqlSourceTestCase extends MigrateTestCase {
|
|||
|
||||
// Setup the plugin.
|
||||
$plugin_class = static::PLUGIN_CLASS;
|
||||
$plugin = new $plugin_class($this->migrationConfiguration['source'], $this->migrationConfiguration['source']['plugin'], array(), $migration, $entity_manager);
|
||||
$plugin = new $plugin_class($this->migrationConfiguration['source'], $this->migrationConfiguration['source']['plugin'], array(), $migration, $state, $entity_manager);
|
||||
|
||||
// Do some reflection to set the database and moduleHandler.
|
||||
$plugin_reflection = new \ReflectionClass($plugin);
|
||||
|
@ -111,6 +114,7 @@ abstract class MigrateSqlSourceTestCase extends MigrateTestCase {
|
|||
* Test the source returns the same rows as expected.
|
||||
*/
|
||||
public function testRetrieval() {
|
||||
$this->assertInstanceOf(SelectInterface::class, $this->source->query());
|
||||
$this->queryResultTest($this->source, $this->expectedResults);
|
||||
}
|
||||
|
||||
|
@ -118,7 +122,16 @@ abstract class MigrateSqlSourceTestCase extends MigrateTestCase {
|
|||
* Test the source returns the row count expected.
|
||||
*/
|
||||
public function testSourceCount() {
|
||||
$this->assertEquals($this->source->count(), $this->expectedCount);
|
||||
$count = $this->source->count();
|
||||
$this->assertTrue(is_numeric($count));
|
||||
$this->assertEquals($count, $this->expectedCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the source defines a valid ID.
|
||||
*/
|
||||
public function testSourceId() {
|
||||
$this->assertNotEmpty($this->source->getIds());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -96,13 +96,13 @@ class MigrationTest extends UnitTestCase {
|
|||
$migration_d = $this->getMock('Drupal\migrate\Entity\MigrationInterface');
|
||||
|
||||
$migration_b->expects($this->once())
|
||||
->method('isComplete')
|
||||
->method('allRowsProcessed')
|
||||
->willReturn(TRUE);
|
||||
$migration_c->expects($this->once())
|
||||
->method('isComplete')
|
||||
->method('allRowsProcessed')
|
||||
->willReturn(FALSE);
|
||||
$migration_d->expects($this->once())
|
||||
->method('isComplete')
|
||||
->method('allRowsProcessed')
|
||||
->willReturn(TRUE);
|
||||
|
||||
$migration_storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
|
||||
|
|
|
@ -37,6 +37,9 @@ class ConfigTest extends UnitTestCase {
|
|||
}
|
||||
$config->expects($this->once())
|
||||
->method('save');
|
||||
$config->expects($this->once())
|
||||
->method('getName')
|
||||
->willReturn('d8_config');
|
||||
$config_factory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
|
||||
$config_factory->expects($this->once())
|
||||
->method('getEditable')
|
||||
|
@ -49,7 +52,8 @@ class ConfigTest extends UnitTestCase {
|
|||
->method('getRawDestination')
|
||||
->will($this->returnValue($source));
|
||||
$destination = new Config(array('config_name' => 'd8_config'), 'd8_config', array('pluginId' => 'd8_config'), $migration, $config_factory);
|
||||
$destination->import($row);
|
||||
$destination_id = $destination->import($row);
|
||||
$this->assertEquals($destination_id, ['d8_config']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Reference in a new issue