diff --git a/core/modules/comment/src/Tests/Migrate/d7/MigrateCommentTest.php b/core/modules/comment/src/Tests/Migrate/d7/MigrateCommentTest.php index 6c7277e..8d6e668 100644 --- a/core/modules/comment/src/Tests/Migrate/d7/MigrateCommentTest.php +++ b/core/modules/comment/src/Tests/Migrate/d7/MigrateCommentTest.php @@ -11,7 +11,6 @@ use Drupal\comment\Entity\Comment; use Drupal\migrate_drupal\Tests\d7\MigrateDrupal7TestBase; use Drupal\node\NodeInterface; -use Drupal\user\Entity\User; /** * Tests migration of comments from Drupal 7. @@ -37,12 +36,6 @@ protected function setUp() { 'd7_user_role', 'd7_user', ]); - // The test database doesn't include uid 1, so we'll need to create it. - User::create(array( - 'uid' => 1, - 'name' => 'admin', - 'mail' => 'admin@local.host', - ))->save(); $this->executeMigration('d7_node_type'); // We only need the test_content_type node migration to run for real, so // mock all the others. diff --git a/core/modules/migrate/config/schema/migrate.data_types.schema.yml b/core/modules/migrate/config/schema/migrate.data_types.schema.yml index 7521ee1..60dd519 100644 --- a/core/modules/migrate/config/schema/migrate.data_types.schema.yml +++ b/core/modules/migrate/config/schema/migrate.data_types.schema.yml @@ -10,6 +10,13 @@ migrate_plugin: migrate_destination: type: migrate_plugin label: 'Destination' + mapping: + overwrite_properties: + type: sequence + label: 'Properties to overwrite' + sequence: + type: string + label: 'Property' migrate_source: type: migrate_plugin diff --git a/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php b/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php index 69c9e66..f80034c 100644 --- a/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php +++ b/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php @@ -109,6 +109,17 @@ public function getIds() { * The row object to update from. */ protected function updateEntity(EntityInterface $entity, Row $row) { + // 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. + if (isset($this->configuration['overwrite_properties'])) { + $clone = $row->cloneWithoutDestination(); + foreach ($this->configuration['overwrite_properties'] as $property) { + $clone->setDestinationProperty($property, $row->getDestinationProperty($property)); + } + $row = $clone; + } + foreach ($row->getDestination() as $field_name => $values) { $field = $entity->$field_name; if ($field instanceof TypedDataInterface) { diff --git a/core/modules/migrate/src/Row.php b/core/modules/migrate/src/Row.php index 8774976..e055c1d 100644 --- a/core/modules/migrate/src/Row.php +++ b/core/modules/migrate/src/Row.php @@ -188,6 +188,15 @@ public function freezeSource() { } /** + * Clones the row with an empty set of destination values. + * + * @return static + */ + public function cloneWithoutDestination() { + return (new static($this->getSource(), $this->sourceIds, $this->isStub()))->freezeSource(); + } + + /** * Tests if destination property exists. * * @param array|string $property diff --git a/core/modules/migrate_drupal/src/Tests/d6/EntityContentBaseTest.php b/core/modules/migrate_drupal/src/Tests/d6/EntityContentBaseTest.php new file mode 100644 index 0000000..1015aa1 --- /dev/null +++ b/core/modules/migrate_drupal/src/Tests/d6/EntityContentBaseTest.php @@ -0,0 +1,93 @@ + 'signature', + 'entity_type' => 'user', + 'type' => 'text_long', + ])->save(); + + FieldConfig::create([ + 'field_name' => 'signature', + 'entity_type' => 'user', + 'bundle' => 'user', + ])->save(); + + User::create([ + 'uid' => 2, + 'name' => 'Ford Prefect', + 'mail' => 'ford.prefect@localhost', + 'signature' => array( + array( + 'value' => 'Bring a towel.', + 'format' => 'filtered_html', + ), + ), + 'init' => 'proto@zo.an', + ])->save(); + + $this->executeMigrations(['d6_filter_format', 'd6_user_role']); + } + + /** + * Tests overwriting all mapped properties in the destination entity (default + * behavior). + */ + public function testOverwriteAllMappedProperties() { + $this->executeMigration('d6_user'); + /** @var \Drupal\user\UserInterface $account */ + $account = User::load(2); + $this->assertIdentical('john.doe', $account->label()); + $this->assertIdentical('john.doe@example.com', $account->getEmail()); + $this->assertIdentical('doe@example.com', $account->getInitialEmail()); + } + + /** + * Tests overwriting selected properties in the destination entity, specified + * in the destination configuration. + */ + public function testOverwriteProperties() { + // Execute the migration in migrate_overwrite_test, which documents how + // property overwrites work. + $this->executeMigration('users'); + + /** @var \Drupal\user\UserInterface $account */ + $account = User::load(2); + $this->assertIdentical('john.doe', $account->label()); + $this->assertIdentical('john.doe@example.com', $account->getEmail()); + $this->assertIdentical('The answer is 42.', $account->signature->value); + // This value is not overwritten because it's not listed in + // overwrite_properties. + $this->assertIdentical('proto@zo.an', $account->getInitialEmail()); + } + +} diff --git a/core/modules/migrate_drupal/tests/fixtures/drupal7.php b/core/modules/migrate_drupal/tests/fixtures/drupal7.php index 3a9d266..0804334 100644 --- a/core/modules/migrate_drupal/tests/fixtures/drupal7.php +++ b/core/modules/migrate_drupal/tests/fixtures/drupal7.php @@ -39895,9 +39895,9 @@ )) ->values(array( 'uid' => '1', - 'name' => 'root', + 'name' => 'admin', 'pass' => '$S$D/HVkgCg1Hvi7DN5KVSgNl.2C5g8W6oe/OoIRMUlyjkmPugQRhoB', - 'mail' => '', + 'mail' => 'admin@local.host', 'theme' => '', 'signature' => '', 'signature_format' => NULL, diff --git a/core/modules/migrate_drupal/tests/modules/migrate_overwrite_test/migrate_overwrite_test.info.yml b/core/modules/migrate_drupal/tests/modules/migrate_overwrite_test/migrate_overwrite_test.info.yml new file mode 100644 index 0000000..503c6ce --- /dev/null +++ b/core/modules/migrate_drupal/tests/modules/migrate_overwrite_test/migrate_overwrite_test.info.yml @@ -0,0 +1,6 @@ +name: 'Migrate property overwrite test' +type: module +description: 'Example module demonstrating property overwrite support in the Migrate API.' +package: Testing +version: VERSION +core: 8.x diff --git a/core/modules/migrate_drupal/tests/modules/migrate_overwrite_test/migration_templates/users.yml b/core/modules/migrate_drupal/tests/modules/migrate_overwrite_test/migration_templates/users.yml new file mode 100644 index 0000000..e23d90d --- /dev/null +++ b/core/modules/migrate_drupal/tests/modules/migrate_overwrite_test/migration_templates/users.yml @@ -0,0 +1,31 @@ +id: users +label: User migration +migration_tags: + - Drupal 6 + - Drupal 7 +source: + plugin: d6_user +process: + # If the entity's ID is migrated, the Migrate API will try to update + # an existing entity with that ID. If no entity with that ID already + # exists, it will be created. + uid: uid + name: name + mail: mail + password: password + 'signature/value': + plugin: default_value + default_value: 'The answer is 42.' +destination: + plugin: entity:user + # If the destination is going to update an existing user, you can optionally + # specify the properties that should be overwritten. For example, if the + # migration tries to import user 31 and user 31 already exists in the + # destination database, only the 'name' and 'mail' properties of the user + # will be overwritten. If user 31 doesn't exist, it will be created and + # the overwrite_properties list will be ignored. + overwrite_properties: + - name + - mail + # It's possible to overwrite nested properties too. + - 'signature/value' diff --git a/core/modules/node/src/Tests/Migrate/d7/MigrateNodeTest.php b/core/modules/node/src/Tests/Migrate/d7/MigrateNodeTest.php index b2537f5..9a9024b 100644 --- a/core/modules/node/src/Tests/Migrate/d7/MigrateNodeTest.php +++ b/core/modules/node/src/Tests/Migrate/d7/MigrateNodeTest.php @@ -123,7 +123,7 @@ protected function assertRevision($id, $title, $uid, $log, $timestamp) { */ public function testNode() { $this->assertEntity(1, 'test_content_type', 'en', 'A Node', '2', TRUE, '1421727515', '1441032132', TRUE, FALSE); - $this->assertRevision(1, 'A Node', '2', NULL, '1441032132'); + $this->assertRevision(1, 'A Node', '1', NULL, '1441032132'); $node = Node::load(1); $this->assertTrue($node->field_boolean->value); diff --git a/core/modules/user/src/Plugin/migrate/source/d6/User.php b/core/modules/user/src/Plugin/migrate/source/d6/User.php index 59c3229..e344d06 100644 --- a/core/modules/user/src/Plugin/migrate/source/d6/User.php +++ b/core/modules/user/src/Plugin/migrate/source/d6/User.php @@ -25,7 +25,7 @@ class User extends DrupalSqlBase { public function query() { return $this->select('users', 'u') ->fields('u', array_keys($this->baseFields())) - ->condition('uid', 1, '>'); + ->condition('uid', 0, '>'); } /** diff --git a/core/modules/user/src/Plugin/migrate/source/d7/User.php b/core/modules/user/src/Plugin/migrate/source/d7/User.php index fc05bf3..fa872c6 100755 --- a/core/modules/user/src/Plugin/migrate/source/d7/User.php +++ b/core/modules/user/src/Plugin/migrate/source/d7/User.php @@ -25,7 +25,7 @@ class User extends FieldableEntity { public function query() { return $this->select('users', 'u') ->fields('u') - ->condition('uid', 1, '>'); + ->condition('uid', 0, '>'); } /**