Commit 69c0eadb authored by catch's avatar catch

Issue #2669964 by quietone, Gábor Hojtsy, Jo Fitzgerald, phenaproxima: Migrate...

Issue #2669964 by quietone, Gábor Hojtsy, Jo Fitzgerald, phenaproxima: Migrate Drupal 7 core node translations to Drupal 8
parent f6c8f900
......@@ -35,7 +35,10 @@ process:
phone: telephone
text_long: text_long
text_with_summary: text_with_summary
translatable: translatable
# Translatable is not migrated and the Drupal 8 default of true is used.
# If translatable is false in field storage then the field can not be
# set to translatable via the UI.
#translatable: translatable
cardinality: cardinality
settings:
plugin: d7_field_settings
......
......@@ -28,6 +28,7 @@ process:
source:
- default_value
- widget_settings
translatable: translatable
destination:
plugin: entity:field_config
migration_dependencies:
......
......@@ -86,6 +86,25 @@ public function prepareRow(Row $row) {
$field_data = unserialize($row->getSourceProperty('field_data'));
$row->setSourceProperty('field_settings', $field_data['settings']);
$translatable = FALSE;
if ($row->getSourceProperty('entity_type') == 'node') {
// language_content_type_[bundle] may be
// - 0: no language support
// - 1: language assignment support
// - 2: node translation support
// - 4: entity translation support
if ($this->variableGet('language_content_type_' . $row->getSourceProperty('bundle'), 0) == 2) {
$translatable = TRUE;
}
}
else {
// This is not a node entity. Get the translatable value from the source
// field_config table.
$data = unserialize($row->getSourceProperty('field_data'));
$translatable = $data['translatable'];
}
$row->setSourceProperty('translatable', $translatable);
return parent::prepareRow($row);
}
......
......@@ -80,8 +80,10 @@ protected function createType($id) {
* The expected field type.
* @param bool $is_required
* Whether or not the field is required.
* @param bool $expected_translatable
* Whether or not the field is expected to be translatable.
*/
protected function assertEntity($id, $expected_label, $expected_field_type, $is_required) {
protected function assertEntity($id, $expected_label, $expected_field_type, $is_required, $expected_translatable) {
list ($expected_entity_type, $expected_bundle, $expected_name) = explode('.', $id);
/** @var \Drupal\field\FieldConfigInterface $field */
......@@ -94,6 +96,7 @@ protected function assertEntity($id, $expected_label, $expected_field_type, $is_
$this->assertIdentical($expected_name, $field->getName());
$this->assertEqual($is_required, $field->isRequired());
$this->assertIdentical($expected_entity_type . '.' . $expected_name, $field->getFieldStorageDefinition()->id());
$this->assertSame($expected_translatable, $field->isTranslatable());
}
/**
......@@ -113,40 +116,38 @@ protected function assertLinkFields($id, $title_setting) {
* Tests migrating D7 field instances to field_config entities.
*/
public function testFieldInstances() {
$this->assertEntity('comment.comment_node_page.comment_body', 'Comment', 'text_long', TRUE);
$this->assertEntity('node.page.body', 'Body', 'text_with_summary', FALSE);
$this->assertEntity('comment.comment_node_article.comment_body', 'Comment', 'text_long', TRUE);
$this->assertEntity('node.article.body', 'Body', 'text_with_summary', FALSE);
$this->assertEntity('node.article.field_tags', 'Tags', 'entity_reference', FALSE);
$this->assertEntity('node.article.field_image', 'Image', 'image', FALSE);
$this->assertEntity('comment.comment_node_blog.comment_body', 'Comment', 'text_long', TRUE);
$this->assertEntity('node.blog.body', 'Body', 'text_with_summary', FALSE);
$this->assertEntity('comment.comment_node_book.comment_body', 'Comment', 'text_long', TRUE);
$this->assertEntity('node.book.body', 'Body', 'text_with_summary', FALSE);
$this->assertEntity('node.forum.taxonomy_forums', 'Forums', 'entity_reference', TRUE);
$this->assertEntity('comment.comment_node_forum.comment_body', 'Comment', 'text_long', TRUE);
$this->assertEntity('node.forum.body', 'Body', 'text_with_summary', FALSE);
$this->assertEntity('comment.comment_node_test_content_type.comment_body', 'Comment', 'text_long', TRUE);
$this->assertEntity('node.test_content_type.field_boolean', 'Boolean', 'boolean', FALSE);
$this->assertEntity('node.test_content_type.field_email', 'Email', 'email', FALSE);
$this->assertEntity('node.test_content_type.field_phone', 'Phone', 'telephone', TRUE);
$this->assertEntity('node.test_content_type.field_date', 'Date', 'datetime', FALSE);
$this->assertEntity('node.test_content_type.field_date_with_end_time', 'Date With End Time', 'datetime', FALSE);
$this->assertEntity('node.test_content_type.field_file', 'File', 'file', FALSE);
$this->assertEntity('node.test_content_type.field_float', 'Float', 'float', FALSE);
$this->assertEntity('node.test_content_type.field_images', 'Images', 'image', TRUE);
$this->assertEntity('node.test_content_type.field_integer', 'Integer', 'integer', TRUE);
$this->assertEntity('node.test_content_type.field_link', 'Link', 'link', FALSE);
$this->assertEntity('node.test_content_type.field_text_list', 'Text List', 'list_string', FALSE);
$this->assertEntity('node.test_content_type.field_integer_list', 'Integer List', 'list_integer', FALSE);
$this->assertEntity('node.test_content_type.field_long_text', 'Long text', 'text_with_summary', FALSE);
$this->assertEntity('node.test_content_type.field_term_reference', 'Term Reference', 'entity_reference', FALSE);
$this->assertEntity('node.test_content_type.field_node_entityreference', 'Node Entity Reference', 'entity_reference', FALSE);
$this->assertEntity('node.test_content_type.field_user_entityreference', 'User Entity Reference', 'entity_reference', FALSE);
$this->assertEntity('node.test_content_type.field_term_entityreference', 'Term Entity Reference', 'entity_reference', FALSE);
$this->assertEntity('node.test_content_type.field_text', 'Text', 'text', FALSE);
$this->assertEntity('comment.comment_node_test_content_type.field_integer', 'Integer', 'integer', FALSE);
$this->assertEntity('user.user.field_file', 'File', 'file', FALSE);
$this->assertEntity('comment.comment_node_page.comment_body', 'Comment', 'text_long', TRUE, FALSE);
$this->assertEntity('node.page.body', 'Body', 'text_with_summary', FALSE, FALSE);
$this->assertEntity('comment.comment_node_article.comment_body', 'Comment', 'text_long', TRUE, FALSE);
$this->assertEntity('node.article.body', 'Body', 'text_with_summary', FALSE, TRUE);
$this->assertEntity('node.article.field_tags', 'Tags', 'entity_reference', FALSE, TRUE);
$this->assertEntity('node.article.field_image', 'Image', 'image', FALSE, TRUE);
$this->assertEntity('comment.comment_node_blog.comment_body', 'Comment', 'text_long', TRUE, FALSE);
$this->assertEntity('node.blog.body', 'Body', 'text_with_summary', FALSE, TRUE);
$this->assertEntity('comment.comment_node_book.comment_body', 'Comment', 'text_long', TRUE, FALSE);
$this->assertEntity('node.book.body', 'Body', 'text_with_summary', FALSE, FALSE);
$this->assertEntity('node.forum.taxonomy_forums', 'Forums', 'entity_reference', TRUE, FALSE);
$this->assertEntity('comment.comment_node_forum.comment_body', 'Comment', 'text_long', TRUE, FALSE);
$this->assertEntity('node.forum.body', 'Body', 'text_with_summary', FALSE, FALSE);
$this->assertEntity('comment.comment_node_test_content_type.comment_body', 'Comment', 'text_long', TRUE, FALSE);
$this->assertEntity('node.test_content_type.field_boolean', 'Boolean', 'boolean', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_email', 'Email', 'email', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_phone', 'Phone', 'telephone', TRUE, FALSE);
$this->assertEntity('node.test_content_type.field_date', 'Date', 'datetime', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_date_with_end_time', 'Date With End Time', 'datetime', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_file', 'File', 'file', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_float', 'Float', 'float', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_images', 'Images', 'image', TRUE, FALSE);
$this->assertEntity('node.test_content_type.field_integer', 'Integer', 'integer', TRUE, FALSE);
$this->assertEntity('node.test_content_type.field_link', 'Link', 'link', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_text_list', 'Text List', 'list_string', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_integer_list', 'Integer List', 'list_integer', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_long_text', 'Long text', 'text_with_summary', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_term_reference', 'Term Reference', 'entity_reference', FALSE, FALSE);
$this->assertEntity('node.test_content_type.field_text', 'Text', 'text', FALSE, FALSE);
$this->assertEntity('comment.comment_node_test_content_type.field_integer', 'Integer', 'integer', FALSE, FALSE);
$this->assertEntity('user.user.field_file', 'File', 'file', FALSE, FALSE);
$this->assertLinkFields('node.test_content_type.field_link', DRUPAL_OPTIONAL);
$this->assertLinkFields('node.article.field_link', DRUPAL_DISABLED);
......
......@@ -60,8 +60,6 @@ protected function assertEntity($id, $expected_type, $expected_translatable, $ex
$this->assertTrue($field instanceof FieldStorageConfigInterface);
$this->assertIdentical($expected_name, $field->getName());
$this->assertIdentical($expected_type, $field->getType());
// FieldStorageConfig::$translatable is TRUE by default, so it is useful
// to test for FALSE here.
$this->assertEqual($expected_translatable, $field->isTranslatable());
$this->assertIdentical($expected_entity_type, $field->getTargetEntityTypeId());
......@@ -78,31 +76,31 @@ protected function assertEntity($id, $expected_type, $expected_translatable, $ex
* Tests migrating D7 fields to field_storage_config entities.
*/
public function testFields() {
$this->assertEntity('node.body', 'text_with_summary', FALSE, 1);
$this->assertEntity('node.field_long_text', 'text_with_summary', FALSE, 1);
$this->assertEntity('comment.comment_body', 'text_long', FALSE, 1);
$this->assertEntity('node.field_file', 'file', FALSE, 1);
$this->assertEntity('user.field_file', 'file', FALSE, 1);
$this->assertEntity('node.field_float', 'float', FALSE, 1);
$this->assertEntity('node.field_image', 'image', FALSE, 1);
$this->assertEntity('node.field_images', 'image', FALSE, 1);
$this->assertEntity('node.field_integer', 'integer', FALSE, 1);
$this->assertEntity('comment.field_integer', 'integer', FALSE, 1);
$this->assertEntity('node.field_integer_list', 'list_integer', FALSE, 1);
$this->assertEntity('node.field_link', 'link', FALSE, 1);
$this->assertEntity('node.field_tags', 'entity_reference', FALSE, -1);
$this->assertEntity('node.field_term_reference', 'entity_reference', FALSE, 1);
$this->assertEntity('node.taxonomy_forums', 'entity_reference', FALSE, 1);
$this->assertEntity('node.field_text', 'text', FALSE, 1);
$this->assertEntity('node.field_text_list', 'list_string', FALSE, 3);
$this->assertEntity('node.field_boolean', 'boolean', FALSE, 1);
$this->assertEntity('node.field_email', 'email', FALSE, -1);
$this->assertEntity('node.field_phone', 'telephone', FALSE, 1);
$this->assertEntity('node.field_date', 'datetime', FALSE, 1);
$this->assertEntity('node.field_date_with_end_time', 'datetime', FALSE, 1);
$this->assertEntity('node.field_node_entityreference', 'entity_reference', FALSE, -1);
$this->assertEntity('node.field_user_entityreference', 'entity_reference', FALSE, 1);
$this->assertEntity('node.field_term_entityreference', 'entity_reference', FALSE, -1);
$this->assertEntity('node.body', 'text_with_summary', TRUE, 1);
$this->assertEntity('node.field_long_text', 'text_with_summary', TRUE, 1);
$this->assertEntity('comment.comment_body', 'text_long', TRUE, 1);
$this->assertEntity('node.field_file', 'file', TRUE, 1);
$this->assertEntity('user.field_file', 'file', TRUE, 1);
$this->assertEntity('node.field_float', 'float', TRUE, 1);
$this->assertEntity('node.field_image', 'image', TRUE, 1);
$this->assertEntity('node.field_images', 'image', TRUE, 1);
$this->assertEntity('node.field_integer', 'integer', TRUE, 1);
$this->assertEntity('comment.field_integer', 'integer', TRUE, 1);
$this->assertEntity('node.field_integer_list', 'list_integer', TRUE, 1);
$this->assertEntity('node.field_link', 'link', TRUE, 1);
$this->assertEntity('node.field_tags', 'entity_reference', TRUE, -1);
$this->assertEntity('node.field_term_reference', 'entity_reference', TRUE, 1);
$this->assertEntity('node.taxonomy_forums', 'entity_reference', TRUE, 1);
$this->assertEntity('node.field_text', 'text', TRUE, 1);
$this->assertEntity('node.field_text_list', 'list_string', TRUE, 3);
$this->assertEntity('node.field_boolean', 'boolean', TRUE, 1);
$this->assertEntity('node.field_email', 'email', TRUE, -1);
$this->assertEntity('node.field_phone', 'telephone', TRUE, 1);
$this->assertEntity('node.field_date', 'datetime', TRUE, 1);
$this->assertEntity('node.field_date_with_end_time', 'datetime', TRUE, 1);
$this->assertEntity('node.field_node_entityreference', 'entity_reference', TRUE, -1);
$this->assertEntity('node.field_user_entityreference', 'entity_reference', TRUE, 1);
$this->assertEntity('node.field_term_entityreference', 'entity_reference', TRUE, -1);
// Assert that the taxonomy term reference fields are referencing the
// correct entity type.
......@@ -123,7 +121,8 @@ public function testFields() {
// Validate that the source count and processed count match up.
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
$migration = $this->getMigration('d7_field');
$this->assertIdentical($migration->getSourcePlugin()->count(), $migration->getIdMap()->processedCount());
$this->assertSame($migration->getSourcePlugin()
->count(), $migration->getIdMap()->processedCount());
}
}
......@@ -94,6 +94,7 @@ public function providerSource() {
],
'description' => '',
'required' => FALSE,
'field_data' => 'a:6:{s:12:"entity_types";a:1:{i:0;s:4:"node";}s:12:"translatable";b:0;s:8:"settings";a:0:{}s:7:"storage";a:4:{s:4:"type";s:17:"field_sql_storage";s:8:"settings";a:0:{}s:6:"module";s:17:"field_sql_storage";s:6:"active";i:1;}s:12:"foreign keys";a:1:{s:6:"format";a:2:{s:5:"table";s:13:"filter_format";s:7:"columns";a:1:{s:6:"format";s:6:"format";}}}s:7:"indexes";a:1:{s:6:"format";a:1:{i:0;s:6:"format";}}}',
],
];
......
......@@ -6141,6 +6141,30 @@
'body_summary' => '',
'body_format' => 'filtered_html',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '4',
'revision_id' => '4',
'language' => 'und',
'delta' => '0',
'body_value' => 'is - Is that is it awesome.',
'body_summary' => '',
'body_format' => 'filtered_html',
))
->values(array(
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '5',
'revision_id' => '5',
'language' => 'und',
'delta' => '0',
'body_value' => 'en - Is that is it awesome.',
'body_summary' => '',
'body_format' => 'filtered_html',
))
->execute();
$connection->schema()->createTable('field_revision_comment_body', array(
......@@ -30945,6 +30969,38 @@
'tnid' => '2',
'translate' => '0',
))
->values(array(
'nid' => '4',
'vid' => '4',
'type' => 'article',
'language' => 'is',
'title' => 'is - The thing about Firefly',
'uid' => '1',
'status' => '1',
'created' => '1478755274',
'changed' => '1478755274',
'comment' => '2',
'promote' => '1',
'sticky' => '0',
'tnid' => '4',
'translate' => '0',
))
->values(array(
'nid' => '5',
'vid' => '5',
'type' => 'article',
'language' => 'en',
'title' => 'en - The thing about Firefly',
'uid' => '1',
'status' => '1',
'created' => '1478755314',
'changed' => '1478755314',
'comment' => '2',
'promote' => '1',
'sticky' => '0',
'tnid' => '4',
'translate' => '0',
))
->execute();
$connection->schema()->createTable('node_access', array(
......@@ -31089,6 +31145,22 @@
'last_comment_uid' => '1',
'comment_count' => '0',
))
->values(array(
'nid' => '4',
'cid' => '0',
'last_comment_timestamp' => '1478755274',
'last_comment_name' => NULL,
'last_comment_uid' => '1',
'comment_count' => '0',
))
->values(array(
'nid' => '5',
'cid' => '0',
'last_comment_timestamp' => '1478755314',
'last_comment_name' => NULL,
'last_comment_uid' => '1',
'comment_count' => '0',
))
->execute();
$connection->schema()->createTable('node_counter', array(
......@@ -31143,15 +31215,27 @@
->values(array(
'nid' => '2',
'totalcount' => '1',
'daycount' => '1',
'daycount' => '0',
'timestamp' => '1471428059',
))
->values(array(
'nid' => '3',
'totalcount' => '1',
'daycount' => '1',
'daycount' => '0',
'timestamp' => '1471428153',
))
->values(array(
'nid' => '4',
'totalcount' => '1',
'daycount' => '1',
'timestamp' => '1478755275',
))
->values(array(
'nid' => '5',
'totalcount' => '1',
'daycount' => '1',
'timestamp' => '1478755314',
))
->execute();
$connection->schema()->createTable('node_revision', array(
......@@ -31272,6 +31356,30 @@
'promote' => '1',
'sticky' => '0',
))
->values(array(
'nid' => '4',
'vid' => '4',
'uid' => '1',
'title' => 'is - The thing about Firefly',
'log' => '',
'timestamp' => '1478755274',
'status' => '1',
'comment' => '2',
'promote' => '1',
'sticky' => '0',
))
->values(array(
'nid' => '5',
'vid' => '5',
'uid' => '1',
'title' => 'en - The thing about Firefly',
'log' => '',
'timestamp' => '1478755314',
'status' => '1',
'comment' => '2',
'promote' => '1',
'sticky' => '0',
))
->execute();
$connection->schema()->createTable('node_type', array(
......@@ -374,6 +374,10 @@ class MigrateUpgradeForm extends ConfirmFormBase {
'source_module' => 'node',
'destination_module' => 'node',
],
'd7_node_translation' => [
'source_module' => 'node',
'destination_module' => 'node',
],
'd7_node_title_label' => [
'source_module' => 'node',
'destination_module' => 'node',
......
......@@ -8,7 +8,10 @@ source:
process:
# If you are using this file to build a custom migration consider removing
# the nid and vid fields to allow incremental migrations.
nid: nid
# In D7, 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\d7\Node::prepareRow().
nid: tnid
vid: vid
langcode:
plugin: default_value
......
id: d7_node_translation
label: Node translations
migration_tags:
- Drupal 7
- translation
deriver: Drupal\node\Plugin\migrate\D7NodeDeriver
source:
plugin: d7_node
translations: true
process:
# If you are using this file to build a custom migration consider removing
# the nid field to allow incremental migrations.
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
revision_uid: revision_uid
revision_log: log
revision_timestamp: timestamp
content_translation_source: source_langcode
destination:
plugin: entity:node
translations: true
content_translation_update_definitions:
- node
migration_dependencies:
required:
- d7_user
- d7_node_type
- language
optional:
- d7_field_instance
provider: migrate_drupal
......@@ -38,6 +38,13 @@ class D7NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
*/
protected $cckPluginManager;
/**
* Whether or not to include translations.
*
* @var bool
*/
protected $includeTranslations;
/**
* D7NodeDeriver constructor.
*
......@@ -45,19 +52,24 @@ class D7NodeDeriver extends DeriverBase implements ContainerDeriverInterface {
* The base plugin ID for the plugin ID.
* @param \Drupal\migrate_drupal\Plugin\MigrateCckFieldPluginManagerInterface $cck_manager
* The CCK plugin manager.
* @param bool $translations
* Whether or not to include translations.
*/
public function __construct($base_plugin_id, MigrateCckFieldPluginManagerInterface $cck_manager) {
public function __construct($base_plugin_id, MigrateCckFieldPluginManagerInterface $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')
);
}
......@@ -65,6 +77,11 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
* {@inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition) {
if (in_array('translation', $base_plugin_definition['migration_tags']) && !$this->includeTranslations) {
// Refuse to generate anything.
return $this->derivatives;
}
$node_types = static::getSourcePlugin('d7_node_type');
try {
$node_types->checkRequirements();
......@@ -105,6 +122,13 @@ public function getDerivativeDefinitions($base_plugin_definition) {
$values['source']['node_type'] = $node_type;
$values['destination']['default_bundle'] = $node_type;
// If this migration is based on the d7_node_revision migration or
// is for translations of nodes, it should explicitly depend on the
// corresponding d7_node variant.
if ($base_plugin_definition['id'] == ['d7_node_revision'] || in_array('translation', $base_plugin_definition['migration_tags'])) {
$values['migration_dependencies']['required'][] = 'd7_node:' . $node_type;
}
$migration = \Drupal::service('plugin.manager.migration')->createStubMigration($values);
if (isset($fields[$node_type])) {
foreach ($fields[$node_type] as $field_name => $info) {
......@@ -131,7 +155,6 @@ public function getDerivativeDefinitions($base_plugin_definition) {
// MigrationPluginManager gathers up the migration definitions but we do
// not actually have a Drupal 7 source database.
}
return $this->derivatives;
}
......
......@@ -2,8 +2,15 @@
namespace Drupal\node\Plugin\migrate\source\d7;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\State\StateInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Drupal 7 node source from database.
......@@ -14,6 +21,35 @@
* )
*/
class Node extends FieldableEntity {
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $state, $entity_manager);
$this->moduleHandler = $module_handler;
}
/**
* {@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'),
$container->get('entity.manager'),
$container->get('module_handler')
);
}
/**
* The join options between the node and the node_revisions table.
......@@ -49,6 +85,14 @@ public function query() {
$query->addField('nr', 'uid', 'revision_uid');
$query->innerJoin('node', 'n', static::JOIN);
// If the content_translation module is enabled, get the source langcode
// to fill the content_translation_source field.
if ($this->moduleHandler->moduleExists('content_translation')) {
$query->leftJoin('node', 'nt', 'n.tnid = nt.nid');
$query->addField('nt', 'language', 'source_langcode');
}
$this->handleTranslations($query);
if (isset($this->configuration['node_type'])) {
$query->condition('n.type', $this->configuration['node_type']);
}
......@@ -66,6 +110,11 @@ public function prepareRow(Row $row) {
$vid = $row->getSourceProperty('vid');
$row->setSourceProperty($field, $this->getFieldValues('node', $field, $nid, $vid));
}
// Make sure we always have a translation set.
if ($row->getSourceProperty('tnid') == 0) {
$row->setSourceProperty('tnid', $row->getSourceProperty('nid'));
}
return parent::prepareRow($row);
}
......@@ -101,4 +150,21 @@ public function getIds() {
return $ids;
}
/**
* Adapt our query for translations.
*
* @param \Drupal\Core\Database\Query\SelectInterface $query
* 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');
}
}
}
<?php
namespace Drupal\Tests\node\Kernel\Migrate\d7;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
/**
* Test D7NodeDeriver.
*
* @group migrate_drupal_7
*/
class MigrateNodeDeriverTest extends MigrateDrupal7TestBase {
/**
* 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('d7_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', 'node', 'filter']);
$migrations = $this->pluginManager->createInstances('d7_node_translation');
$this->assertArrayHasKey('d7_node_translation:article', $migrations,
"Node translation migrations exist after content_translation installed");
}
}
......@@ -13,11 +13,16 @@
*/
class MigrateNodeTest extends MigrateDrupal7TestBase {
/**
* {@inheritdoc}
*/
public static $modules = array(
'content_translation',
'comment',
'datetime',
'filter',
'image',
'language',
'link',
'node',
'taxonomy',
......@@ -40,15 +45,17 @@ protected function setUp() {
$this->installSchema('system', ['sequences']);
$this->executeMigrations([