Update to Drupal 8.0.0-rc3. For more information, see https://www.drupal.org/node/2608078

This commit is contained in:
Pantheon Automation 2015-11-04 11:11:27 -08:00 committed by Greg Anderson
parent 6419a031d7
commit 4afb23bbd3
762 changed files with 20080 additions and 6368 deletions

View file

@ -2,7 +2,7 @@
/**
* @file
* Contains Drupal\migrate\Event\MigrateEvents.
* Contains \Drupal\migrate\Event\MigrateEvents.
*/
namespace Drupal\migrate\Event;
@ -17,6 +17,7 @@ namespace Drupal\migrate\Event;
* @see \Drupal\migrate\Event\MigratePostRowSaveEvent
* @see \Drupal\migrate\Event\MigrateRollbackEvent
* @see \Drupal\migrate\Event\MigrateRowDeleteEvent
* @see \Drupal\migrate\Event\MigrateIdMapMessageEvent
*/
final class MigrateEvents {
@ -170,4 +171,19 @@ final class MigrateEvents {
*/
const POST_ROW_DELETE = 'migrate.post_row_delete';
/**
* Name of the event fired when saving a message to the idmap.
*
* This event allows modules to perform an action whenever a message is being
* logged by the idmap. The event listener method
* receives a \Drupal\migrate\Event\MigrateIdMapMessageEvent instance.
*
* @Event
*
* @see \Drupal\migrate\Event\MigrateIdMapMessageEvent
*
* @var string
*/
const IDMAP_MESSAGE = 'migrate.idmap_message';
}

View file

@ -0,0 +1,106 @@
<?php
/**
* @file
* Contains \Drupal\migrate\Event\MigrateIdMapMessageEvent.
*/
namespace Drupal\migrate\Event;
use Drupal\migrate\Entity\MigrationInterface;
use Symfony\Component\EventDispatcher\Event;
/**
* Wraps an idmap message event for event listeners.
*/
class MigrateIdMapMessageEvent extends Event {
/**
* Migration entity.
*
* @var \Drupal\migrate\Entity\MigrationInterface
*/
protected $migration;
/**
* Array of values uniquely identifying the source row.
*
* @var array
*/
protected $sourceIdValues;
/**
* Message to be logged.
*
* @var string
*/
protected $message;
/**
* Message severity.
*
* @var int
*/
protected $level;
/**
* Constructs a post-save event object.
*
* @param \Drupal\migrate\Entity\MigrationInterface $migration
* Migration entity.
* @param array $source_id_values
* Values represent the source ID.
* @param string $message
* The message
* @param int $level
* Severity level (one of the MigrationInterface::MESSAGE_* constants).
*/
public function __construct(MigrationInterface $migration, array $source_id_values, $message, $level) {
$this->migration = $migration;
$this->sourceIdValues = $source_id_values;
$this->message = $message;
$this->level = $level;
}
/**
* Gets the migration entity.
*
* @return \Drupal\migrate\Entity\MigrationInterface
* The migration entity involved.
*/
public function getMigration() {
return $this->migration;
}
/**
* Gets the source ID values.
*
* @return array
* The source ID as an array.
*/
public function getSourceIdValues() {
return $this->sourceIdValues;
}
/**
* Gets the message to be logged.
*
* @return string
* The message text.
*/
public function getMessage() {
return $this->message;
}
/**
* Gets the severity level of the message (one of the
* MigrationInterface::MESSAGE_* constants).
*
* @return int
* The message level.
*/
public function getLevel() {
return $this->level;
}
}

View file

@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\migrate\Event\MigratePreSaveEvent.
* Contains \Drupal\migrate\Event\MigratePreRowSaveEvent.
*/
namespace Drupal\migrate\Event;

View file

@ -64,13 +64,6 @@ class MigrateExecutable implements MigrateExecutableInterface {
*/
protected $sourceIdValues;
/**
* The rollback action to be saved for the current row.
*
* @var int
*/
public $rollbackAction;
/**
* An array of counts. Initially used for cache hit/miss tracking.
*
@ -230,12 +223,12 @@ class MigrateExecutable implements MigrateExecutableInterface {
$save = TRUE;
}
catch (MigrateException $e) {
$this->migration->getIdMap()->saveIdMapping($row, array(), $e->getStatus(), $this->rollbackAction);
$this->migration->getIdMap()->saveIdMapping($row, array(), $e->getStatus());
$this->saveMessage($e->getMessage(), $e->getLevel());
$save = FALSE;
}
catch (MigrateSkipRowException $e) {
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED, $this->rollbackAction);
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_IGNORED);
$save = FALSE;
}
@ -247,11 +240,11 @@ class MigrateExecutable implements MigrateExecutableInterface {
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);
$id_map->saveIdMapping($row, $destination_id_values, $this->sourceRowStatus, $destination->rollbackAction());
}
}
else {
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_FAILED, $this->rollbackAction);
$id_map->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_FAILED);
if (!$id_map->messageCount()) {
$message = $this->t('New object was not saved, no error provided');
$this->saveMessage($message);
@ -260,11 +253,11 @@ class MigrateExecutable implements MigrateExecutableInterface {
}
}
catch (MigrateException $e) {
$this->migration->getIdMap()->saveIdMapping($row, array(), $e->getStatus(), $this->rollbackAction);
$this->migration->getIdMap()->saveIdMapping($row, array(), $e->getStatus());
$this->saveMessage($e->getMessage(), $e->getLevel());
}
catch (\Exception $e) {
$this->migration->getIdMap()->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_FAILED, $this->rollbackAction);
$this->migration->getIdMap()->saveIdMapping($row, array(), MigrateIdMapInterface::STATUS_FAILED);
$this->handleException($e);
}
}
@ -330,11 +323,14 @@ class MigrateExecutable implements MigrateExecutableInterface {
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));
$map_row = $id_map->getRowByDestination($destination_key);
if ($map_row['rollback_action'] == MigrateIdMapInterface::ROLLBACK_DELETE) {
$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);
}

View file

@ -80,7 +80,19 @@ interface MigrateDestinationInterface extends PluginInspectionInterface {
public function rollback(array $destination_identifier);
/**
* Whether the destination can be rolled back or not.
*
* @return bool
* TRUE if rollback is supported, FALSE if not.
*/
public function supportsRollback();
/**
* The rollback action for the last imported item.
*
* @return int
* The MigrateIdMapInterface::ROLLBACK_ constant indicating how an imported
* item should be handled on rollback.
*/
public function rollbackAction();
}

View file

@ -12,6 +12,7 @@ use Drupal\Core\Plugin\PluginBase;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\Plugin\MigrateDestinationInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Plugin\RequirementsInterface;
/**
@ -33,6 +34,13 @@ abstract class DestinationBase extends PluginBase implements MigrateDestinationI
*/
protected $supportsRollback = FALSE;
/**
* The rollback action to be saved for the last imported item.
*
* @var int
*/
protected $rollbackAction = MigrateIdMapInterface::ROLLBACK_DELETE;
/**
* The migration.
*
@ -57,6 +65,13 @@ abstract class DestinationBase extends PluginBase implements MigrateDestinationI
$this->migration = $migration;
}
/**
* {@inheritdoc}
*/
public function rollbackAction() {
return $this->rollbackAction;
}
/**
* {@inheritdoc}
*/
@ -79,4 +94,23 @@ abstract class DestinationBase extends PluginBase implements MigrateDestinationI
public function supportsRollback() {
return $this->supportsRollback;
}
/**
* For a destination item being updated, set the appropriate rollback action.
*
* @param array $id_map
* The map row data for the item.
*/
protected function setRollbackAction(array $id_map) {
// If the entity we're updating was previously migrated by us, preserve the
// existing rollback action.
if (isset($id_map['sourceid1'])) {
$this->rollbackAction = $id_map['rollback_action'];
}
// Otherwise, we're updating an entity which already existed on the
// destination and want to make sure we do not delete it on rollback.
else {
$this->rollbackAction = MigrateIdMapInterface::ROLLBACK_PRESERVE;
}
}
}

View file

@ -10,6 +10,7 @@ namespace Drupal\migrate\Plugin\migrate\destination;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\EntityInterface;
use Drupal\migrate\MigrateException;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Row;
/**
@ -31,6 +32,7 @@ class EntityConfigBase extends Entity {
if ($row->isStub()) {
throw new MigrateException('Config entities can not be stubbed.');
}
$this->rollbackAction = MigrateIdMapInterface::ROLLBACK_DELETE;
$ids = $this->getIds();
$id_key = $this->getKey('id');
if (count($ids) > 1) {
@ -64,7 +66,6 @@ class EntityConfigBase extends Entity {
return $ids;
}
/**
* Updates an entity with the contents of a row.
*
@ -77,6 +78,8 @@ class EntityConfigBase extends Entity {
foreach ($row->getRawDestination() as $property => $value) {
$this->updateEntityProperty($entity, explode(Row::PROPERTY_SEPARATOR, $property), $value);
}
$this->setRollbackAction($row->getIdMap());
}
/**

View file

@ -13,6 +13,7 @@ use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -71,6 +72,7 @@ class EntityContentBase extends Entity {
* {@inheritdoc}
*/
public function import(Row $row, array $old_destination_id_values = array()) {
$this->rollbackAction = MigrateIdMapInterface::ROLLBACK_DELETE;
$entity = $this->getEntity($row, $old_destination_id_values);
return $this->save($entity, $old_destination_id_values);
}
@ -126,6 +128,8 @@ class EntityContentBase extends Entity {
$field->setValue($values);
}
}
$this->setRollbackAction($row->getIdMap());
}
}

View file

@ -12,6 +12,7 @@ use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Event\MigrateIdMapMessageEvent;
use Drupal\migrate\MigrateException;
use Drupal\migrate\MigrateMessageInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
@ -562,6 +563,10 @@ class Sql extends PluginBase implements MigrateIdMapInterface, ContainerFactoryP
$this->getDatabase()->insert($this->messageTableName())
->fields($fields)
->execute();
// Notify anyone listening of the message we've saved.
$this->eventDispatcher->dispatch(MigrateEvents::IDMAP_MESSAGE,
new MigrateIdMapMessageEvent($this->migration, $source_id_values, $message, $level));
}
/**

View file

@ -0,0 +1,133 @@
<?php
/**
* @file
* Contains \Drupal\migrate\Tests\MigrateMessageTest.
*/
namespace Drupal\migrate\Tests;
use Drupal\migrate\Entity\Migration;
use Drupal\migrate\Entity\MigrationInterface;
use Drupal\migrate\Event\MigrateEvents;
use Drupal\migrate\Event\MigrateIdMapMessageEvent;
use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\MigrateMessageInterface;
use Drupal\simpletest\KernelTestBase;
/**
* Test whether idmap messages are sent to the message interface when requested.
*
* @group migrate
*/
class MigrateMessageTest extends KernelTestBase implements MigrateMessageInterface {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['migrate', 'system'];
/**
* Migration to run.
*
* @var \Drupal\migrate\Entity\MigrationInterface
*/
protected $migration;
/**
* Messages accumulated during the migration run.
*
* @var array
*/
protected $messages = [];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->installConfig(['system']);
// A simple migration, which will generate a message to the id map because
// the concat plugin throws an exception if its source is not an array.
$config = [
'id' => 'sample_data',
'migration_tags' => ['Message test'],
'source' => [
'plugin' => 'embedded_data',
'data_rows' => [
['name' => 'source_message', 'value' => 'a message'],
],
'ids' => [
'name' => ['type' => 'string'],
],
],
'process' => [
'message' => [
'plugin' => 'concat',
'source' => 'value',
],
],
'destination' => [
'plugin' => 'config',
'config_name' => 'system.maintenance',
],
];
$this->migration = Migration::create($config);
}
/**
* Tests migration interruptions.
*/
public function testMessagesNotTeed() {
// We don't ask for messages to be teed, so don't expect any.
$executable = new MigrateExecutable($this->migration, $this);
$executable->import();
$this->assertIdentical(count($this->messages), 0);
}
/**
* Tests migration interruptions.
*/
public function testMessagesTeed() {
// Ask to receive any messages sent to the idmap.
\Drupal::service('event_dispatcher')->addListener(MigrateEvents::IDMAP_MESSAGE,
array($this, 'mapMessageRecorder'));
$executable = new MigrateExecutable($this->migration, $this);
$executable->import();
$this->assertIdentical(count($this->messages), 1);
$this->assertIdentical(reset($this->messages), "source_message: 'a message' is not an array");
}
/**
* Reacts to map message event.
*
* @param \Drupal\Migrate\Event\MigrateIdMapMessageEvent $event
* The migration event.
* @param string $name
* The event name.
*/
public function mapMessageRecorder(MigrateIdMapMessageEvent $event, $name) {
if ($event->getLevel() == MigrationInterface::MESSAGE_NOTICE ||
$event->getLevel() == MigrationInterface::MESSAGE_INFORMATIONAL) {
$type = 'status';
}
else {
$type = 'error';
}
$source_id_string = implode(',', $event->getSourceIdValues());
$this->display($source_id_string . ': ' . $event->getMessage(), $type);
}
/**
* {@inheritdoc}
*/
public function display($message, $type = 'status') {
$this->messages[] = $message;
}
}

View file

@ -9,6 +9,8 @@ namespace Drupal\migrate\Tests;
use Drupal\migrate\Entity\Migration;
use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Row;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\Entity\Vocabulary;
@ -109,9 +111,21 @@ class MigrateRollbackTest extends MigrateTestBase {
$this->assertTrue($term_migration->getDestinationPlugin()->supportsRollback());
// Pre-create a term, to make sure it isn't deleted on rollback.
$preserved_term_ids[] = 1;
$new_term = Term::create(['tid' => 1, 'vid' => 1, 'name' => 'music']);
$new_term->save();
// Import and validate term entities were created.
$term_executable = new MigrateExecutable($term_migration, $this);
$term_executable->import();
// Also explicitly mark one row to be preserved on rollback.
$preserved_term_ids[] = 2;
$map_row = $term_id_map->getRowBySource(['id' => 2]);
$dummy_row = new Row(['id' => 2], $ids);
$term_id_map->saveIdMapping($dummy_row, [$map_row['destid1']],
$map_row['source_row_status'], MigrateIdMapInterface::ROLLBACK_PRESERVE);
foreach ($term_data_rows as $row) {
/** @var Term $term */
$term = Term::load($row['id']);
@ -124,7 +138,12 @@ class MigrateRollbackTest extends MigrateTestBase {
$term_executable->rollback();
foreach ($term_data_rows as $row) {
$term = Term::load($row['id']);
$this->assertNull($term);
if (in_array($row['id'], $preserved_term_ids)) {
$this->assertNotNull($term);
}
else {
$this->assertNull($term);
}
$map_row = $term_id_map->getRowBySource(['id' => $row['id']]);
$this->assertFalse($map_row);
}

View file

@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\migrate\Tests\MigrateStatusTest
* Contains \Drupal\migrate\Tests\MigrateStatusTest.
*/
namespace Drupal\migrate\Tests;

View file

@ -1,5 +1,10 @@
<?php
/**
* @file
* Contains \Drupal\migrate\Tests\MigrationTest.
*/
namespace Drupal\migrate\Tests;
use Drupal\migrate\Entity\Migration;

View file

@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\migrate\Tests\SqlBaseTest
* Contains \Drupal\migrate\Tests\SqlBaseTest.
*/
namespace Drupal\migrate\Tests;

View file

@ -2,7 +2,7 @@
/**
* @file
* Contains \Drupal\migrate\Tests\TemplateTest
* Contains \Drupal\migrate\Tests\TemplateTest.
*/
namespace Drupal\migrate\Tests;