summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2016-10-12 10:59:25 (GMT)
committerNathaniel Catchpole2016-10-12 10:59:25 (GMT)
commit50d30d975f40f5af0853789b883287f3dc9137d2 (patch)
treed6db0981f037a0d7715d10f5fe55a8c03a0a88d6
parent5c93d7e314e0124648f7184f0bb953af7b6d27a7 (diff)
Issue #2751223 by maxocub, jeroenbegyn, Gábor Hojtsy, Jo Fitzgerald: D6 & D7 users are migrated into D8 with incorrect langcode
-rw-r--r--core/modules/migrate_drupal/tests/fixtures/drupal7.php28
-rw-r--r--core/modules/migrate_drupal_ui/src/Tests/d7/MigrateUpgrade7Test.php2
-rw-r--r--core/modules/user/migration_templates/d6_user.yml15
-rw-r--r--core/modules/user/migration_templates/d7_user.yml17
-rw-r--r--core/modules/user/src/Plugin/migrate/process/UserLangcode.php86
-rw-r--r--core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserProfileValuesTest.php6
-rw-r--r--core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserTest.php51
-rw-r--r--core/modules/user/tests/src/Kernel/Migrate/d7/MigrateUserTest.php134
8 files changed, 288 insertions, 51 deletions
diff --git a/core/modules/migrate_drupal/tests/fixtures/drupal7.php b/core/modules/migrate_drupal/tests/fixtures/drupal7.php
index e8c006b..aacbc2b 100644
--- a/core/modules/migrate_drupal/tests/fixtures/drupal7.php
+++ b/core/modules/migrate_drupal/tests/fixtures/drupal7.php
@@ -41044,11 +41044,29 @@ $connection->insert('users')
'login' => '0',
'status' => '1',
'timezone' => 'America/Chicago',
- 'language' => 'en',
+ 'language' => 'is',
'picture' => '0',
'init' => 'odo@local.host',
'data' => 'a:1:{s:7:"contact";i:1;}',
))
+->values(array(
+ 'uid' => '3',
+ 'name' => 'Bob',
+ 'pass' => '$S$DGFZUE.FhrXbe4y52eC7p0ZVRGD/gOPtVctDlmC89qkujnBokAlJ',
+ 'mail' => 'bob@local.host',
+ 'theme' => '',
+ 'signature' => '',
+ 'signature_format' => 'filtered_html',
+ 'created' => '1440532218',
+ 'access' => '0',
+ 'login' => '0',
+ 'status' => '1',
+ 'timezone' => 'America/New_York',
+ 'language' => 'fr',
+ 'picture' => '0',
+ 'init' => 'bob@local.host',
+ 'data' => 'a:1:{s:7:"contact";i:1;}',
+))
->execute();
$connection->schema()->createTable('users_roles', array(
@@ -41084,6 +41102,14 @@ $connection->insert('users_roles')
'uid' => '1',
'rid' => '3',
))
+->values(array(
+ 'uid' => '2',
+ 'rid' => '3',
+))
+->values(array(
+ 'uid' => '3',
+ 'rid' => '3',
+))
->execute();
$connection->schema()->createTable('variable', array(
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 bac70e5..eef7b90 100644
--- a/core/modules/migrate_drupal_ui/src/Tests/d7/MigrateUpgrade7Test.php
+++ b/core/modules/migrate_drupal_ui/src/Tests/d7/MigrateUpgrade7Test.php
@@ -61,7 +61,7 @@ class MigrateUpgrade7Test extends MigrateUpgradeTestBase {
'taxonomy_term' => 18,
'taxonomy_vocabulary' => 3,
'tour' => 4,
- 'user' => 3,
+ 'user' => 4,
'user_role' => 4,
'menu_link_content' => 9,
'view' => 12,
diff --git a/core/modules/user/migration_templates/d6_user.yml b/core/modules/user/migration_templates/d6_user.yml
index bf6ec2a..fa6326e 100644
--- a/core/modules/user/migration_templates/d6_user.yml
+++ b/core/modules/user/migration_templates/d6_user.yml
@@ -16,7 +16,18 @@ process:
timezone:
plugin: user_update_7002
source: timezone
- preferred_langcode: language
+ langcode:
+ plugin: user_langcode
+ source: language
+ fallback_to_site_default: false
+ preferred_langcode:
+ plugin: user_langcode
+ source: language
+ fallback_to_site_default: true
+ preferred_admin_langcode:
+ plugin: user_langcode
+ source: language
+ fallback_to_site_default: true
init: init
roles:
plugin: migration
@@ -34,6 +45,8 @@ migration_dependencies:
required:
- d6_user_role
optional:
+ - language
+ - default_language
- d6_user_picture_file
- user_picture_entity_display
- user_picture_entity_form_display
diff --git a/core/modules/user/migration_templates/d7_user.yml b/core/modules/user/migration_templates/d7_user.yml
index d68fddf..b72e8c7 100644
--- a/core/modules/user/migration_templates/d7_user.yml
+++ b/core/modules/user/migration_templates/d7_user.yml
@@ -15,9 +15,18 @@ process:
login: login
status: status
timezone: timezone
- langcode: language
- preferred_langcode: language
- preferred_admin_langcode: language
+ langcode:
+ plugin: user_langcode
+ source: language
+ fallback_to_site_default: false
+ preferred_langcode:
+ plugin: user_langcode
+ source: language
+ fallback_to_site_default: true
+ preferred_admin_langcode:
+ plugin: user_langcode
+ source: language
+ fallback_to_site_default: true
init: init
roles:
plugin: migration
@@ -38,6 +47,8 @@ migration_dependencies:
- d7_user_role
optional:
- d7_file
+ - language
+ - default_language
- user_picture_field_instance
- user_picture_entity_display
- user_picture_entity_form_display
diff --git a/core/modules/user/src/Plugin/migrate/process/UserLangcode.php b/core/modules/user/src/Plugin/migrate/process/UserLangcode.php
new file mode 100644
index 0000000..80f2078
--- /dev/null
+++ b/core/modules/user/src/Plugin/migrate/process/UserLangcode.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Drupal\user\Plugin\migrate\process;
+
+use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\migrate\MigrateExecutableInterface;
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\Row;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a process plugin for the user langcode.
+ *
+ * @MigrateProcessPlugin(
+ * id = "user_langcode"
+ * )
+ */
+class UserLangcode extends ProcessPluginBase implements ContainerFactoryPluginInterface {
+
+ /**
+ * The language manager.
+ *
+ * @var \Drupal\Core\Language\LanguageManager
+ */
+ protected $languageManager;
+
+ /**
+ * Constructs a UserLangcode object.
+ *
+ * @param array $configuration
+ * Plugin configuration.
+ * @param string $plugin_id
+ * The plugin ID.
+ * @param mixed $plugin_definition
+ * The plugin definiiton.
+ * @param \Drupal\Core\Language\LanguageManager $language_manager
+ * The language manager service.
+ */
+ public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManager $language_manager) {
+ parent::__construct($configuration, $plugin_id, $plugin_definition);
+ $this->languageManager = $language_manager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+ return new static(
+ $configuration,
+ $plugin_id,
+ $plugin_definition,
+ $container->get('language_manager')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
+ if (!isset($this->configuration['fallback_to_site_default'])) {
+ $this->configuration['fallback_to_site_default'] = TRUE;
+ }
+
+ // If the user's language is empty, it means the locale module was not
+ // installed, so the user's langcode should be English and the user's
+ // preferred_langcode and preferred_admin_langcode should fallback to the
+ // default language.
+ if (empty($value)) {
+ if ($this->configuration['fallback_to_site_default']) {
+ return $this->languageManager->getDefaultLanguage()->getId();
+ }
+ else {
+ return 'en';
+ }
+ }
+ // If the user's language does not exists, use the default language.
+ elseif ($this->languageManager->getLanguage($value) === NULL) {
+ return $this->languageManager->getDefaultLanguage()->getId();
+ }
+
+ // If the langcode is a valid one, just return it.
+ return $value;
+ }
+
+}
diff --git a/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserProfileValuesTest.php b/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserProfileValuesTest.php
index 978c0bf..e734517 100644
--- a/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserProfileValuesTest.php
+++ b/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserProfileValuesTest.php
@@ -15,10 +15,16 @@ class MigrateUserProfileValuesTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
+ public static $modules = ['language'];
+
+ /**
+ * {@inheritdoc}
+ */
protected function setUp() {
parent::setUp();
$this->executeMigrations([
+ 'language',
'user_profile_field',
'user_profile_field_instance',
'user_profile_entity_display',
diff --git a/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserTest.php b/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserTest.php
index 9317834..33952d1 100644
--- a/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserTest.php
+++ b/core/modules/user/tests/src/Kernel/Migrate/d6/MigrateUserTest.php
@@ -22,6 +22,11 @@ class MigrateUserTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
+ public static $modules = ['language'];
+
+ /**
+ * {@inheritdoc}
+ */
protected function setUp() {
parent::setUp();
@@ -60,6 +65,7 @@ class MigrateUserTest extends MigrateDrupal6TestBase {
file_put_contents($file->getFileUri(), file_get_contents('core/modules/simpletest/files/image-2.jpg'));
$file->save();
+ $this->executeMigration('language');
$this->migrateUsers();
}
@@ -91,28 +97,47 @@ class MigrateUserTest extends MigrateDrupal6TestBase {
/** @var \Drupal\user\UserInterface $user */
$user = User::load($source->uid);
- $this->assertIdentical($source->uid, $user->id());
- $this->assertIdentical($source->name, $user->label());
- $this->assertIdentical($source->mail, $user->getEmail());
- $this->assertIdentical($source->created, $user->getCreatedTime());
- $this->assertIdentical($source->access, $user->getLastAccessedTime());
- $this->assertIdentical($source->login, $user->getLastLoginTime());
+ $this->assertSame($source->uid, $user->id());
+ $this->assertSame($source->name, $user->label());
+ $this->assertSame($source->mail, $user->getEmail());
+ $this->assertSame($source->created, $user->getCreatedTime());
+ $this->assertSame($source->access, $user->getLastAccessedTime());
+ $this->assertSame($source->login, $user->getLastLoginTime());
$is_blocked = $source->status == 0;
- $this->assertIdentical($is_blocked, $user->isBlocked());
+ $this->assertSame($is_blocked, $user->isBlocked());
+ $expected_timezone_name = $source->timezone_name ?: $this->config('system.date')->get('timezone.default');
+ $this->assertSame($expected_timezone_name, $user->getTimeZone());
+ $this->assertSame($source->init, $user->getInitialEmail());
+ $this->assertSame($roles, $user->getRoles());
+
+ // Ensure the user's langcode, preferred_langcode and
+ // preferred_admin_langcode are valid.
// $user->getPreferredLangcode() might fallback to default language if the
// user preferred language is not configured on the site. We just want to
// test if the value was imported correctly.
- $this->assertIdentical($source->language, $user->preferred_langcode->value);
- $expected_timezone_name = $source->timezone_name ?: $this->config('system.date')->get('timezone.default');
- $this->assertIdentical($expected_timezone_name, $user->getTimeZone());
- $this->assertIdentical($source->init, $user->getInitialEmail());
- $this->assertIdentical($roles, $user->getRoles());
+ $language_manager = $this->container->get('language_manager');
+ $default_langcode = $language_manager->getDefaultLanguage()->getId();
+ if (empty($source->language)) {
+ $this->assertSame('en', $user->langcode->value);
+ $this->assertSame($default_langcode, $user->preferred_langcode->value);
+ $this->assertSame($default_langcode, $user->preferred_admin_langcode->value);
+ }
+ elseif ($language_manager->getLanguage($source->language) === NULL) {
+ $this->assertSame($default_langcode, $user->langcode->value);
+ $this->assertSame($default_langcode, $user->preferred_langcode->value);
+ $this->assertSame($default_langcode, $user->preferred_admin_langcode->value);
+ }
+ else {
+ $this->assertSame($source->language, $user->langcode->value);
+ $this->assertSame($source->language, $user->preferred_langcode->value);
+ $this->assertSame($source->language, $user->preferred_admin_langcode->value);
+ }
// We have one empty picture in the data so don't try load that.
if (!empty($source->picture)) {
// Test the user picture.
$file = File::load($user->user_picture->target_id);
- $this->assertIdentical(basename($source->picture), $file->getFilename());
+ $this->assertSame(basename($source->picture), $file->getFilename());
}
else {
// Ensure the user does not have a picture.
diff --git a/core/modules/user/tests/src/Kernel/Migrate/d7/MigrateUserTest.php b/core/modules/user/tests/src/Kernel/Migrate/d7/MigrateUserTest.php
index 33bc5fe..c21856e 100644
--- a/core/modules/user/tests/src/Kernel/Migrate/d7/MigrateUserTest.php
+++ b/core/modules/user/tests/src/Kernel/Migrate/d7/MigrateUserTest.php
@@ -3,6 +3,7 @@
namespace Drupal\Tests\user\Kernel\Migrate\d7;
use Drupal\comment\Entity\CommentType;
+use Drupal\Core\Database\Database;
use Drupal\node\Entity\NodeType;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
@@ -25,6 +26,7 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
'datetime',
'file',
'image',
+ 'language',
'link',
'node',
'system',
@@ -49,6 +51,7 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
$this->createType('test_content_type');
Vocabulary::create(['vid' => 'test_vocabulary'])->save();
$this->executeMigrations([
+ 'language',
'user_picture_field',
'user_picture_field_instance',
'd7_user_role',
@@ -88,6 +91,8 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
* The user's email address.
* @param string $password
* The password for this user.
+ * @param int $created
+ * The user's creation time.
* @param int $access
* The last access time.
* @param int $login
@@ -96,37 +101,59 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
* Whether or not the account is blocked.
* @param string $langcode
* The user account's language code.
+ * @param string $timezone
+ * The user account's timezone name.
* @param string $init
* The user's initial email address.
* @param string[] $roles
* Role IDs the user account is expected to have.
- * @param bool $has_picture
- * Whether the user is expected to have a picture attached.
* @param int $field_integer
* The value of the integer field.
+ * @param bool $has_picture
+ * Whether the user is expected to have a picture attached.
*/
- protected function assertEntity($id, $label, $mail, $password, $access, $login, $blocked, $langcode, $init, array $roles = [RoleInterface::AUTHENTICATED_ID], $has_picture = FALSE, $field_integer = NULL) {
+ protected function assertEntity($id, $label, $mail, $password, $created, $access, $login, $blocked, $langcode, $timezone, $init, $roles, $field_integer, $has_picture = FALSE) {
/** @var \Drupal\user\UserInterface $user */
$user = User::load($id);
$this->assertTrue($user instanceof UserInterface);
- $this->assertIdentical($label, $user->label());
- $this->assertIdentical($mail, $user->getEmail());
- $this->assertIdentical($access, $user->getLastAccessedTime());
- $this->assertIdentical($login, $user->getLastLoginTime());
- $this->assertIdentical($blocked, $user->isBlocked());
+ $this->assertSame($label, $user->label());
+ $this->assertSame($mail, $user->getEmail());
+ $this->assertSame($password, $user->getPassword());
+ $this->assertSame($created, $user->getCreatedTime());
+ $this->assertSame($access, $user->getLastAccessedTime());
+ $this->assertSame($login, $user->getLastLoginTime());
+ $this->assertNotSame($blocked, $user->isBlocked());
+
+ // Ensure the user's langcode, preferred_langcode and
+ // preferred_admin_langcode are valid.
// $user->getPreferredLangcode() might fallback to default language if the
// user preferred language is not configured on the site. We just want to
// test if the value was imported correctly.
- $this->assertIdentical($langcode, $user->langcode->value);
- $this->assertIdentical($langcode, $user->preferred_langcode->value);
- $this->assertIdentical($langcode, $user->preferred_admin_langcode->value);
- $this->assertIdentical($init, $user->getInitialEmail());
- $this->assertIdentical($roles, $user->getRoles());
- $this->assertIdentical($has_picture, !$user->user_picture->isEmpty());
- $this->assertIdentical($password, $user->getPassword());
+ $language_manager = $this->container->get('language_manager');
+ $default_langcode = $language_manager->getDefaultLanguage()->getId();
+ if ($langcode == '') {
+ $this->assertSame('en', $user->langcode->value);
+ $this->assertSame($default_langcode, $user->preferred_langcode->value);
+ $this->assertSame($default_langcode, $user->preferred_admin_langcode->value);
+ }
+ elseif ($language_manager->getLanguage($langcode) === NULL) {
+ $this->assertSame($default_langcode, $user->langcode->value);
+ $this->assertSame($default_langcode, $user->preferred_langcode->value);
+ $this->assertSame($default_langcode, $user->preferred_admin_langcode->value);
+ }
+ else {
+ $this->assertSame($langcode, $user->langcode->value);
+ $this->assertSame($langcode, $user->preferred_langcode->value);
+ $this->assertSame($langcode, $user->preferred_admin_langcode->value);
+ }
+
+ $this->assertSame($timezone, $user->getTimeZone());
+ $this->assertSame($init, $user->getInitialEmail());
+ $this->assertSame($roles, $user->getRoles());
+ $this->assertSame($has_picture, !$user->user_picture->isEmpty());
if (!is_null($field_integer)) {
$this->assertTrue($user->hasField('field_integer'));
- $this->assertEquals($field_integer, $user->field_integer->value);
+ $this->assertEquals($field_integer[0], $user->field_integer->value);
}
}
@@ -134,22 +161,65 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
* Tests the Drupal 7 user to Drupal 8 migration.
*/
public function testUser() {
- $password = '$S$DGFZUE.FhrXbe4y52eC7p0ZVRGD/gOPtVctDlmC89qkujnBokAlJ';
- $this->assertEntity(2, 'Odo', 'odo@local.host', $password, '0', '0', FALSE, 'en', 'odo@local.host', [RoleInterface::AUTHENTICATED_ID], FALSE, 99);
-
- // Ensure that the user can authenticate.
- $this->assertEquals(2, \Drupal::service('user.auth')->authenticate('Odo', 'a password'));
- // After authenticating the password will be rehashed because the password
- // stretching iteration count has changed from 15 in Drupal 7 to 16 in
- // Drupal 8.
- $user = User::load(2);
- $rehash = $user->getPassword();
- $this->assertNotEquals($password, $rehash);
-
- // Authenticate again and there should be no re-hash.
- $this->assertEquals(2, \Drupal::service('user.auth')->authenticate('Odo', 'a password'));
- $user = User::load(2);
- $this->assertEquals($rehash, $user->getPassword());
+ $users = Database::getConnection('default', 'migrate')
+ ->select('users', 'u')
+ ->fields('u')
+ ->condition('uid', 1, '>')
+ ->execute()
+ ->fetchAll();
+
+ foreach ($users as $source) {
+ $rids = Database::getConnection('default', 'migrate')
+ ->select('users_roles', 'ur')
+ ->fields('ur', array('rid'))
+ ->condition('ur.uid', $source->uid)
+ ->execute()
+ ->fetchCol();
+ $roles = array(RoleInterface::AUTHENTICATED_ID);
+ $id_map = $this->getMigration('d7_user_role')->getIdMap();
+ foreach ($rids as $rid) {
+ $role = $id_map->lookupDestinationId(array($rid));
+ $roles[] = reset($role);
+ }
+
+ $field_integer = Database::getConnection('default', 'migrate')
+ ->select('field_data_field_integer', 'fi')
+ ->fields('fi', array('field_integer_value'))
+ ->condition('fi.entity_id', $source->uid)
+ ->execute()
+ ->fetchCol();
+ $field_integer = !empty($field_integer) ? $field_integer : NULL;
+
+ $this->assertEntity(
+ $source->uid,
+ $source->name,
+ $source->mail,
+ $source->pass,
+ $source->created,
+ $source->access,
+ $source->login,
+ $source->status,
+ $source->language,
+ $source->timezone,
+ $source->init,
+ $roles,
+ $field_integer
+ );
+
+ // Ensure that the user can authenticate.
+ $this->assertEquals($source->uid, $this->container->get('user.auth')->authenticate($source->name, 'a password'));
+ // After authenticating the password will be rehashed because the password
+ // stretching iteration count has changed from 15 in Drupal 7 to 16 in
+ // Drupal 8.
+ $user = User::load($source->uid);
+ $rehash = $user->getPassword();
+ $this->assertNotEquals($source->pass, $rehash);
+
+ // Authenticate again and there should be no re-hash.
+ $this->assertEquals($source->uid, $this->container->get('user.auth')->authenticate($source->name, 'a password'));
+ $user = User::load($source->uid);
+ $this->assertEquals($rehash, $user->getPassword());
+ }
}
}