summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/modules/content_translation/src/ContentTranslationUpdatesManager.php19
-rw-r--r--core/modules/language/migration_templates/d6_language_content_settings.yml3
-rw-r--r--core/modules/language/migration_templates/d7_language_content_settings.yml2
-rw-r--r--core/modules/migrate/src/Plugin/migrate/destination/DestinationBase.php6
-rw-r--r--core/modules/migrate/src/Plugin/migrate/destination/Entity.php3
-rw-r--r--core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php82
-rw-r--r--core/modules/migrate/tests/modules/migrate_external_translated_test/migrate_external_translated_test.info.yml8
-rw-r--r--core/modules/migrate/tests/modules/migrate_external_translated_test/migrations/migrate.migration.external_translated_test_node.yml19
-rw-r--r--core/modules/migrate/tests/modules/migrate_external_translated_test/migrations/migrate.migration.external_translated_test_node_translation.yml27
-rw-r--r--core/modules/migrate/tests/modules/migrate_external_translated_test/src/Plugin/migrate/source/MigrateExternalTranslatedTestSource.php77
-rw-r--r--core/modules/migrate/tests/src/Kernel/MigrateEntityContentBaseTest.php159
-rw-r--r--core/modules/migrate/tests/src/Kernel/MigrateExternalTranslatedTest.php92
-rw-r--r--core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php28
-rw-r--r--core/modules/migrate_drupal/tests/fixtures/drupal6.php134
-rw-r--r--core/modules/migrate_drupal/tests/src/Kernel/d6/EntityContentBaseTest.php39
-rw-r--r--core/modules/migrate_drupal/tests/src/Kernel/d6/MigrateDrupal6TestBase.php15
-rw-r--r--core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php12
-rw-r--r--core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php2
-rw-r--r--core/modules/migrate_drupal_ui/src/Tests/d6/MigrateUpgrade6Test.php8
-rw-r--r--core/modules/migrate_drupal_ui/src/Tests/d7/MigrateUpgrade7Test.php5
-rw-r--r--core/modules/node/migration_templates/d6_node.yml5
-rw-r--r--core/modules/node/migration_templates/d6_node_translation.yml52
-rw-r--r--core/modules/node/src/Plugin/migrate/D6NodeDeriver.php28
-rw-r--r--core/modules/node/src/Plugin/migrate/source/d6/Node.php35
-rw-r--r--core/modules/node/src/Plugin/migrate/source/d6/NodeRevision.php8
-rw-r--r--core/modules/node/src/Tests/Migrate/d6/MigrateNodeRevisionTest.php5
-rw-r--r--core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeDeriverTest.php50
-rw-r--r--core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php16
-rw-r--r--core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeByNodeTypeTest.php4
-rw-r--r--core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeRevisionByNodeTypeTest.php4
-rw-r--r--core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeRevisionTest.php4
-rw-r--r--core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTest.php108
-rw-r--r--core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTestBase.php179
-rw-r--r--core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTranslationTest.php46
-rw-r--r--core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeRevisionTest.php2
-rw-r--r--core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeTest.php2
36 files changed, 1156 insertions, 132 deletions
diff --git a/core/modules/content_translation/src/ContentTranslationUpdatesManager.php b/core/modules/content_translation/src/ContentTranslationUpdatesManager.php
index 8b34797..4fa54f3 100644
--- a/core/modules/content_translation/src/ContentTranslationUpdatesManager.php
+++ b/core/modules/content_translation/src/ContentTranslationUpdatesManager.php
@@ -2,10 +2,13 @@
namespace Drupal\content_translation;
+use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Config\ConfigEvents;
use Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\migrate\Event\MigrateEvents;
+use Drupal\migrate\Event\MigrateImportEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
@@ -75,10 +78,26 @@ class ContentTranslationUpdatesManager implements EventSubscriberInterface {
}
/**
+ * Listener for migration imports.
+ */
+ public function onMigrateImport(MigrateImportEvent $event) {
+ $migration = $event->getMigration();
+ $configuration = $migration->getDestinationConfiguration();
+ $entity_types = NestedArray::getValue($configuration, ['content_translation_update_definitions']);
+ if ($entity_types) {
+ $entity_types = array_intersect_key($this->entityManager->getDefinitions(), array_flip($entity_types));
+ $this->updateDefinitions($entity_types);
+ }
+ }
+
+ /**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[ConfigEvents::IMPORT][] = ['onConfigImporterImport', 60];
+ if (class_exists('\Drupal\migrate\Event\MigrateEvents')) {
+ $events[MigrateEvents::POST_IMPORT][] = ['onMigrateImport'];
+ }
return $events;
}
diff --git a/core/modules/language/migration_templates/d6_language_content_settings.yml b/core/modules/language/migration_templates/d6_language_content_settings.yml
index e5dc750..3bf9078 100644
--- a/core/modules/language/migration_templates/d6_language_content_settings.yml
+++ b/core/modules/language/migration_templates/d6_language_content_settings.yml
@@ -1,5 +1,6 @@
id: d6_language_content_settings
label: Drupal 6 language content settings
+
migration_tags:
- Drupal 6
source:
@@ -39,6 +40,8 @@ process:
2: true
destination:
plugin: entity:language_content_settings
+ content_translation_update_definitions:
+ - node
migration_dependencies:
required:
- d6_node_type
diff --git a/core/modules/language/migration_templates/d7_language_content_settings.yml b/core/modules/language/migration_templates/d7_language_content_settings.yml
index cbe935a..09437fa 100644
--- a/core/modules/language/migration_templates/d7_language_content_settings.yml
+++ b/core/modules/language/migration_templates/d7_language_content_settings.yml
@@ -39,6 +39,8 @@ process:
2: true
destination:
plugin: entity:language_content_settings
+ content_translation_update_definitions:
+ - node
migration_dependencies:
required:
- d7_node_type
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/DestinationBase.php b/core/modules/migrate/src/Plugin/migrate/destination/DestinationBase.php
index b4cf30b..18a95e6 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/DestinationBase.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/DestinationBase.php
@@ -94,8 +94,10 @@ abstract class DestinationBase extends PluginBase implements MigrateDestinationI
*
* @param array $id_map
* The map row data for the item.
+ * @param int $update_action
+ * The rollback action to take if we are updating an existing item.
*/
- protected function setRollbackAction(array $id_map) {
+ protected function setRollbackAction(array $id_map, $update_action = MigrateIdMapInterface::ROLLBACK_PRESERVE) {
// If the entity we're updating was previously migrated by us, preserve the
// existing rollback action.
if (isset($id_map['sourceid1'])) {
@@ -104,7 +106,7 @@ abstract class DestinationBase extends PluginBase implements MigrateDestinationI
// 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;
+ $this->rollbackAction = $update_action;
}
}
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/Entity.php b/core/modules/migrate/src/Plugin/migrate/destination/Entity.php
index abf2dc9..1b2c2e7 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/Entity.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/Entity.php
@@ -124,7 +124,8 @@ abstract class Entity extends DestinationBase implements ContainerFactoryPluginI
protected function getEntity(Row $row, array $old_destination_id_values) {
$entity_id = reset($old_destination_id_values) ?: $this->getEntityId($row);
if (!empty($entity_id) && ($entity = $this->storage->load($entity_id))) {
- $this->updateEntity($entity, $row);
+ // Allow updateEntity() to change the entity.
+ $entity = $this->updateEntity($entity, $row) ?: $entity;
}
else {
// Attempt to ensure we always have a bundle.
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php b/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php
index 6a2fb98..3617f38 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php
@@ -7,6 +7,7 @@ use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
+use Drupal\Core\TypedData\TranslatableInterface;
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\MigrateException;
@@ -85,7 +86,12 @@ class EntityContentBase extends Entity {
if (!$entity) {
throw new MigrateException('Unable to get entity');
}
- return $this->save($entity, $old_destination_id_values);
+
+ $ids = $this->save($entity, $old_destination_id_values);
+ if (!empty($this->configuration['translations'])) {
+ $ids[] = $entity->language()->getId();
+ }
+ return $ids;
}
/**
@@ -105,11 +111,31 @@ class EntityContentBase extends Entity {
}
/**
+ * Get whether this destination is for translations.
+ *
+ * @return bool
+ * Whether this destination is for translations.
+ */
+ protected function isTranslationDestination() {
+ return !empty($this->configuration['translations']);
+ }
+
+ /**
* {@inheritdoc}
*/
public function getIds() {
$id_key = $this->getKey('id');
$ids[$id_key]['type'] = 'integer';
+
+ if ($this->isTranslationDestination()) {
+ if ($key = $this->getKey('langcode')) {
+ $ids[$key]['type'] = 'string';
+ }
+ else {
+ throw new MigrateException('This entity type does not support translation.');
+ }
+ }
+
return $ids;
}
@@ -120,8 +146,29 @@ class EntityContentBase extends Entity {
* The entity to update.
* @param \Drupal\migrate\Row $row
* The row object to update from.
+ *
+ * @return NULL|\Drupal\Core\Entity\EntityInterface
+ * An updated entity, or NULL if it's the same as the one passed in.
*/
protected function updateEntity(EntityInterface $entity, Row $row) {
+ // By default, an update will be preserved.
+ $rollback_action = MigrateIdMapInterface::ROLLBACK_PRESERVE;
+
+ // Make sure we have the right translation.
+ if ($this->isTranslationDestination()) {
+ $property = $this->storage->getEntityType()->getKey('langcode');
+ if ($row->hasDestinationProperty($property)) {
+ $language = $row->getDestinationProperty($property);
+ if (!$entity->hasTranslation($language)) {
+ $entity->addTranslation($language);
+
+ // We're adding a translation, so delete it on rollback.
+ $rollback_action = MigrateIdMapInterface::ROLLBACK_DELETE;
+ }
+ $entity = $entity->getTranslation($language);
+ }
+ }
+
// If the migration has specified a list of properties to be overwritten,
// clone the row with an empty set of destination values, and re-add only
// the specified properties.
@@ -140,7 +187,10 @@ class EntityContentBase extends Entity {
}
}
- $this->setRollbackAction($row->getIdMap());
+ $this->setRollbackAction($row->getIdMap(), $rollback_action);
+
+ // We might have a different (translated) entity, so return it.
+ return $entity;
}
/**
@@ -185,4 +235,32 @@ class EntityContentBase extends Entity {
}
}
+ /**
+ * {@inheritdoc}
+ */
+ public function rollback(array $destination_identifier) {
+ if ($this->isTranslationDestination()) {
+ // Attempt to remove the translation.
+ $entity = $this->storage->load(reset($destination_identifier));
+ if ($entity && $entity instanceof TranslatableInterface) {
+ if ($key = $this->getKey('langcode')) {
+ if (isset($destination_identifier[$key])) {
+ $langcode = $destination_identifier[$key];
+ if ($entity->hasTranslation($langcode)) {
+ // Make sure we don't remove the default translation.
+ $translation = $entity->getTranslation($langcode);
+ if (!$translation->isDefaultTranslation()) {
+ $entity->removeTranslation($langcode);
+ $entity->save();
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ parent::rollback($destination_identifier);
+ }
+ }
+
}
diff --git a/core/modules/migrate/tests/modules/migrate_external_translated_test/migrate_external_translated_test.info.yml b/core/modules/migrate/tests/modules/migrate_external_translated_test/migrate_external_translated_test.info.yml
new file mode 100644
index 0000000..065d512
--- /dev/null
+++ b/core/modules/migrate/tests/modules/migrate_external_translated_test/migrate_external_translated_test.info.yml
@@ -0,0 +1,8 @@
+name: 'Migration external translated test'
+type: module
+package: Testing
+version: VERSION
+core: 8.x
+dependencies:
+ - node
+ - migrate
diff --git a/core/modules/migrate/tests/modules/migrate_external_translated_test/migrations/migrate.migration.external_translated_test_node.yml b/core/modules/migrate/tests/modules/migrate_external_translated_test/migrations/migrate.migration.external_translated_test_node.yml
new file mode 100644
index 0000000..f643b60
--- /dev/null
+++ b/core/modules/migrate/tests/modules/migrate_external_translated_test/migrations/migrate.migration.external_translated_test_node.yml
@@ -0,0 +1,19 @@
+id: external_translated_test_node
+label: External translated content
+source:
+ plugin: migrate_external_translated_test
+ default_lang: true
+ constants:
+ type: external_test
+process:
+ type: constants/type
+ title: title
+ langcode:
+ plugin: static_map
+ source: lang
+ map:
+ English: en
+ French: fr
+ Spanish: es
+destination:
+ plugin: entity:node
diff --git a/core/modules/migrate/tests/modules/migrate_external_translated_test/migrations/migrate.migration.external_translated_test_node_translation.yml b/core/modules/migrate/tests/modules/migrate_external_translated_test/migrations/migrate.migration.external_translated_test_node_translation.yml
new file mode 100644
index 0000000..ff29084
--- /dev/null
+++ b/core/modules/migrate/tests/modules/migrate_external_translated_test/migrations/migrate.migration.external_translated_test_node_translation.yml
@@ -0,0 +1,27 @@
+id: external_translated_test_node_translation
+label: External translated content translations
+source:
+ plugin: migrate_external_translated_test
+ default_lang: false
+ constants:
+ type: external_test
+process:
+ nid:
+ plugin: migration
+ source: name
+ migration: external_translated_test_node
+ type: constants/type
+ title: title
+ langcode:
+ plugin: static_map
+ source: lang
+ map:
+ English: en
+ French: fr
+ Spanish: es
+destination:
+ plugin: entity:node
+ translations: true
+migration_dependencies:
+ required:
+ - external_translated_test_node
diff --git a/core/modules/migrate/tests/modules/migrate_external_translated_test/src/Plugin/migrate/source/MigrateExternalTranslatedTestSource.php b/core/modules/migrate/tests/modules/migrate_external_translated_test/src/Plugin/migrate/source/MigrateExternalTranslatedTestSource.php
new file mode 100644
index 0000000..ceda6d8
--- /dev/null
+++ b/core/modules/migrate/tests/modules/migrate_external_translated_test/src/Plugin/migrate/source/MigrateExternalTranslatedTestSource.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Drupal\migrate_external_translated_test\Plugin\migrate\source;
+
+use Drupal\migrate\Plugin\migrate\source\SourcePluginBase;
+
+/**
+ * A simple migrate source for our tests.
+ *
+ * @MigrateSource(
+ * id = "migrate_external_translated_test"
+ * )
+ */
+class MigrateExternalTranslatedTestSource extends SourcePluginBase {
+
+ /**
+ * The data to import.
+ *
+ * @var array
+ */
+ protected $import = [
+ ['name' => 'cat', 'title' => 'Cat', 'lang' => 'English'],
+ ['name' => 'cat', 'title' => 'Chat', 'lang' => 'French'],
+ ['name' => 'cat', 'title' => 'Gato', 'lang' => 'Spanish'],
+ ['name' => 'dog', 'title' => 'Dog', 'lang' => 'English'],
+ ['name' => 'dog', 'title' => 'Chien', 'lang' => 'French'],
+ ['name' => 'monkey', 'title' => 'Monkey', 'lang' => 'English'],
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ public function fields() {
+ return [
+ 'name' => $this->t('Unique name'),
+ 'title' => $this->t('Title'),
+ 'lang' => $this->t('Language'),
+ ];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString() {
+ return '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getIds() {
+ $ids['name']['type'] = 'string';
+ if (!$this->configuration['default_lang']) {
+ $ids['lang']['type'] = 'string';
+ }
+ return $ids;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function initializeIterator() {
+ $data = [];
+
+ // Keep the rows with the right languages.
+ $want_default = $this->configuration['default_lang'];
+ foreach ($this->import as $row) {
+ $is_english = $row['lang'] == 'English';
+ if ($want_default == $is_english) {
+ $data[] = $row;
+ }
+ }
+
+ return new \ArrayIterator($data);
+ }
+
+}
diff --git a/core/modules/migrate/tests/src/Kernel/MigrateEntityContentBaseTest.php b/core/modules/migrate/tests/src/Kernel/MigrateEntityContentBaseTest.php
new file mode 100644
index 0000000..352b660
--- /dev/null
+++ b/core/modules/migrate/tests/src/Kernel/MigrateEntityContentBaseTest.php
@@ -0,0 +1,159 @@
+<?php
+
+namespace Drupal\Tests\migrate\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
+use Drupal\migrate\Plugin\MigrateIdMapInterface;
+use Drupal\migrate\Plugin\MigrationInterface;
+use Drupal\migrate\Row;
+
+/**
+ * Tests the EntityContentBase destination.
+ *
+ * @group migrate
+ */
+class MigrateEntityContentBaseTest extends KernelTestBase {
+
+ /**
+ * Modules to enable.
+ *
+ * @var array
+ */
+ public static $modules = ['migrate', 'user', 'language', 'entity_test'];
+
+ /**
+ * The storage for entity_test_mul.
+ *
+ * @var \Drupal\Core\Entity\ContentEntityStorageInterface
+ */
+ protected $storage;
+
+ /**
+ * A content migrate destination.
+ *
+ * @var \Drupal\migrate\Plugin\MigrateDestinationInterface
+ */
+ protected $destination;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+ $this->installEntitySchema('entity_test_mul');
+
+ ConfigurableLanguage::createFromLangcode('en')->save();
+ ConfigurableLanguage::createFromLangcode('fr')->save();
+
+ $this->storage = $this->container->get('entity.manager')->getStorage('entity_test_mul');
+ }
+
+ /**
+ * Check the existing translations of an entity.
+ *
+ * @param int $id
+ * The entity ID.
+ * @param string $default
+ * The expected default translation language code.
+ * @param string[] $others
+ * The expected other translation language codes.
+ */
+ protected function assertTranslations($id, $default, $others = []) {
+ $entity = $this->storage->load($id);
+ $this->assertTrue($entity, "Entity exists");
+ $this->assertEquals($default, $entity->language()->getId(), "Entity default translation");
+ $translations = array_keys($entity->getTranslationLanguages(FALSE));
+ sort($others);
+ sort($translations);
+ $this->assertEquals($others, $translations, "Entity translations");
+ }
+
+ /**
+ * Create the destination plugin to test.
+ *
+ * @param array $configuration
+ * The plugin configuration.
+ */
+ protected function createDestination(array $configuration) {
+ $this->destination = new EntityContentBase(
+ $configuration,
+ 'fake_plugin_id',
+ [],
+ $this->getMock(MigrationInterface::class),
+ $this->storage,
+ [],
+ $this->container->get('entity.manager'),
+ $this->container->get('plugin.manager.field.field_type')
+ );
+ }
+
+ /**
+ * Test importing and rolling back translated entities.
+ */
+ public function testTranslated() {
+ // Create a destination.
+ $this->createDestination(['translations' => TRUE]);
+
+ // Create some pre-existing entities.
+ $this->storage->create(['id' => 1, 'langcode' => 'en'])->save();
+ $this->storage->create(['id' => 2, 'langcode' => 'fr'])->save();
+ $translated = $this->storage->create(['id' => 3, 'langcode' => 'en']);
+ $translated->save();
+ $translated->addTranslation('fr')->save();
+
+ // Pre-assert that things are as expected.
+ $this->assertTranslations(1, 'en');
+ $this->assertTranslations(2, 'fr');
+ $this->assertTranslations(3, 'en', ['fr']);
+ $this->assertFalse($this->storage->load(4));
+
+ $destination_rows = [
+ // Existing default translation.
+ ['id' => 1, 'langcode' => 'en', 'action' => MigrateIdMapInterface::ROLLBACK_PRESERVE],
+ // New translation.
+ ['id' => 2, 'langcode' => 'en', 'action' => MigrateIdMapInterface::ROLLBACK_DELETE],
+ // Existing non-default translation.
+ ['id' => 3, 'langcode' => 'fr', 'action' => MigrateIdMapInterface::ROLLBACK_PRESERVE],
+ // Brand new row.
+ ['id' => 4, 'langcode' => 'fr', 'action' => MigrateIdMapInterface::ROLLBACK_DELETE],
+ ];
+ $rollback_actions = [];
+
+ // Import some rows.
+ foreach ($destination_rows as $idx => $destination_row) {
+ $row = new Row([], []);
+ foreach ($destination_row as $key => $value) {
+ $row->setDestinationProperty($key, $value);
+ }
+ $this->destination->import($row);
+
+ // Check that the rollback action is correct, and save it.
+ $this->assertEquals($destination_row['action'], $this->destination->rollbackAction());
+ $rollback_actions[$idx] = $this->destination->rollbackAction();
+ }
+
+ $this->assertTranslations(1, 'en');
+ $this->assertTranslations(2, 'fr', ['en']);
+ $this->assertTranslations(3, 'en', ['fr']);
+ $this->assertTranslations(4, 'fr');
+
+ // Rollback the rows.
+ foreach ($destination_rows as $idx => $destination_row) {
+ if ($rollback_actions[$idx] == MigrateIdMapInterface::ROLLBACK_DELETE) {
+ $this->destination->rollback($destination_row);
+ }
+ }
+
+ // No change, update of existing translation.
+ $this->assertTranslations(1, 'en');
+ // Remove added translation.
+ $this->assertTranslations(2, 'fr');
+ // No change, update of existing translation.
+ $this->assertTranslations(3, 'en', ['fr']);
+ // No change, can't remove default translation.
+ $this->assertTranslations(4, 'fr');
+ }
+
+}
diff --git a/core/modules/migrate/tests/src/Kernel/MigrateExternalTranslatedTest.php b/core/modules/migrate/tests/src/Kernel/MigrateExternalTranslatedTest.php
new file mode 100644
index 0000000..ce9c013
--- /dev/null
+++ b/core/modules/migrate/tests/src/Kernel/MigrateExternalTranslatedTest.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace Drupal\Tests\migrate\Kernel;
+
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\migrate\MigrateExecutable;
+use Drupal\node\Entity\NodeType;
+
+/**
+ * Tests migrating non-Drupal translated content.
+ *
+ * Ensure it's possible to migrate in translations, even if there's no nid or
+ * tnid property on the source.
+ *
+ * @group migrate
+ */
+class MigrateExternalTranslatedTest extends MigrateTestBase {
+
+ /**
+ * {@inheritdoc}
+ *
+ * @todo: Remove migrate_drupal when https://www.drupal.org/node/2560795 is
+ * fixed.
+ */
+ public static $modules = ['system', 'user', 'language', 'node', 'field', 'migrate_drupal', 'migrate_external_translated_test'];
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ $this->installSchema('system', ['sequences']);
+ $this->installSchema('node', array('node_access'));
+ $this->installEntitySchema('user');
+ $this->installEntitySchema('node');
+
+ // Create some languages.
+ ConfigurableLanguage::createFromLangcode('en')->save();
+ ConfigurableLanguage::createFromLangcode('fr')->save();
+ ConfigurableLanguage::createFromLangcode('es')->save();
+
+ // Create a content type.
+ NodeType::create([
+ 'type' => 'external_test',
+ 'name' => 'Test node type',
+ ])->save();
+ }
+
+ /**
+ * Test importing and rolling back our data.
+ */
+ public function testMigrations() {
+ /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
+ $storage = $this->container->get('entity.manager')->getStorage('node');
+ $this->assertEquals(0, count($storage->loadMultiple()));
+
+ // Run the migrations.
+ $migration_ids = ['external_translated_test_node', 'external_translated_test_node_translation'];
+ $this->executeMigrations($migration_ids);
+ $this->assertEquals(3, count($storage->loadMultiple()));
+
+ $node = $storage->load(1);
+ $this->assertEquals('en', $node->language()->getId());
+ $this->assertEquals('Cat', $node->title->value);
+ $this->assertEquals('Chat', $node->getTranslation('fr')->title->value);
+ $this->assertEquals('Gato', $node->getTranslation('es')->title->value);
+
+ $node = $storage->load(2);
+ $this->assertEquals('en', $node->language()->getId());
+ $this->assertEquals('Dog', $node->title->value);
+ $this->assertEquals('Chien', $node->getTranslation('fr')->title->value);
+ $this->assertFalse($node->hasTranslation('es'), "No spanish translation for node 2");
+
+ $node = $storage->load(3);
+ $this->assertEquals('en', $node->language()->getId());
+ $this->assertEquals('Monkey', $node->title->value);
+ $this->assertFalse($node->hasTranslation('fr'), "No french translation for node 3");
+ $this->assertFalse($node->hasTranslation('es'), "No spanish translation for node 3");
+
+ $this->assertNull($storage->load(4), "No node 4 migrated");
+
+ // Roll back the migrations.
+ foreach ($migration_ids as $migration_id) {
+ $migration = $this->getMigration($migration_id);
+ $executable = new MigrateExecutable($migration, $this);
+ $executable->rollback();
+ }
+
+ $this->assertEquals(0, count($storage->loadMultiple()));
+ }
+
+}
diff --git a/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php b/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php
index da20b49..33aec58 100644
--- a/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php
+++ b/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php
@@ -8,6 +8,7 @@
namespace Drupal\Tests\migrate\Unit\Plugin\migrate\destination;
use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\ContentEntityType;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
@@ -97,6 +98,33 @@ class EntityContentBaseTest extends UnitTestCase {
$destination->import(new Row([], []));
}
+ /**
+ * Test that translation destination fails for untranslatable entities.
+ *
+ * @expectedException \Drupal\migrate\MigrateException
+ * @expectedExceptionMessage This entity type does not support translation
+ */
+ public function testUntranslatable() {
+ // An entity type without a language.
+ $entity_type = $this->prophesize(ContentEntityType::class);
+ $entity_type->getKey('langcode')->willReturn('');
+ $entity_type->getKey('id')->willReturn('id');
+
+ $this->storage->getEntityType()->willReturn($entity_type->reveal());
+
+ $destination = new EntityTestDestination(
+ [ 'translations' => TRUE ],
+ '',
+ [],
+ $this->migration->reveal(),
+ $this->storage->reveal(),
+ [],
+ $this->entityManager->reveal(),
+ $this->prophesize(FieldTypePluginManagerInterface::class)->reveal()
+ );
+ $destination->getIds();
+ }
+
}
/**
diff --git a/core/modules/migrate_drupal/tests/fixtures/drupal6.php b/core/modules/migrate_drupal/tests/fixtures/drupal6.php
index 97ed43e..347b2f2 100644
--- a/core/modules/migrate_drupal/tests/fixtures/drupal6.php
+++ b/core/modules/migrate_drupal/tests/fixtures/drupal6.php
@@ -8034,7 +8034,17 @@ $connection->insert('history')
->values(array(
'uid' => '1',
'nid' => '9',
- 'timestamp' => '1457655127',
+ 'timestamp' => '1468384961',
+))
+->values(array(
+ 'uid' => '1',
+ 'nid' => '12',
+ 'timestamp' => '1468384823',
+))
+->values(array(
+ 'uid' => '1',
+ 'nid' => '13',
+ 'timestamp' => '1468384931',
))
->execute();
@@ -34709,7 +34719,7 @@ $connection->insert('menu_router')
'access_callback' => 'user_access',
'access_arguments' => 'a:1:{i:0;s:24:"administer content types";}',
'page_callback' => 'drupal_get_form',
- 'page_arguments' => 'a:2:{i:0;s:14:"node_type_form";i:1;O:8:"stdClass":14:{s:4:"type";s:7:"company";s:4:"name";s:7:"Company";s:6:"module";s:4:"node";s:11:"description";s:17:"Company node type";s:4:"help";s:0:"";s:9:"has_title";s:1:"1";s:11:"title_label";s:4:"Name";s:8:"has_body";s:1:"1";s:10:"body_label";s:11:"Description";s:14:"min_word_count";s:2:"20";s:6:"custom";s:1:"0";s:8:"modified";s:1:"0";s:6:"locked";s:1:"0";s:9:"orig_type";s:7:"company";}}',
+ 'page_arguments' => 'a:2:{i:0;s:14:"node_type_form";i:1;O:8:"stdClass":14:{s:4:"type";s:7:"company";s:4:"name";s:7:"Company";s:6:"module";s:4:"node";s:11:"description";s:17:"Company node type";s:4:"help";s:0:"";s:9:"has_title";s:1:"1";s:11:"title_label";s:4:"Name";s:8:"has_body";s:1:"1";s:10:"body_label";s:11:"Description";s:14:"min_word_count";s:1:"0";s:6:"custom";s:1:"0";s:8:"modified";s:1:"1";s:6:"locked";s:1:"0";s:9:"orig_type";s:7:"company";}}',
'fit' => '15',
'number_parts' => '4',
'tab_parent' => '',
@@ -34731,7 +34741,7 @@ $connection->insert('menu_router')
'access_callback' => 'user_access',
'access_arguments' => 'a:1:{i:0;s:24:"administer content types";}',
'page_callback' => 'drupal_get_form',
- 'page_arguments' => 'a:2:{i:0;s:24:"node_type_delete_confirm";i:1;O:8:"stdClass":14:{s:4:"type";s:7:"company";s:4:"name";s:7:"Company";s:6:"module";s:4:"node";s:11:"description";s:17:"Company node type";s:4:"help";s:0:"";s:9:"has_title";s:1:"1";s:11:"title_label";s:4:"Name";s:8:"has_body";s:1:"1";s:10:"body_label";s:11:"Description";s:14:"min_word_count";s:2:"20";s:6:"custom";s:1:"0";s:8:"modified";s:1:"0";s:6:"locked";s:1:"0";s:9:"orig_type";s:7:"company";}}',
+ 'page_arguments' => 'a:2:{i:0;s:24:"node_type_delete_confirm";i:1;O:8:"stdClass":14:{s:4:"type";s:7:"company";s:4:"name";s:7:"Company";s:6:"module";s:4:"node";s:11:"description";s:17:"Company node type";s:4:"help";s:0:"";s:9:"has_title";s:1:"1";s:11:"title_label";s:4:"Name";s:8:"has_body";s:1:"1";s:10:"body_label";s:11:"Description";s:14:"min_word_count";s:1:"0";s:6:"custom";s:1:"0";s:8:"modified";s:1:"1";s:6:"locked";s:1:"0";s:9:"orig_type";s:7:"company";}}',
'fit' => '31',
'number_parts' => '5',
'tab_parent' => '',
@@ -34841,7 +34851,7 @@ $connection->insert('menu_router')
'access_callback' => 'user_access',
'access_arguments' => 'a:1:{i:0;s:24:"administer content types";}',
'page_callback' => 'drupal_get_form',
- 'page_arguments' => 'a:2:{i:0;s:14:"node_type_form";i:1;O:8:"stdClass":14:{s:4:"type";s:7:"company";s:4:"name";s:7:"Company";s:6:"module";s:4:"node";s:11:"description";s:17:"Company node type";s:4:"help";s:0:"";s:9:"has_title";s:1:"1";s:11:"title_label";s:4:"Name";s:8:"has_body";s:1:"1";s:10:"body_label";s:11:"Description";s:14:"min_word_count";s:2:"20";s:6:"custom";s:1:"0";s:8:"modified";s:1:"0";s:6:"locked";s:1:"0";s:9:"orig_type";s:7:"company";}}',
+ 'page_arguments' => 'a:2:{i:0;s:14:"node_type_form";i:1;O:8:"stdClass":14:{s:4:"type";s:7:"company";s:4:"name";s:7:"Company";s:6:"module";s:4:"node";s:11:"description";s:17:"Company node type";s:4:"help";s:0:"";s:9:"has_title";s:1:"1";s:11:"title_label";s:4:"Name";s:8:"has_body";s:1:"1";s:10:"body_label";s:11:"Description";s:14:"min_word_count";s:1:"0";s:6:"custom";s:1:"0";s:8:"modified";s:1:"1";s:6:"locked";s:1:"0";s:9:"orig_type";s:7:"company";}}',
'fit' => '31',
'number_parts' => '5',
'tab_parent' => 'admin/content/node-type/company',
@@ -41334,6 +41344,40 @@ $connection->insert('node')
'tnid' => '0',
'translate' => '0',
))
+->values(array(
+ 'nid' => '10',
+ 'vid' => '13',
+ 'type' => 'page',
+ 'language' => 'en',
+ 'title' => 'The Real McCoy',
+ 'uid' => '1',
+ 'status' => '1',
+ 'created' => '1444238800',
+ 'changed' => '1444238808',
+ 'comment' => '2',
+ 'promote' => '1',
+ 'moderate' => '0',
+ 'sticky' => '0',
+ 'tnid' => '10',
+ 'translate' => '0',
+))
+->values(array(
+ 'nid' => '11',
+ 'vid' => '14',
+ 'type' => 'page',
+ 'language' => 'fr',
+ 'title' => 'Le Vrai McCoy',
+ 'uid' => '1',
+ 'status' => '1',
+ 'created' => '1444239050',
+ 'changed' => '1444239050',
+ 'comment' => '2',
+ 'promote' => '1',
+ 'moderate' => '0',
+ 'sticky' => '0',
+ 'tnid' => '10',
+ 'translate' => '0',
+))
->execute();
$connection->schema()->createTable('node_access', array(
@@ -41464,6 +41508,13 @@ $connection->insert('node_comment_statistics')
'comment_count',
))
->values(array(
+ 'nid' => '0',
+ 'last_comment_timestamp' => '1468384735',
+ 'last_comment_name' => NULL,
+ 'last_comment_uid' => '1',
+ 'comment_count' => '0',
+))
+->values(array(
'nid' => '1',
'last_comment_timestamp' => '1388271197',
'last_comment_name' => NULL,
@@ -41479,7 +41530,14 @@ $connection->insert('node_comment_statistics')
))
->values(array(
'nid' => '9',
- 'last_comment_timestamp' => '1444671588',
+ 'last_comment_timestamp' => '1444238800',
+ 'last_comment_name' => NULL,
+ 'last_comment_uid' => '1',
+ 'comment_count' => '0',
+))
+->values(array(
+ 'nid' => '10',
+ 'last_comment_timestamp' => '1444239050',
'last_comment_name' => NULL,
'last_comment_uid' => '1',
'comment_count' => '0',
@@ -41727,6 +41785,28 @@ $connection->insert('node_revisions')
'timestamp' => '1444671588',
'format' => '1',
))
+->values(array(
+ 'nid' => '10',
+ 'vid' => '13',
+ 'uid' => '1',
+ 'title' => 'The Real McCoy',
+ 'body' => "In the original, Queen's English.",
+ 'teaser' => "In the original, Queen's English.",
+ 'log' => '',
+ 'timestamp' => '1444238808',
+ 'format' => '1',
+))
+->values(array(
+ 'nid' => '11',
+ 'vid' => '14',
+ 'uid' => '1',
+ 'title' => 'Le Vrai McCoy',
+ 'body' => 'Ooh là là!',
+ 'teaser' => 'Ooh là là!',
+ 'log' => '',
+ 'timestamp' => '1444239050',
+ 'format' => '1',
+))
->execute();
$connection->schema()->createTable('node_type', array(
@@ -41861,9 +41941,9 @@ $connection->insert('node_type')
'title_label' => 'Name',
'has_body' => '1',
'body_label' => 'Description',
- 'min_word_count' => '20',
+ 'min_word_count' => '0',
'custom' => '0',
- 'modified' => '0',
+ 'modified' => '1',
'locked' => '0',
'orig_type' => 'company',
))
@@ -44465,8 +44545,8 @@ $connection->insert('users')
'signature' => '',
'signature_format' => '0',
'created' => '0',
- 'access' => '1458198052',
- 'login' => '1458193160',
+ 'access' => '1468384823',
+ 'login' => '1468384420',
'status' => '1',
'timezone' => NULL,
'language' => '',
@@ -44810,12 +44890,16 @@ $connection->insert('variable')
'value' => 's:1:"2";',
))
->values(array(
+ 'name' => 'comment_company',
+ 'value' => 's:1:"2";',
+))
+->values(array(
'name' => 'comment_controls_article',
'value' => 'i:3;',
))
->values(array(
'name' => 'comment_controls_company',
- 'value' => 'i:3;',
+ 'value' => 's:1:"3";',
))
->values(array(
'name' => 'comment_controls_employee',
@@ -44855,7 +44939,7 @@ $connection->insert('variable')
))
->values(array(
'name' => 'comment_default_mode_company',
- 'value' => 'i:4;',
+ 'value' => 's:1:"4";',
))
->values(array(
'name' => 'comment_default_mode_employee',
@@ -44895,7 +44979,7 @@ $connection->insert('variable')
))
->values(array(
'name' => 'comment_default_order_company',
- 'value' => 'i:1;',
+ 'value' => 's:1:"1";',
))
->values(array(
'name' => 'comment_default_order_employee',
@@ -44935,7 +45019,7 @@ $connection->insert('variable')
))
->values(array(
'name' => 'comment_default_per_page_company',
- 'value' => 'i:50;',
+ 'value' => 's:2:"50";',
))
->values(array(
'name' => 'comment_default_per_page_employee',
@@ -44975,7 +45059,7 @@ $connection->insert('variable')
))
->values(array(
'name' => 'comment_form_location_company',
- 'value' => 'i:0;',
+ 'value' => 's:1:"0";',
))
->values(array(
'name' => 'comment_form_location_employee',
@@ -45019,7 +45103,7 @@ $connection->insert('variable')
))
->values(array(
'name' => 'comment_preview_company',
- 'value' => 'i:1;',
+ 'value' => 's:1:"1";',
))
->values(array(
'name' => 'comment_preview_employee',
@@ -45063,7 +45147,7 @@ $connection->insert('variable')
))
->values(array(
'name' => 'comment_subject_field_company',
- 'value' => 'i:1;',
+ 'value' => 's:1:"1";',
))
->values(array(
'name' => 'comment_subject_field_employee',
@@ -45426,6 +45510,10 @@ $connection->insert('variable')
'value' => 's:5:"never";',
))
->values(array(
+ 'name' => 'event_nodeapi_company',
+ 'value' => 's:5:"never";',
+))
+->values(array(
'name' => 'event_nodeapi_event',
'value' => 's:3:"all";',
))
@@ -45487,7 +45575,11 @@ $connection->insert('variable')
))
->values(array(
'name' => 'form_build_id_article',
- 'value' => 's:48:"form-mXZfFJxcCFGB80PPYtNOuwYbho6-xKTvrRLb3TAMkic";',
+ 'value' => 's:48:"form-t2zKJflpBD4rpYoGQH33ckjjWAYdo5lF3Hl1O_YnWyE";',
+))
+->values(array(
+ 'name' => 'form_build_id_company',
+ 'value' => 's:48:"form-jFw2agRukPxjG5dG-N6joZLyoxXmCoxTzua0HUciqK0";',
))
->values(array(
'name' => 'forum_block_num_0',
@@ -45590,6 +45682,10 @@ $connection->insert('variable')
'value' => 'a:1:{i:0;s:6:"status";}',
))
->values(array(
+ 'name' => 'node_options_company',
+ 'value' => 'a:2:{i:0;s:6:"status";i:1;s:7:"promote";}',
+))
+->values(array(
'name' => 'node_options_forum',
'value' => 'a:1:{i:0;s:6:"status";}',
))
@@ -45786,6 +45882,10 @@ $connection->insert('variable')
'value' => 'b:0;',
))
->values(array(
+ 'name' => 'upload_company',
+ 'value' => 's:1:"1";',
+))
+->values(array(
'name' => 'upload_page',
'value' => 'b:1;',
))
diff --git a/core/modules/migrate_drupal/tests/src/Kernel/d6/EntityContentBaseTest.php b/core/modules/migrate_drupal/tests/src/Kernel/d6/EntityContentBaseTest.php
index bdac5c9..5074473 100644
--- a/core/modules/migrate_drupal/tests/src/Kernel/d6/EntityContentBaseTest.php
+++ b/core/modules/migrate_drupal/tests/src/Kernel/d6/EntityContentBaseTest.php
@@ -4,7 +4,10 @@ namespace Drupal\Tests\migrate_drupal\Kernel\d6;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\migrate\MigrateExecutable;
+use Drupal\migrate\MigrateMessageInterface;
use Drupal\user\Entity\User;
+use Prophecy\Argument;
/**
* @group migrate_drupal
@@ -85,4 +88,40 @@ class EntityContentBaseTest extends MigrateDrupal6TestBase {
$this->assertIdentical('proto@zo.an', $account->getInitialEmail());
}
+ /**
+ * Test that translation destination fails for untranslatable entities.
+ */
+ public function testUntranslatable() {
+ $this->enableModules(['language_test']);
+ $this->installEntitySchema('no_language_entity_test');
+
+ /** @var MigrationInterface $migration */
+ $migration = \Drupal::service('plugin.manager.migration')->createStubMigration([
+ 'source' => [
+ 'plugin' => 'embedded_data',
+ 'ids' => ['id' => ['type' => 'integer']],
+ 'data_rows' => [['id' => 1]],
+ ],
+ 'process' => [
+ 'id' => 'id',
+ ],
+ 'destination' => [
+ 'plugin' => 'entity:no_language_entity_test',
+ 'translations' => TRUE,
+ ],
+ ]);
+
+ $message = $this->prophesize(MigrateMessageInterface::class);
+ // Match the expected message. Can't use default argument types, because
+ // we need to convert to string from TranslatableMarkup.
+ $argument = Argument::that(function($msg) {
+ return strpos((string) $msg, "This entity type does not support translation") !== FALSE;
+ });
+ $message->display($argument, Argument::any())
+ ->shouldBeCalled();
+
+ $executable = new MigrateExecutable($migration, $message->reveal());
+ $executable->import();
+ }
+
}
diff --git a/core/modules/migrate_drupal/tests/src/Kernel/d6/MigrateDrupal6TestBase.php b/core/modules/migrate_drupal/tests/src/Kernel/d6/MigrateDrupal6TestBase.php
index 72a8095..3a9467e 100644
--- a/core/modules/migrate_drupal/tests/src/Kernel/d6/MigrateDrupal6TestBase.php
+++ b/core/modules/migrate_drupal/tests/src/Kernel/d6/MigrateDrupal6TestBase.php
@@ -89,17 +89,24 @@ abstract class MigrateDrupal6TestBase extends MigrateDrupalTestBase {
/**
* Executes all content migrations.
*
- * @param bool $include_revisions
- * If TRUE, migrates node revisions.
+ * @param array $include
+ * Extra things to include as part of the migrations. Values may be
+ * 'revisions' or 'translations'.
*/
- protected function migrateContent($include_revisions = FALSE) {
+ protected function migrateContent($include = []) {
+ if (in_array('translations', $include)) {
+ $this->executeMigrations(['language']);
+ }
$this->migrateUsers(FALSE);
$this->migrateFields();
$this->installEntitySchema('node');
$this->executeMigrations(['d6_node_settings', 'd6_node']);
- if ($include_revisions) {
+ if (in_array('translations', $include)) {
+ $this->executeMigrations(['translations']);
+ }
+ if (in_array('revisions', $include)) {
$this->executeMigrations(['d6_node_revision']);
}
}
diff --git a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
index 5808c1f..b437852 100644
--- a/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
+++ b/core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
@@ -266,6 +266,14 @@ class MigrateUpgradeForm extends ConfirmFormBase {
'source_module' => 'image',
'destination_module' => 'image',
],
+ 'd6_language_content_settings' => [
+ 'source_module' => 'locale',
+ 'destination_module' => 'language',
+ ],
+ 'd7_language_content_settings' => [
+ 'source_module' => 'locale',
+ 'destination_module' => 'language',
+ ],
'd7_language_negotiation_settings' => [
'source_module' => 'locale',
'destination_module' => 'language',
@@ -290,6 +298,10 @@ class MigrateUpgradeForm extends ConfirmFormBase {
'source_module' => 'node',
'destination_module' => 'node',
],
+ 'd6_node_translation' => [
+ 'source_module' => 'node',
+ 'destination_module' => 'node',
+ ],
'd6_node_revision' => [
'source_module' => 'node',
'destination_module' => 'node',
diff --git a/core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php b/core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php
index 8cf8c8d..c139291 100644
--- a/core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php
+++ b/core/modules/migrate_drupal_ui/src/Tests/MigrateUpgradeTestBase.php
@@ -30,7 +30,7 @@ abstract class MigrateUpgradeTestBase extends WebTestBase {
*
* @var array
*/
- public static $modules = ['migrate_drupal_ui', 'telephone'];
+ public static $modules = ['language', 'content_translation', 'migrate_drupal_ui', 'telephone'];
/**
* {@inheritdoc}
diff --git a/core/modules/migrate_drupal_ui/src/Tests/d6/MigrateUpgrade6Test.php b/core/modules/migrate_drupal_ui/src/Tests/d6/MigrateUpgrade6Test.php
index ea0b588..2a806de 100644
--- a/core/modules/migrate_drupal_ui/src/Tests/d6/MigrateUpgrade6Test.php
+++ b/core/modules/migrate_drupal_ui/src/Tests/d6/MigrateUpgrade6Test.php
@@ -40,14 +40,16 @@ class MigrateUpgrade6Test extends MigrateUpgradeTestBase {
'comment' => 3,
'comment_type' => 2,
'contact_form' => 5,
+ 'configurable_language' => 5,
'editor' => 2,
- 'field_config' => 62,
+ 'field_config' => 63,
'field_storage_config' => 43,
'file' => 7,
'filter_format' => 7,
'image_style' => 5,
+ 'language_content_settings' => 2,
'migration' => 105,
- 'node' => 9,
+ 'node' => 10,
'node_type' => 11,
'rdf_mapping' => 5,
'search_page' => 2,
@@ -57,7 +59,7 @@ class MigrateUpgrade6Test extends MigrateUpgradeTestBase {
'menu' => 8,
'taxonomy_term' => 6,
'taxonomy_vocabulary' => 6,
- 'tour' => 1,
+ 'tour' => 4,
'user' => 7,
'user_role' => 6,
'menu_link_content' => 4,
diff --git a/core/modules/migrate_drupal_ui/src/Tests/d7/MigrateUpgrade7Test.php b/core/modules/migrate_drupal_ui/src/Tests/d7/MigrateUpgrade7Test.php
index 1d3ce61..be807e4 100644
--- a/core/modules/migrate_drupal_ui/src/Tests/d7/MigrateUpgrade7Test.php
+++ b/core/modules/migrate_drupal_ui/src/Tests/d7/MigrateUpgrade7Test.php
@@ -39,6 +39,8 @@ class MigrateUpgrade7Test extends MigrateUpgradeTestBase {
'block_content_type' => 1,
'comment' => 1,
'comment_type' => 7,
+ // Module 'language' comes with 'en', 'und', 'zxx'. Migration adds 'is'.
+ 'configurable_language' => 4,
'contact_form' => 3,
'editor' => 2,
'field_config' => 41,
@@ -46,6 +48,7 @@ class MigrateUpgrade7Test extends MigrateUpgradeTestBase {
'file' => 1,
'filter_format' => 7,
'image_style' => 6,
+ 'language_content_settings' => 1,
'migration' => 59,
'node' => 2,
'node_type' => 6,
@@ -57,7 +60,7 @@ class MigrateUpgrade7Test extends MigrateUpgradeTestBase {
'menu' => 10,
'taxonomy_term' => 18,
'taxonomy_vocabulary' => 3,
- 'tour' => 1,
+ 'tour' => 4,
'user' => 3,
'user_role' => 4,
'menu_link_content' => 9,
diff --git a/core/modules/node/migration_templates/d6_node.yml b/core/modules/node/migration_templates/d6_node.yml
index 1ce67db..f87e666 100644
--- a/core/modules/node/migration_templates/d6_node.yml
+++ b/core/modules/node/migration_templates/d6_node.yml
@@ -6,7 +6,10 @@ deriver: Drupal\node\Plugin\migrate\D6NodeDeriver
source:
plugin: d6_node
process:
- nid: nid
+ # In D6, nodes always have a tnid, but it's zero for untranslated nodes.
+ # We normalize it to equal the nid in that case.
+ # @see \Drupal\node\Plugin\migrate\source\d6\Node::prepareRow().
+ nid: tnid
vid: vid
langcode:
plugin: default_value
diff --git a/core/modules/node/migration_templates/d6_node_translation.yml b/core/modules/node/migration_templates/d6_node_translation.yml
new file mode 100644
index 0000000..b4a2402
--- /dev/null
+++ b/core/modules/node/migration_templates/d6_node_translation.yml
@@ -0,0 +1,52 @@
+id: d6_node_translation
+label: Node translations
+migration_tags:
+ - Drupal 6
+deriver: Drupal\node\Plugin\migrate\D6NodeDeriver
+source:
+ plugin: d6_node
+ translations: true
+process:
+ nid: tnid
+ type: type
+ langcode:
+ plugin: default_value
+ source: language
+ default_value: "und"
+ title: title
+ uid: node_uid
+ status: status
+ created: created
+ changed: changed
+ promote: promote
+ sticky: sticky
+ 'body/format':
+ plugin: migration
+ migration: d6_filter_format
+ source: format
+ 'body/value': body
+ 'body/summary': teaser
+ revision_uid: revision_uid
+ revision_log: log
+ revision_timestamp: timestamp
+
+# unmapped d6 fields.
+# translate
+# moderate
+# comment
+
+destination:
+ plugin: entity:node
+ translations: true
+migration_dependencies:
+ required:
+ - d6_user
+ - d6_node_type
+ - d6_node_settings
+ - d6_filter_format
+ - language
+ optional:
+ - d6_field_instance_widget_settings
+ - d6_field_formatter_settings
+ - d6_upload_field_instance
+provider: migrate_drupal
diff --git a/core/modules/node/src/Plugin/migrate/D6NodeDeriver.php b/core/modules/node/src/Plugin/migrate/D6NodeDeriver.php
index c8a1397..f3e1a92 100644
--- a/core/modules/node/src/Plugin/migrate/D6NodeDeriver.php
+++ b/core/modules/node/src/Plugin/migrate/D6NodeDeriver.php
@@ -38,25 +38,37 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
protected $cckPluginManager;
/**
+ * Whether or not to include translations.
+ *
+ * @var bool
+ */
+ protected $includeTranslations;
+
+ /**
* D6NodeDeriver constructor.
*
* @param string $base_plugin_id
* The base plugin ID for the plugin ID.
* @param \Drupal\Component\Plugin\PluginManagerInterface $cck_manager
* The CCK plugin manager.
+ * @param bool $translations
+ * Whether or not to include translations.
*/
- public function __construct($base_plugin_id, PluginManagerInterface $cck_manager) {
+ public function __construct($base_plugin_id, PluginManagerInterface $cck_manager, $translations) {
$this->basePluginId = $base_plugin_id;
$this->cckPluginManager = $cck_manager;
+ $this->includeTranslations = $translations;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
+ // Translations don't make sense unless we have content_translation.
return new static(
$base_plugin_id,
- $container->get('plugin.manager.migrate.cckfield')
+ $container->get('plugin.manager.migrate.cckfield'),
+ $container->get('module_handler')->moduleExists('content_translation')
);
}
@@ -72,6 +84,11 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
* @see \Drupal\Component\Plugin\Derivative\DeriverBase::getDerivativeDefinition()
*/
public function getDerivativeDefinitions($base_plugin_definition) {
+ if ($base_plugin_definition['id'] == 'd6_node_translation' && !$this->includeTranslations) {
+ // Refuse to generate anything.
+ return $this->derivatives;
+ }
+
// Read all CCK field instance definitions in the source database.
$fields = array();
try {
@@ -100,9 +117,10 @@ class D6NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
$values['source']['node_type'] = $node_type;
$values['destination']['default_bundle'] = $node_type;
- // If this migration is based on the d6_node_revision migration, it
- // should explicitly depend on the corresponding d6_node variant.
- if ($base_plugin_definition['id'] == 'd6_node_revision') {
+ // If this migration is based on the d6_node_revision migration or
+ // is for translations of nodes, it should explicitly depend on the
+ // corresponding d6_node variant.
+ if (in_array($base_plugin_definition['id'], ['d6_node_revision', 'd6_node_translation'])) {
$values['migration_dependencies']['required'][] = 'd6_node:' . $node_type;
}
diff --git a/core/modules/node/src/Plugin/migrate/source/d6/Node.php b/core/modules/node/src/Plugin/migrate/source/d6/Node.php
index 1ed96f9..5ca698f 100644
--- a/core/modules/node/src/Plugin/migrate/source/d6/Node.php
+++ b/core/modules/node/src/Plugin/migrate/source/d6/Node.php
@@ -2,6 +2,7 @@
namespace Drupal\node\Plugin\migrate\source\d6;
+use Drupal\Core\Database\Query\SelectInterface;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
@@ -37,9 +38,11 @@ class Node extends DrupalSqlBase {
* {@inheritdoc}
*/
public function query() {
- // Select node in its last revision.
- $query = $this->select('node_revisions', 'nr')
- ->fields('n', array(
+ $query = $this->select('node_revisions', 'nr');
+ $query->innerJoin('node', 'n', static::JOIN);
+ $this->handleTranslations($query);
+
+ $query->fields('n', array(
'nid',
'type',
'language',
@@ -54,17 +57,16 @@ class Node extends DrupalSqlBase {
'translate',
))
->fields('nr', array(
- 'vid',
'title',
'body',
'teaser',
'log',
'timestamp',
'format',
+ 'vid',
));
$query->addField('n', 'uid', 'node_uid');
$query->addField('nr', 'uid', 'revision_uid');
- $query->innerJoin('node', 'n', static::JOIN);
if (isset($this->configuration['node_type'])) {
$query->condition('n.type', $this->configuration['node_type']);
@@ -123,6 +125,11 @@ class Node extends DrupalSqlBase {
}
}
+ // Make sure we always have a translation set.
+ if ($row->getSourceProperty('tnid') == 0) {
+ $row->setSourceProperty('tnid', $row->getSourceProperty('nid'));
+ }
+
return parent::prepareRow($row);
}
@@ -251,4 +258,22 @@ class Node extends DrupalSqlBase {
return $ids;
}
+ /**
+ * Adapt our query for translations.
+ *
+ * @param \Drupal\Core\Database\Query\SelectInterface
+ * The generated query.
+ */
+ protected function handleTranslations(SelectInterface $query) {
+ // Check whether or not we want translations.
+ if (empty($this->configuration['translations'])) {
+ // No translations: Yield untranslated nodes, or default translations.
+ $query->where('n.tnid = 0 OR n.tnid = n.nid');
+ }
+ else {
+ // Translations: Yield only non-default translations.
+ $query->where('n.tnid <> 0 AND n.tnid <> n.nid');
+ }
+ }
+
}
diff --git a/core/modules/node/src/Plugin/migrate/source/d6/NodeRevision.php b/core/modules/node/src/Plugin/migrate/source/d6/NodeRevision.php
index 41e7a18..3f9a580 100644
--- a/core/modules/node/src/Plugin/migrate/source/d6/NodeRevision.php
+++ b/core/modules/node/src/Plugin/migrate/source/d6/NodeRevision.php
@@ -1,6 +1,7 @@
<?php
namespace Drupal\node\Plugin\migrate\source\d6;
+use Drupal\Core\Database\Query\SelectInterface;
/**
* Drupal 6 node revision source from database.
@@ -37,4 +38,11 @@ class NodeRevision extends Node {
return $ids;
}
+ /**
+ * {@inheritdoc}
+ */
+ protected function handleTranslations(SelectInterface $query) {
+ // @todo in https://www.drupal.org/node/2746541
+ }
+
}
diff --git a/core/modules/node/src/Tests/Migrate/d6/MigrateNodeRevisionTest.php b/core/modules/node/src/Tests/Migrate/d6/MigrateNodeRevisionTest.php
index 05be99f..a02ef3f 100644
--- a/core/modules/node/src/Tests/Migrate/d6/MigrateNodeRevisionTest.php
+++ b/core/modules/node/src/Tests/Migrate/d6/MigrateNodeRevisionTest.php
@@ -13,6 +13,11 @@ class MigrateNodeRevisionTest extends MigrateNodeTestBase {
/**
* {@inheritdoc}
*/
+ public static $modules = ['language', 'content_translation'];
+
+ /**
+ * {@inheritdoc}
+ */
protected function setUp() {
parent::setUp();
$this->executeMigrations(['d6_node', 'd6_node_revision']);
diff --git a/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeDeriverTest.php b/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeDeriverTest.php
new file mode 100644
index 0000000..abce689
--- /dev/null
+++ b/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeDeriverTest.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Drupal\Tests\node\Kernel\Migrate\d6;
+
+use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
+
+/**
+ * Test D6NodeDeriver.
+ *
+ * @group migrate_drupal_6
+ */
+class MigrateNodeDeriverTest extends MigrateDrupal6TestBase {
+ /**
+ * The migration plugin manager.
+ *
+ * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
+ */
+ protected $pluginManager;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ $this->pluginManager = $this->container->get('plugin.manager.migration');
+ }
+
+ /**
+ * Test node translation migrations with translation disabled.
+ */
+ public function testNoTranslations() {
+ // Without content_translation, there should be no translation migrations.
+ $migrations = $this->pluginManager->createInstances('d6_node_translation');
+ $this->assertSame([], $migrations,
+ "No node translation migrations without content_translation");
+ }
+
+ /**
+ * Test node translation migrations with translation enabled.
+ */
+ public function testTranslations() {
+ // With content_translation, there should be translation migrations for
+ // each content type.
+ $this->enableModules(['language', 'content_translation']);
+ $migrations = $this->pluginManager->createInstances('d6_node_translation');
+ $this->assertArrayHasKey('d6_node_translation:story', $migrations,
+ "Node translation migrations exist after content_translation installed");
+ }
+
+}
diff --git a/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php b/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php
index 5f48683..122199f 100644
--- a/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php
+++ b/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeTest.php
@@ -19,11 +19,16 @@ class MigrateNodeTest extends MigrateNodeTestBase {
/**
* {@inheritdoc}
*/
+ public static $modules = ['language', 'content_translation'];
+
+ /**
+ * {@inheritdoc}
+ */
protected function setUp() {
parent::setUp();
$this->setUpMigratedFiles();
$this->installSchema('file', ['file_usage']);
- $this->executeMigrations(['d6_node']);
+ $this->executeMigrations(['language', 'd6_node', 'd6_node_translation']);
}
/**
@@ -85,6 +90,15 @@ class MigrateNodeTest extends MigrateNodeTestBase {
$this->assertSame('Buy it now', $node->field_test_link->title);
$this->assertSame(['attributes' => ['target' => '_blank']], $node->field_test_link->options);
+ // Test that translations are working.
+ $node = Node::load(10);
+ $this->assertIdentical('en', $node->langcode->value);
+ $this->assertIdentical('The Real McCoy', $node->title->value);
+ $this->assertTrue($node->hasTranslation('fr'), "Node 10 has french translation");
+
+ // Node 11 is a translation of node 10, and should not be imported separately.
+ $this->assertNull(Node::load(11), "Node 11 doesn't exist in D8, it was a translation");
+
// Rerun migration with two source database changes.
// 1. Add an invalid link attributes and a different URL and
// title. If only the attributes are changed the error does not occur.
diff --git a/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeByNodeTypeTest.php b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeByNodeTypeTest.php
index 0c31810..6a308ff 100644
--- a/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeByNodeTypeTest.php
+++ b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeByNodeTypeTest.php
@@ -40,7 +40,7 @@ class NodeByNodeTypeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
- 'tnid' => 0,
+ 'tnid' => 1,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 1',
@@ -64,7 +64,7 @@ class NodeByNodeTypeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
- 'tnid' => 0,
+ 'tnid' => 2,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 2',
diff --git a/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeRevisionByNodeTypeTest.php b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeRevisionByNodeTypeTest.php
index 8c78be7..d548ff3 100644
--- a/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeRevisionByNodeTypeTest.php
+++ b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeRevisionByNodeTypeTest.php
@@ -134,7 +134,7 @@ class NodeRevisionByNodeTypeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
- 'tnid' => 0,
+ 'tnid' => 1,
'translate' => 0,
'vid' => 1,
'node_uid' => 1,
@@ -156,7 +156,7 @@ class NodeRevisionByNodeTypeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
- 'tnid' => 0,
+ 'tnid' => 1,
'translate' => 0,
'vid' => 3,
'node_uid' => 1,
diff --git a/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeRevisionTest.php b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeRevisionTest.php
index b1c23f8..752ed9b 100644
--- a/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeRevisionTest.php
+++ b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeRevisionTest.php
@@ -133,7 +133,7 @@ class NodeRevisionTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
- 'tnid' => 0,
+ 'tnid' => 1,
'translate' => 0,
// Node revision fields.
'vid' => 1,
@@ -157,7 +157,7 @@ class NodeRevisionTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
- 'tnid' => 0,
+ 'tnid' => 1,
'translate' => 0,
// Node revision fields.
'vid' => 3,
diff --git a/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTest.php b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTest.php
index ce55d52..b6ce22e 100644
--- a/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTest.php
+++ b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTest.php
@@ -2,16 +2,12 @@
namespace Drupal\Tests\node\Unit\Plugin\migrate\source\d6;
-use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
-
/**
* Tests D6 node source plugin.
*
* @group node
*/
-class NodeTest extends MigrateSqlSourceTestCase {
-
- const PLUGIN_CLASS = 'Drupal\node\Plugin\migrate\source\d6\Node';
+class NodeTest extends NodeTestBase {
protected $migrationConfiguration = array(
'id' => 'test',
@@ -36,7 +32,7 @@ class NodeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
- 'tnid' => 0,
+ 'tnid' => 1,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 1',
@@ -60,7 +56,7 @@ class NodeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
- 'tnid' => 0,
+ 'tnid' => 2,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 2',
@@ -83,7 +79,7 @@ class NodeTest extends MigrateSqlSourceTestCase {
'promote' => 1,
'moderate' => 0,
'sticky' => 0,
- 'tnid' => 0,
+ 'tnid' => 5,
'translate' => 0,
// Node revision fields.
'body' => 'body for node 5',
@@ -98,79 +94,29 @@ class NodeTest extends MigrateSqlSourceTestCase {
),
),
),
+ array(
+ 'nid' => 6,
+ 'vid' => 6,
+ 'type' => 'story',
+ 'language' => 'en',
+ 'title' => 'node title 6',
+ 'uid' => 1,
+ 'status' => 1,
+ 'created' => 1279290909,
+ 'changed' => 1279308994,
+ 'comment' => 0,
+ 'promote' => 1,
+ 'moderate' => 0,
+ 'sticky' => 0,
+ 'tnid' => 6,
+ 'translate' => 0,
+ // Node revision fields.
+ 'body' => 'body for node 6',
+ 'teaser' => 'body for node 6',
+ 'log' => '',
+ 'timestamp' => 1279308994,
+ 'format' => 1,
+ ),
);
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- $this->databaseContents['content_node_field'] = array(
- array(
- 'field_name' => 'field_test_four',
- 'type' => 'number_float',
- 'global_settings' => 'a:0:{}',
- 'required' => '0',
- 'multiple' => '0',
- 'db_storage' => '1',
- 'module' => 'number',
- 'db_columns' => 'a:1:{s:5:"value";a:3:{s:4:"type";s:5:"float";s:8:"not null";b:0;s:8:"sortable";b:1;}}',
- 'active' => '1',
- 'locked' => '0',
- ),
- );
- $this->databaseContents['content_node_field_instance'] = array(
- array(
- 'field_name' => 'field_test_four',
- 'type_name' => 'story',
- 'weight' => '3',
- 'label' => 'Float Field',
- 'widget_type' => 'number',
- 'widget_settings' => 'a:0:{}',
- 'display_settings' => 'a:0:{}',
- 'description' => 'An example float field.',
- 'widget_module' => 'number',
- 'widget_active' => '1',
- ),
- );
- $this->databaseContents['content_type_story'] = array(
- array(
- 'nid' => 5,
- 'vid' => 5,
- 'uid' => 5,
- 'field_test_four_value' => '3.14159',
- ),
- );
- $this->databaseContents['system'] = array(
- array(
- 'type' => 'module',
- 'name' => 'content',
- 'schema_version' => 6001,
- 'status' => TRUE,
- ),
- );
- foreach ($this->expectedResults as $k => $row) {
- foreach (array('nid', 'vid', 'title', 'uid', 'body', 'teaser', 'format', 'timestamp', 'log') as $field) {
- $this->databaseContents['node_revisions'][$k][$field] = $row[$field];
- switch ($field) {
- case 'nid': case 'vid':
- break;
- case 'uid':
- $this->databaseContents['node_revisions'][$k]['uid']++;
- break;
- default:
- unset($row[$field]);
- break;
- }
- }
- $this->databaseContents['node'][$k] = $row;
- }
- array_walk($this->expectedResults, function (&$row) {
- $row['node_uid'] = $row['uid'];
- $row['revision_uid'] = $row['uid'] + 1;
- unset($row['uid']);
- });
-
- parent::setUp();
- }
-
}
diff --git a/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTestBase.php b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTestBase.php
new file mode 100644
index 0000000..8850fc4
--- /dev/null
+++ b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTestBase.php
@@ -0,0 +1,179 @@
+<?php
+
+namespace Drupal\Tests\node\Unit\Plugin\migrate\source\d6;
+
+use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
+
+/**
+ * Base for D6 node migration tests.
+ */
+abstract class NodeTestBase extends MigrateSqlSourceTestCase {
+
+ const PLUGIN_CLASS = 'Drupal\node\Plugin\migrate\source\d6\Node';
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ $this->databaseContents['content_node_field'] = array(
+ array(
+ 'field_name' => 'field_test_four',
+ 'type' => 'number_float',
+ 'global_settings' => 'a:0:{}',
+ 'required' => '0',
+ 'multiple' => '0',
+ 'db_storage' => '1',
+ 'module' => 'number',
+ 'db_columns' => 'a:1:{s:5:"value";a:3:{s:4:"type";s:5:"float";s:8:"not null";b:0;s:8:"sortable";b:1;}}',
+ 'active' => '1',
+ 'locked' => '0',
+ ),
+ );
+ $this->databaseContents['content_node_field_instance'] = array(
+ array(
+ 'field_name' => 'field_test_four',
+ 'type_name' => 'story',
+ 'weight' => '3',
+ 'label' => 'Float Field',
+ 'widget_type' => 'number',
+ 'widget_settings' => 'a:0:{}',
+ 'display_settings' => 'a:0:{}',
+ 'description' => 'An example float field.',
+ 'widget_module' => 'number',
+ 'widget_active' => '1',
+ ),
+ );
+ $this->databaseContents['content_type_story'] = array(
+ array(
+ 'nid' => 5,
+ 'vid' => 5,
+ 'uid' => 5,
+ 'field_test_four_value' => '3.14159',
+ ),
+ );
+ $this->databaseContents['system'] = array(
+ array(
+ 'type' => 'module',
+ 'name' => 'content',
+ 'schema_version' => 6001,
+ 'status' => TRUE,
+ ),
+ );
+ $this->databaseContents['node'] = [
+ [
+ 'nid' => 1,
+ 'vid' => 1,
+ 'type' => 'page',
+ 'language' => 'en',
+ 'title' => 'node title 1',
+ 'uid' => 1,
+ 'status' => 1,
+ 'created' => 1279051598,
+ 'changed' => 1279051598,
+ 'comment' => 2,
+ 'promote' => 1,
+ 'moderate' => 0,
+ 'sticky' => 0,
+ 'translate' => 0,
+ 'tnid' => 0,
+ ],
+ [
+ 'nid' => 2,
+ 'vid' => 2,
+ 'type' => 'page',
+ 'language' => 'en',
+ 'title' => 'node title 2',
+ 'uid' => 1,
+ 'status' => 1,
+ 'created' => 1279290908,
+ 'changed' => 1279308993,
+ 'comment' => 0,
+ 'promote' => 1,
+ 'moderate' => 0,
+ 'sticky' => 0,
+ 'translate' => 0,
+ 'tnid' => 0,
+ ],
+ [
+ 'nid' => 5,
+ 'vid' => 5,
+ 'type' => 'story',
+ 'language' => 'en',
+ 'title' => 'node title 5',
+ 'uid' => 1,
+ 'status' => 1,
+ 'created' => 1279290908,
+ 'changed' => 1279308993,
+ 'comment' => 0,
+ 'promote' => 1,
+ 'moderate' => 0,
+ 'sticky' => 0,
+ 'translate' => 0,
+ 'tnid' => 0,
+ ],
+ [
+ 'nid' => 6,
+ 'vid' => 6,
+ 'type' => 'story',
+ 'language' => 'en',
+ 'title' => 'node title 6',
+ 'uid' => 1,
+ 'status' => 1,
+ 'created' => 1279290909,
+ 'changed' => 1279308994,
+ 'comment' => 0,
+ 'promote' => 1,
+ 'moderate' => 0,
+ 'sticky' => 0,
+ 'translate' => 0,
+ 'tnid' => 6,
+ ],
+ [
+ 'nid' => 7,
+ 'vid' => 7,
+ 'type' => 'story',
+ 'language' => 'fr',
+ 'title' => 'node title 7',
+ 'uid' => 1,
+ 'status' => 1,
+ 'created' => 1279290910,
+ 'changed' => 1279308995,
+ 'comment' => 0,
+ 'promote' => 1,
+ 'moderate' => 0,
+ 'sticky' => 0,
+ 'translate' => 0,
+ 'tnid' => 6,
+ ],
+ ];
+
+ foreach ($this->databaseContents['node'] as $k => $row) {
+ // Find the equivalent row from expected results.
+ $result_row = NULL;
+ foreach ($this->expectedResults as $result) {
+ if (in_array($result['nid'], [$row['nid'], $row['tnid']]) && $result['language'] == $row['language']) {
+ $result_row = $result;
+ break;
+ }
+ }
+
+ // Populate node_revisions.
+ foreach (array('nid', 'vid', 'title', 'uid', 'body', 'teaser', 'format', 'timestamp', 'log') as $field) {
+ $value = isset($row[$field]) ? $row[$field] : $result_row[$field];
+ $this->databaseContents['node_revisions'][$k][$field] = $value;
+ if ($field == 'uid') {
+ $this->databaseContents['node_revisions'][$k]['uid']++;
+ }
+ }
+ }
+
+ array_walk($this->expectedResults, function (&$row) {
+ $row['node_uid'] = $row['uid'];
+ $row['revision_uid'] = $row['uid'] + 1;
+ unset($row['uid']);
+ });
+
+ parent::setUp();
+ }
+
+}
diff --git a/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTranslationTest.php b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTranslationTest.php
new file mode 100644
index 0000000..da0b167
--- /dev/null
+++ b/core/modules/node/tests/src/Unit/Plugin/migrate/source/d6/NodeTranslationTest.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace Drupal\Tests\node\Unit\Plugin\migrate\source\d6;
+
+/**
+ * Tests D6 node translation source plugin.
+ *
+ * @group node
+ */
+class NodeTranslationTest extends NodeTestBase {
+
+ protected $migrationConfiguration = array(
+ 'id' => 'test',
+ 'source' => array(
+ 'plugin' => 'd6_node',
+ 'translations' => TRUE,
+ ),
+ );
+
+ protected $expectedResults = array(
+ array(
+ 'nid' => 7,
+ 'vid' => 7,
+ 'type' => 'story',
+ 'language' => 'fr',
+ 'title' => 'node title 7',
+ 'uid' => 1,
+ 'status' => 1,
+ 'created' => 1279290910,
+ 'changed' => 1279308995,
+ 'comment' => 0,
+ 'promote' => 1,
+ 'moderate' => 0,
+ 'sticky' => 0,
+ 'tnid' => 6,
+ 'translate' => 0,
+ // Node revision fields.
+ 'body' => 'body for node 7',
+ 'teaser' => 'body for node 7',
+ 'log' => '',
+ 'timestamp' => 1279308995,
+ 'format' => 1,
+ ),
+ );
+
+}
diff --git a/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeRevisionTest.php b/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeRevisionTest.php
index ff2b514..facd69b 100644
--- a/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeRevisionTest.php
+++ b/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeRevisionTest.php
@@ -22,7 +22,7 @@ class MigrateTermNodeRevisionTest extends MigrateDrupal6TestBase {
protected function setUp() {
parent::setUp();
$this->installSchema('node', ['node_access']);
- $this->migrateContent(TRUE);
+ $this->migrateContent(['revisions']);
$this->migrateTaxonomy();
$this->executeMigrations(['d6_term_node', 'd6_term_node_revision']);
}
diff --git a/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeTest.php b/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeTest.php
index 718c35d..26f069c 100644
--- a/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeTest.php
+++ b/core/modules/taxonomy/tests/src/Kernel/Migrate/d6/MigrateTermNodeTest.php
@@ -55,7 +55,7 @@ class MigrateTermNodeTest extends MigrateDrupal6TestBase {
public function testSkipNonExistentNode() {
// Node 2 is migrated by d6_node__story, but we need to pretend that it
// failed, so record that in the map table.
- $this->mockFailure('d6_node:story', ['nid' => 2]);
+ $this->mockFailure('d6_node:story', ['nid' => 2, 'language' => 'en']);
// d6_term_node__2 should skip over node 2 (a.k.a. revision 3) because,
// according to the map table, it failed.