Hi there! ^_^
I was testing out the new multilingual node migration support in 8.1.6 (patch) now that #2225775: Migrate Drupal 6 core node translation to Drupal 8 has made its way into 8.1.x + 8.2.x
api = 2
core = 8.x
projects[drupal][type] = core
projects[drupal][version] = 8.1.6
; Patches for Drupal Core
projects[drupal][patch][2225775] = https://www.drupal.org/files/issues/2225775-i18n-node-238.patch
...
Unfortunately I have not been able to get the migration process plugin to link up the nodes and instead use an entity update vs entity creation. The rough yml resembling below and linking to a first migration import of the nodes. This is based on the added migrate_external_translated_test example in the referenced patch above:
process:
id: name
title: title
nid:
plugin: migration
migration: wxt_node_json
source: name
I then instead tried the following using default_value and then the first node was correctly linked leading this to be a problem with the migration process plugin:
process:
id: name
title: title
nid:
plugin: default_value
default_value: 1
I eventually traced this to the logic in:
MigrateExecutable.php
for the method:
processRow()
and the line:
$plugin->transform($scalar_value, $this, $row, $destination)
which when called always returns empty for $destination_property being "nid" even though when entering that function and traversing I can correctly see it is performing the lookup correctly and getting the $destination_ids as the following:
Array
(
[0] => 1
[1] => en
)
Array
(
[0] => 2
[1] => en
)
However in the earlier part of the transform method the $value passed was a simple sourceid lookup and thereby detected as a scalar so at the end of the method that part of logic is entered which has no way to return these set of values as the count is greater then 1 and a scalar.
if ($destination_ids) {
if ($scalar) {
if (count($destination_ids) == 1) {
return reset($destination_ids);
}
}
else {
return $destination_ids;
}
}
I changed with to the following:
if ($destination_ids) {
if ($scalar) {
+ if ($destination_property == 'nid') {
+ return reset($destination_ids);
+ }
if (count($destination_ids) == 1) {
return reset($destination_ids);
}
Attaching a patch which hopefully illustrates my issue and maybe points to something I did wrong?
Can see the complete migration code + yml I am working with @ https://github.com/wet-boew-wem/wxt-migrate
Comment | File | Size | Author |
---|---|---|---|
#22 | interdiff-19-22.txt | 2.43 KB | maxocub |
#22 | 2767643-22.patch | 4.92 KB | maxocub |
#19 | 2767643-19.patch | 3.87 KB | maxocub |
#19 | 2767643-19-test-only.patch | 2.84 KB | maxocub |
#12 | 2767643-migration-scalar-handling-3.patch | 1.03 KB | TrevorBradley |
Comments
Comment #2
sylus CreditAttribution: sylus commentedComment #3
sylus CreditAttribution: sylus commentedComment #4
sylus CreditAttribution: sylus commentedComment #5
sylus CreditAttribution: sylus commentedThe fix works but is obviously a hack so any guidance on perhaps something I may have missed or a better solution would be great! ^_^
Comment #7
sylus CreditAttribution: sylus commentedThis fix was specific to 'nid' but any entityreference field_*/target_id would also need this fix for translatable nodes. The real problem is the languages are added as part of the dest_ids and the scalar transform method doesn't correctly handle this. Not sure if this is the correct way to fix this but as languages are vaild destination_ids I just changed the count.
Comment #8
phenaproximaComment #9
phenaproximaI'm not sure this fix is going to be valid. This returns reset($destination_ids) if it's 2 or less -- but some IDs might very well need two values to be considered complete. IMHO, the fact that it passes all the tests proves that our coverage for the Migration plugin is wholly insufficient.
I would suggest the following, at the end of Migration::transform():
Comment #10
TrevorBradley CreditAttribution: TrevorBradley commentedI have a distinctly different issue from phenaproxima, with the same root cause. The folks in #drupal-migrate suggested I directly modify this issue.
I'm attempting to use the migrate module to import Paragraphs. After a patch to Entity Reference Revisions, the migration map for a destination plugin of "entity_reference_revisions:paragraph" correctly creates a map with two destid's. Migration::transform *almost* correctly translates the single migration id into target_id and target_revision_id, but it fails horribly in the last 10 lines.
If the migration's input value is a scalar, but the expected return value is an array, Migration:transform currently returns NULL.
$scalar's value is set in this block of code:
And the return value is determined by this block of code:
The problem is, if $value is initially a scalar, but $destinitation_ids is expected to be an array of size > 1, the code goes into the scalar loop, and returns nothing because count($destintation_ids) isn't 1.
Unlike phenaproxmia's solution, I really do need both of those values returned. It's not possible to reference an entity_reference_revision without both keys. I do not want $destination_ids to be reset.
I'm actually submitting two patches that fix this problem. A "quick fix" (#1), that ensures that Migration::transform returns a value in this scalar->array migration case, and a more brutal "Why do we need scalars anyway?" approach (#2) that just discards the $scalar variable and returns a scalar if there's only one return value, but returns an array if there's an array.
I suspect #1 will be too much of a hack to be accepted, and that I'm misunderstanding some fundamental reason why scalars should be preserved, and that #2 goes too far. Hopefully both will provoke discussion and result in a better patch.
Both patches work with my test case.
Comment #11
mikeryanSetting to "Needs review" - let's let the testbot verify these don't blatantly break things (stipulating as phenaproxima points out that the test coverage is probably inadequate to fully prove nothing will break).
If $value is already an array, this would seem to wrap an extra array around it. How about
(array)$value
?Comment #12
TrevorBradley CreditAttribution: TrevorBradley commentedGah, you're right @mikeryan. Let me reroll a patch to replace #2...
Comment #13
chx CreditAttribution: chx at Smartsheet, Migrate Rocks commentedSolution: add an option to switch off the scalar magic completely. One size doesn't fit all.
Comment #15
mikeryanNeeds work because needs tests.
Comment #16
heddnThis was briefly discussed in the weekly migrate call last night. There wasn't enough time to reach a consensus on how to address a solution here. However, after thinking about the conversation, I would propose that we work on tests in this area first, then come back to fixing this.
The two strongest motivators for this patch are migrating i18n sites from CSV and other non-Drupal sources and migrating multiple paragraphs into a node, etc. Both of those cases have temporary work-around using the above patches, so let's take a little time and improve test coverage first, then fix this right. If writing tests seems to drag on a long time, then we can revisit trying a quicker fix.
Thoughts on this proposal? I looked for an existing issue for 'improve/modernize of the migration process plugin's tests". I couldn't find one. If one doesn't exist, we'll need to create it.
Comment #17
heddnPostponing this temporarily while we work on tests. Related issues added for the blocking tasks before we can return to this.
Comment #18
maxocub CreditAttribution: maxocub commentedThis is also needed for #2827644: Fix path alias migration of translated nodes [D6].
Comment #19
maxocub CreditAttribution: maxocub commentedFollowing @benjy's comment #6 in #2826638: Create a KTB for migrate's process plugins I decided to write a unit test here because this bug needs to be fixed in order to move forward with #2827644: Fix path alias migration of translated nodes [D6].
Comment #21
heddnGreat job on writing the test and ignoring the dependencies here.
One point of feedback I'd like to see in the test is 3 scenarios. Storing the values into a field in my mind is important because there's no way to know if the format of the returned value from the migration process plugin is valid enough for storage in an ER field without going all the way.
Still leaving at NR for other reviews.
Comment #22
maxocub CreditAttribution: maxocub commented@heddn: I don't have any idea how to test the storing of values into fields with this unit test. I think we'll need the kernel test for that.
I added some comments in the test to underline what scenarios are tested here.
In short, it's testing that the migration process plugin can handle single (scalar) and multiple (array) values for input and output.
The migration_map_* tables can have one or more source IDs (sourceid1, sourceid2, etc.) and one or more destination IDs (destid1, destid2, et.). The migration process plugin should be able to handle the four possibilities:
Comment #23
heddnThanks for that extra explanation. I've also tested the patch (it is required for err) over in #2809793: EntityReference migrate destination. And over there I'm doing testing of the various field combinations I asked for in in #21. I think unit testing is enough here, so marking this RTBC.
Comment #25
maxocub CreditAttribution: maxocub commentedRandom fail, back to RTBC.
Comment #27
catchCommitted/pushed to 8.3.x and cherry-picked to 8.2.x. Thanks!
Comment #30
maxocub CreditAttribution: maxocub as a volunteer and commented