Closed (fixed)
Project:
Drupal core
Version:
8.0.x-dev
Component:
migration system
Priority:
Major
Category:
Bug report
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
29 Sep 2015 at 20:31 UTC
Updated:
16 Oct 2015 at 18:44 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
mikeryanHad some discussion with @phenaproxima, who has dug into this area before. As I understand it, in Drupal 6 the widget_type affected the actual database representation, which was fine when it was creating separate tables, but in Drupal 8 the (well, some) distinctions between field types that D6 had at the widget level are now in the base field. So, we actually do need to account for the D6 widget type in creating the D8 field. The problem is if a D6 site used different widget types in different instances of the same field - there's only going to be one field in D8, so we can't apply both widget types. Right now, if I'm not mistaken, the last instance processed takes precedence.
So, the first pass at this, my plan is to take the instance join out of the base query and pull the "first" widget_type in prepareRow() - this fixes the isComplete() problem without making handling conflicts between instances any worse. I'll also detect the situation of conflicting instances and generate a message, so (unlike today) the migrator will get some clue that things aren't 100% hunky-dory. @phenaproxima suggests maybe trying to normalize conflicts to a lower-common-denominator field type - that may be best left to a follow-up issue. The question is, how many real-world D6 sites have instance conflicts that matter?
I presume this issue must have been dealt with in the D6 CCK->D7 field upgrade path, we should investigate that.
Comment #3
mikeryanA fail patch to demonstrate the issues.
Comment #5
mikeryanYep, exactly the expected failures.
Comment #6
benjy commentedIf we're getting duplicates from that query because of the join on CNFI, lets just group by field_name, that will remove the duplicates and then we'll be using the widget type from the first match which is fine. If you reuse the same field across bundles in D6 with two different widgets then we'll only be looking at one but that's no worse than what we're doing now.
Comment #7
benjy commentedAdded a couple of distinct calls for comment and d7 field.
With the d6 field source, it wasn't so easy to just add a groupBy and make it full with all the fields/map fields in the select so i used another join with a sub query that did the group by and used MAX(widget_settings) to single out a row between the duplicates, not sure about that part, will sleep on it.
Lets see what the bot thinks.
Comment #8
mikeryanwidget_settings isn't actually needed, only widget_type is used to determine the ultimate field type, I was removing it in my patch.
The advantage of pulling the widget_type from the instance in prepareRow(), rather than selecting an arbitrary type in the query, is that it allows us to warn the user that something's missing.
Comment #9
mikeryanRemoving widget_settings, which enables some simplification of the query.
Comment #10
mikeryanAfter discussion with phenaproxima, I'm going to go with pulling the widget_type in prepareRow(), so we can produce a message when we detect a conflict in instance widget_types.
Comment #11
mikeryanComment #12
mikeryanHere it is... The one thing it's lacking is a test for the message coming from conflicting widget_types, because in the current data the instances that were generating the extra source count differed only in widget_settings, they had the same widget_type. So, another instance needs to be added to the source data to be able to test the message...
Comment #13
mikeryanSo, the existing D6 dump has two instances of field_test (on the story and test_page node types), both with widget_type text_textfield. To test dealing with instances of one field with different widget_types, I created another instance on the test_planet node type, with widget_type optionwidgets_onoff. My test of this functionality succeeded - yay! But, now MigrateFieldInstanceTest fails when testing story's instance of field_test. That's because optionwidgets_onoff comes before text_textfield alphabetically, so that the base field_test becomes a boolean field - not at all what this test is expecting.
The problem here is a basic WTF of migrating D6 CCK to either D7 or D8 - why, here's what the D7 content_migrate module tells you if you have this situation:
I.e., if you used different widget types on different instances of a field on D6, you're fucked. Frankly, if you used a text widget for one instance of a field and a radio button/checkbox for another, you deserve it - the saving grace is that this is probably (I hope) a very rare condition.
Anyway, since MigrateFieldInstanceTest was not designed to be a demonstration of this problem, I need to use different test data that doesn't overlap with instances explicitly used by existing tests.
Comment #14
mikeryanFinally... Also tweaked the message with feedback from phenaproxima.
Comment #16
mikeryanOh, of course, need to add another field table to the dump... Bah.
Comment #17
mikeryanOr, I should say, add field columns to the node field table. Enough for me for today, I'll pick it up in the morning (unless someone else wants to jump in...)
Comment #20
mikeryanUgh, without a dump that could be used to run a real D6 site so I can manipulate the fields through the UI and have all the DB tables end up in the right place, testing this is damned near impossible. Maybe #2562695: migrate-db.sh skips uid 1 but shouldn't will rescue me?
Comment #21
mikeryanComment #22
mikeryanWith much struggling, managed to get the dumps files in the right place (I think).
Comment #23
phenaproximaNit: Can the delimiter be ", " (note the space)?
Everything else looks good and right to me.
Comment #24
mikeryanSure - let's just wait and make sure the test results don't require any other changes.
Comment #26
mikeryanIt caught me trying to hack the dump files to minimize the changes... Fine, whatever...
Comment #28
mikeryanFor want of a space, the test was lost...
Comment #29
phenaproximaTo me, this patch looks good. I'd like @benjy's input for RTBC.
Comment #32
benjy commentedThat's exactly how we're meant to reproduce the dumps, by importing them, using a D6 site with the codebase here https://www.drupal.org/sandbox/benjy/2405029 and the exporting again with migrate-db.sh. Is that how we created the new dump file?
Given that there aren't likely that many widget types, I wonder if we should query for all widget types in initializerIterator() just once and then have a lookup in an array of field_name => widgets here? Although performance probably isn't an issue with the field migration...
Why an assert? Do we have docs on when to use these somewhere?
Comment #33
mikeryanAh, I vaguely recall the sandbox... I created a D6 environment of my own with the necessary contrib modules and managed to get it into good enough shape to add the instance and export.
Yeah, I think it's clearer to pull them directly here. Overriding initializeIterator() would be an unusual pattern and a "wait, what?" for future reviewers.
Taking advantage of https://www.drupal.org/node/2569701 - not sure how aggressively we're supposed to use them, couldn't resist the shiny new feature;).
Comment #34
benjy commentedOK rest looks good, as discussed on IRC, can we remove the assert on commit and then @mikeryan, could you create a follow-up to discuss using asserts in migrate.
Comment #35
mikeryanGiven a general policy on asserts has an issue at #2548671: [policy, no patch] Define best practices for using and testing assertions and document them before adding assertions to core, I don't think we need a migrate-specific policy (at least unless/until that policy is in place and we decide we should make exceptions).
Comment #38
webchickSorry, that second commit was because mikeryan had told me just before leaving that that line was somewhat contentious and asked to remove it before commit, but I forgot. :P
Comment #40
phenaproximaUm, no...this is fixed.