Problem/Motivation
Currently, stubs are blindly created for any referenced entity ID on the source site, even if that is a non-existing entity reference ID!
If you're also validating all your migrated entities (like you should be), which is possible since #2745797: Add option to content entity destinations for validation (see https://www.drupal.org/node/3073707 for the CR), then all of those rows will also not trigger validation errors, when in reality they should.
This means you end up getting a false sense of security: your entities are migrated and pass validation.
Proposed resolution
Only create stubs if the source plugin finds a row for the given source ID values.
Remaining tasks
Test coverage.
User interface changes
None.
API changes
TBD
Data model changes
TBD
Release notes snippet
TBD
| Comment | File | Size | Author |
|---|---|---|---|
| #47 | interdiff-3156730-44_47.txt | 500 bytes | gauravvvv |
| #47 | 3156730-47.patch | 20.93 KB | gauravvvv |
| #31 | core-create_stub_only_when_matching_source_row_exists--9.2.x--3156730-31.patch | 17.33 KB | huzooka |
| #31 | core-create_stub_only_when_matching_source_row_exists--9.0.x--3156730-31.patch | 17.33 KB | huzooka |
| #31 | interdiff-3156730-29-31.txt | 11.51 KB | huzooka |
Issue fork drupal-3156730
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
wim leersComment #4
wim leersComment #6
wim leersThis means there's probably 4 entities pointing to non-existing menu links
All other failures are only occurring for Drupal 6 migrations; apparently there's something different about how Drupal 6 migration plugins/definitions are processed.
Comment #7
huzookaRe #4:
I don't see how we can assume that the column name (what you use in the condition) is in the plugin's configuration (with key
source). That's a wrong assumption. With this patch, you will get these kind of errors if you migrate users with pictures before the file migration was executed:SQL error:
Lets pick the very last condition:
(= :db_condition_placeholder_2). Yes, the column name is missing :).Why?
Let's see how the user migration looks:
First of all, the migration_lookup plugin's configuration does not have a
sourcekey. But if it would be the the first process plugin in theuser_picture's process pipeline, that would be defined asThis still leads to the SQL error cited above.
Whenever this process plugin isn't the first process plugin, you won't have that key set at all. What you need there is the ID(s) of the source:
$source_plugin->getIds(). Ideally, you need as many incoming value in$valueas many source ID the stub_migration's source plugin defines (or just hope that there will be only one result).Comment #8
huzookaMoved the "fixed" main logic into
\Drupal\migrate\MigrateStub, and since with that change it is actually feasible to create a valid stub in the right migration, I removed the "only one stubbing migration" restriction from\Drupal\migrate\Plugin\migrate\process\MigrationLookup.Comment #9
huzookaComment #10
huzookaComment #11
huzookaComment #12
huzooka#11 contains the same patch as #8.
Comment #13
huzookaComment #14
huzooka\Drupal\migrate\MigrateStubalso got additional test coverage inMigrateStubTest::testCreateStub.Comment #15
huzookaComment #16
huzookaThis is the right patch for 9.1.x.
Comment #17
huzookaI will fix the coding standard violations
Comment #18
huzookaComment #20
wim leers#7: superb comment! Crystal clear. I obviously made grossly simplistic assumptions. Thanks for describing in detail why I was wrong, it makes it very easy to see that your proposed patch is the appropriate solution!
🤓 Nit: I'd have preferred to start with
$sql_succeed = TRUEand then set it toFALSEif an exception is caught.I think that'd be easier to understand.
Right now on the first reading it would seem that if the SQL query doesn't find the requested source row, that then we fall back to the slower behavior anyway! That's not the case, but restructuring the logic that slight way would make it more obvious I think 😊
👍 This will be slow but there's nothing we can do about it…
🤓 Shouldn't this be
$exceptioninstead of$e? Otherwise it will not be rethrown…🙏 Let's not lose the helpful comments that used to be there before this refactor?
Clever 😃
🥳
🤔 What makes this have a valid source ID andSee next point.taxomy_term_stub_testnot?🤔🙏 It took me a while to understand that the new
taxonomy_term_stub_test_validis to be used in tandem withtaxonomy_term_stub_test, specifically for this test. I think this would've clarified it a lot:🤓 s/not exists/does not exist/
Comment #21
wim leersThis is resulting in hard-to-debug messages such as:
It'd be better to include the exception class + message, like so:
Comment #22
huzookaRe #21:
That's a legacy line :)
Comment #23
huzookaI just realized that the original comments of the exceptions (that are mentioned in #20.5) are/were misleading, because they also caught the same exceptions thrown in
MigrateStub::doCreateStub().Comment #24
huzookaFixed #21, and also addresses #20:
$this->assertNotSame('cat', $stub_entity->label());because the stub's label is a random generated string, and nothing guarantees that it won't be 'cat'. I hope that$this->assertEquals(MigrateIdMapInterface::STATUS_NEEDS_UPDATE, $stub_row_3['source_row_status']);also helps.Comment #25
huzookaComment #26
wim leersAh yes,
InvalidArgumentException extends LogicExceptionand therefore this catch would've prevented the problem we saw in #21. 👍WFM! 👍
Comment #27
wim leersThis is a BC break.
AFAICT this BC break can easily be avoided? 🤔
#3146646-2: Clean up ParagraphsLookup could've been avoided too then?
Comment #28
huzookaHmmmm. Yes, it can be avoided! I've seen several times, how.
Comment #29
huzookaI removed the feature that made possible to stub an entity in the right migration derivative (that was the reason of the need for the migration plugin manager injection, and it was an implicit feature addition as well).
So there shouldn't be any BC violations anymore.
Comment #30
huzookaComment #31
huzookaComment #32
huzookaComment #33
wim leersAhhh, that looks much better indeed! And much simpler 💪
Comment #34
mikelutzSo, I'm not opposed to adding this feature, I think it could help flag migrations issues, but I'm not a huge fan of having all of this souce plugin type dependent code here in the service. Would it be possible to create a new interface for source plugins, `MigrateSourceIdCheckInterface`, with a single method, `hasSourceIds(array $source_ids) : bool` That could let source plugins decide how to handle checking whether source ids exist? `SourcePluginBase` could implement the long one, `SqlBase` could do the query, and other source plugins could implement the check efficiently in a way that makes sense for them.
This also needs to be configurable, as current expected behavior is to create a stub regardless of whether the referenced migration has a row or not. For something other than a Drupal upgrade, this behavior can be desired. complex workflows with migrations for non upgrade reasons may be expecting this. There may be an expectation that the referenced entity will be added to the referenced source at a later date. Even if that's a rare use case, Migrations to pull data from apis all the time such that trying to cycle through all the source ids for every reference would be a huge performance hit. Custom remote sources may be able to implement a remote query to determine quickly if a source id actually exists though, so I think this really needs to be considered a feature request and handled in a BC way so that the old behavior is preserved by default, and I think the source plugins should have the ability to determine the best way to find out if a given id exists.
Same as above, you are changing the behavior of this plugin in a non bc way, so it needs to default to the old behavior and have a configuration option to override.
Comment #35
berdirRelated issue when the reason for an ID to not exist is because it's part of a different migration if you have multiple possible migrations. #2842811: Stubbing goes wrong in processes with several migrations
Comment #36
wim leersFor #35.
Comment #37
quietone commentedThis issue is not specific to Drupal 7 sources, removing tag.
Comment #38
thursday_bw commentedre: #21
New issue created [https://www.drupal.org/project/drupal/issues/3202665] to deal with that issue specifically. Let's keep issue's to one issue per issue.
Comment #39
thursday_bw commentedDeal with this in it's own issue: https://www.drupal.org/project/drupal/issues/3202665
Comment #41
wim leers#3207968: Replace @codingStandards comments with phpcs: comments broke this between
9.1.7and9.2.0-rc1.This does not address #34 yet, so keeping NW.
Comment #43
kimberleycgmI've implemented the configuration option and defaulted to the previous behaviour. Haven't addressed the first point from #34 yet though.
Comment #44
kimberleycgmFirst pass at creating MigrateSourceIdCheckInterface to pull that logic out of the method. Kept the fallback for plugins that don't implement the interface. Also cleaned up the variables to (I hope!) make it clearer what's happening.
As an example I implemented it for migrate_source_csv's CSV plugin using the following:
Comment #45
kimberleycgmComment #47
gauravvvv commentedRe-rolled patch #44, Fixed phpcs issues. Attached interdiff for same.
Comment #49
kimberleycgmFixed test error.
Comment #51
huzookaIf any of the followers want to use the feature, you can do so with this process plugin I wrote 16 months ago (and released almost a year ago thanks to Acquia): #3224702: Release the magical migration lookup process plugin, I also add it as a related issue.
MigMagLookup documentation (with a lot of typos as I see).
We have been using it for a while – it made us able to completely drop the currently known follow-up migration concept.
And if it is necessary to stub non-existent entities, then you can specify a stub trap migration for these missing entities (check out the "Use a fallback migration to collect invalid (missing) target ID references" example).
Comment #53
floydm commentedRerolling patch #49 for D9.4.8.
Comment #55
wim leersThank you, @floydm! 😊 I'm glad Acquia isn't the only organization using this Migration system improvement! 👍
I will not have capacity to address the maintainer's feedback from #34.
Comment #57
wim leersConflicted with #3312733: SQL migrations cannot be instantiated if database is not available and Node, Migrate Drupal modules are enabled. Rerolled #53.
Comment #58
mikelutzStill needs work for #34
Comment #61
trackleft2Hiding patch files in favor of a Merge Request.
Comment #62
trackleft2Comment #63
trackleft2