I have a very simple migration for migrating roles. The map table looks like this after running the migration:
+-----------+---------+--------------+---------------+
| sourceid1 | destid1 | needs_update | last_imported |
+-----------+---------+--------------+---------------+
| 3 | 3 | 0 | 0 |
| 4 | 5 | 0 | 0 |
| 5 | 4 | 0 | 0 |
+-----------+---------+--------------+---------------+
If I run a subsequent migration with --update, the map table then looks like this:
+-----------+---------+--------------+---------------+
| sourceid1 | destid1 | needs_update | last_imported |
+-----------+---------+--------------+---------------+
| 3 | 6 | 0 | 0 |
| 4 | 8 | 0 | 0 |
| 5 | 7 | 0 | 0 |
+-----------+---------+--------------+---------------+
I looked at the MigrateDestinationRole::import() code, and I think I see why. Looks like $entity->rid only gets set if $entity->rid is already set (which seems a little pointless, since if it's set and it's the wrong value, it throws an Exception).
// Updating previously-migrated content?
if (isset($row->migrate_map_destid1)) {
if (isset($entity->rid)) {
if ($entity->rid != $row->migrate_map_destid1) {
throw new MigrateException(t("Incoming id !id and map destination id !destid don't match",
array('!id' => $entity->rid, '!destid' => $row->migrate_map_destid1)));
}
else {
$entity->rid = $row->migrate_map_destid1;
}
}
}
I'm wondering why it couldn't be this:
if (isset($row->migrate_map_destid1)) {
$entity->rid = $row->migrate_map_destid1;
}
Marking this as major, as it completely hosed my user migration, and added a bunch of cruft in the database.
Comments
Comment #1
q0rban commentedWell, I tried to write a test for this, but it was failing silently, due to exceptions just getting logged to the message table, but not actually killing the test.
Here was what I added to user.test:
I used Migrate::setDisplayFunction() to store the messages in a global variable.
The test above actually passes, because the integrity constraint makes it so that duplicates aren't possible. In my migration, the names were getting appended with a number, so I wasn't running into that, not sure how/why.
Anyway, I can confirm the bug exists in migrate itself, but don't know a way to easily write a test to prove it, without doing queries to the message table looking for these errors, which seems error prone itself. Is there a way to just get number failed or something?
I can confirm that this patch does fix the issue, though.
Comment #2
q0rban commentedComment #3
mikeryanI think it's just fine to check the message table, I've added a test to do that.
I'd like to keep the check on rid discrepancies - yes, you'd have to work hard to make that fail, but Murphy will someday bite someone. The base problem is that the assignment of $entity->rid is at the wrong nesting level.
I couldn't reproduce the duplicate role creation with WineRoleMigration, just the dupe keys on insert you saw in the test, so please give this a patch a try and make sure it addresses your scenario.
Thanks.
Comment #4
mikeryanThat last patch is at least an improvement, so I've gone ahead and committed it. James, if it doesn't address your duplicate role problem, please reopen.
Thanks.
Comment #5
q0rban commentedYep, that fixed it! Thanks. :)
Comment #6
q0rban commentedFor the record, the reason I was getting new records instead of the integrity constraint violation is because dedupe() was being called on the name mapping: