I have been playing around with the migration system quite a bit and ran into a brick wall when it came to importing content when using Migration process which references a migration that has the destination no_stub option. In particular the Process Migration class (Drupal\migrate\Plugin\migrate\process\Migration) transform method uses cached versions of migrations that have already loaded their destination. This presents a problem because the Stub process uses the Entity Migration method getDestinationPlugin() and passes true in an effort to allow a MigrateSkipRowException. However, that exception will never occur since a cached migration entity is being used that has already loaded the destination without passing true to getDestinationPlugin().
Being relatively unfamiliar with Drupal 8 I was able to implement the below hack from what I learned through several rounds of xdebug sessions. I'm not sure it is the best solution but my migrations with no_stub set to true now seem to be respected with a MigrateSkipRowException being thrown properly.
The code in question is around line 106 of Drupal\migrate\Plugin\migrate\process\Migration. it is the area responsible for resolving the migration to be used to process the stub. Instead of using the existing migration instance I merely load in a new instance. This seems to work since the destination is unresolved and the following call to getDestinationPlugin() with true passed properly triggers the conditional to check for no_stub.
if ($self) {
$migration = $this->migrationStorage->load($this->migration->id());
}
elseif (isset($this->configuration['stub_id'])) {
$migration = $this->migrationStorage->load($this->configuration['stub_id']);
}
else {
$migration = $this->migrationStorage->load(reset($migrations)->id());
}
Comment | File | Size | Author |
---|---|---|---|
#32 | process_migration-2555127-31.patch | 13.41 KB | kostyashupenko |
#22 | interdiff.txt | 880 bytes | mikeryan |
#22 | process_migration-2555127-21.patch | 13.65 KB | mikeryan |
#7 | process_migration-2555127-7-FAIL.patch | 9.47 KB | mikeryan |
Comments
Comment #2
oddz CreditAttribution: oddz commentedComment #3
oddz CreditAttribution: oddz commentedComment #4
oddz CreditAttribution: oddz commentedComment #5
oddz CreditAttribution: oddz commentedComment #6
mikeryan#2575173: d6_user picture migration generates messages for empty pictures is blocked on this.
Comment #7
mikeryanFail patch demonstrating the problem.
Comment #8
mikeryanA straightforward solution - but I think throwing MigrateSkipRowException is an excessive response in general, and in particular is the wrong response in the #2575173: d6_user picture migration generates messages for empty pictures case. Maybe MigrateSkipProcessException? Or, maybe the solution (as oddz was pursuing) is to respond purely in the migration process plugin.
Comment #9
mikeryanJust a note to myself for tomorrow, since I don't think I'll finish this tonight - testing the user picture scenario, MigrateSkipProcessException is not the answer because that means the process pipeline ends up with the original incoming source value, whereas in this case we want it to be NULL (so in this scenario the user picture remains unset, and in cases where you do want to abandon the containing entity you can put skip_row_if_empty in your process pipeline).
So, it should be up to the Migration process plugin to recognize the no_stub case and return NULL.
Comment #11
mikeryanYes, it does make more sense for the destination to apply its own no_stub configuration, rather than the Migration entity's getDestinationPlugin()...
Comment #13
mikeryanComment #15
mikeryanSo, apparently the no_stub schema was defined in the wrong place all along...
Comment #16
mikeryanAll righty - ready for manual review.
Comment #17
quietone CreditAttribution: quietone commentedRan the tests, checked the code re standards and it all looks good to me.
+1 RTBC
Comment #18
benjy CreditAttribution: benjy commentedThis looks good to me.
By returning an empty array in import rather than skipping from the process plugin, the executable logs "'New object was not saved, no error provided'" rather than MigrateIdMapInterface::STATUS_IGNORED ?
Am I missing something extra here?
Comment #19
mikeryanThe empty return when a stub is requested and stubbing is not supported only happens when the import is invoked from the migration plugin, not when run under the (direct) control of the executable. The empty array is returned by the migration plugin, and it's up to subsequent process plugins (if any) to decide what to do when no stub was created - typically I would expect you would use skip_row_if_empty if the field was necessary, default_value if there is a reasonable default you can give, or simply drop through to leave the field empty as in #2575173: d6_user picture migration generates messages for empty pictures.
Comment #20
benjy CreditAttribution: benjy commentedAhh, thats the key bit of information. Maybe we should add that in a comment, RTBC otherwise for me.
Comment #22
mikeryanComment added, thanks!
Comment #23
benjy CreditAttribution: benjy commentedThanks.
Comment #24
dmoore CreditAttribution: dmoore commentedI have applied patch process_migration-2555127-21.patch, and can confirm all the File stub creation errors when migrating users have now disappeared, and the user records are being created correctly with an empty user picture.
Great job.
Comment #25
chx CreditAttribution: chx at Smartsheet commentedRepeating the same check in every import method is a waste of effort. The menu patch at #2589237: Menu links parent migration is broken fixes the same problem with a few lines of code:
Comment #27
mikeryanNovice task to reroll, and try chx's suggestion.
Comment #28
mikeryanI'll retest the user picture fix against current core and see if the change in #2589237: Menu links parent migration is broken is enough.
Comment #29
mikeryanYep, that menu links patch fixed this.
Comment #30
dcam CreditAttribution: dcam commentedTagging for the reroll in advance of Friday's mentored sprints.
Comment #31
mikeryanSorry @dcam, neglected to change the status.
Comment #32
kostyashupenkoreroll of #22
Comment #34
mikeryanSorry, the problem is already fixed.
Comment #35
xjm