Problem/Motivation
For example, the https://www.drupal.org/project/media_migration module ensures the media_filter filter in D7 gets mapped to the media_embed filter in D8/9.
But:
- The D7
media_filterfilter did not have any settings. - The D8/9
media_embedfilter does have settings, and specifies some defaults because of that. - The D8/9
media_embedfilter implementscalculateDependencies()to ensure any Text Format that uses this filter also has the appropriate config dependencies. In this logic, it inspects the settings. - When those settings are not specified (which they should be given they're in the default settings in the filter plugin annotation), this triggers a fatal error:
Error: Unsupported operand types in Drupal\media\Plugin\Filter\MediaEmbed->calculateDependencies() (line 523 of /Users/wim.leers/Work/d8/core/modules/media/src/Plugin/Filter/MediaEmbed.php)
Steps to reproduce
Proposed resolution
Harden \Drupal\filter\Plugin\migrate\process\FilterSettings::transform(), beyond what #2946889: Missing migration filters that are replaced with filter_null may have invalid settings applied already did.
Remaining tasks
Tests
User interface changes
None.
API changes
None.
Data model changes
None.
Release notes snippet
TBD
| Comment | File | Size | Author |
|---|---|---|---|
| #38 | 3166930-38.patch | 9.34 KB | ovilla |
| #35 | 3166930-34.patch | 9.26 KB | wim leers |
| #34 | 3198732-33.patch | 9.72 KB | wim leers |
| #27 | interdiff_26-27.txt | 811 bytes | danflanagan8 |
| #27 | 3166930-27.patch | 9.27 KB | danflanagan8 |
Comments
Comment #2
wim leersWhen this gets committed, #3166602: Ensure media_filter → media_embed mapping does not cause fatal errors becomes obsolete.
Comment #4
wim leersComment #5
wim leersTo reduce the painful disruptiveness of fatal errors during migrations, I created #3167267: MigrateExecutable should catch not only exceptions, but also fatal errors to solve that problem generically.
Comment #6
benjifisherThis issue still has the "Needs tests" tag. If the patch does still need tests, then the status should be NW.
I see a small update to one of the tests. Does that make a difference, or does it just replace Mocks with Prophesies?
The affected code is a migrate process plugin. Even though that code lives in the Filter module, perhaps the Component should be changed to "migration system".
Comment #8
quietone commentedThe migrate maintainers work from the 'migration system' component.
Comment #9
quietone commentedA process plugin should never look at the destination. Another solution needs to be found for this to go in to core. I think a destination plugin. If there are other config migrations that need to 'merge' data with the existing configuration then maybe changes could be made in \Drupal\migrate\Plugin\migrate\destination\Config with maybe a new configuration key. But I can't think of any config migration that needs such a thing.
Migrate is full of unique cases.
The IS and the comments all refer to Drupal 7 yet this is tagged for Drupal 6 source as well. How does this apply to Drupal 6 sources? Does Drupal 6 have the media_filter as well?
Comment #11
wim leersI agree with the principle.
But … I disagree with it in this case 🤓
Like explained above, we need to add the default filter settings. That means … the default Drupal 9 filter settings. (Even if we wanted to, we could not get the default Drupal 7 filter settings, since we cannot execute Drupal 7 code from within Drupal 9.)
I could use
… but that would give me the D7 filter ID, not the equivalent D9 filter plugin ID. That's why this uses
getDestinationProperty().Therefore I see no other solution possible here.
Marking for getting approval for this approach, but this definitely still needs tests.
Comment #12
danflanagan8It's common to pass in a destination value as part of the
sourcethough. It might be clumsy to add the processed id to the source in this case, but maybe we could add a new (optional) configuration parameter tofilter_settings. The yml could look like this:The entity_generate plugin in migrate_plus can do something like this. It's actually related to setting default values so it's almost exactly like the situation with filters. You can pass in an array of
valuesand there's a nifty little call to$this->row->get($property)to get the value.So in our case, assuming we add a config key called
default_settings_filter_id, we could just call$this->row->get($this->configuration['default_settings_filter_id'])instead of$row->getDestinationProperty('id')Comment #13
danflanagan8I also found an instance in core where a process plugin has a hardcoded reference to a destination value. It's in
d7_field_instance_settings.$allowed_values = $row->get('@allowed_values');/code>Comment #14
danflanagan8Here's a show at a fail test for this issue. This changes a few test cases to expect that filter settings get default values added during migration if necessary. Does this look reasonable?
From what I can tell, the test was updated in #4 to account for the change to
FilterSettings::__construct.Comment #16
danflanagan8Those failures look good. Setting back to NR to get a review of the updated test cases. Are those good enough to work against?
Comment #18
quietone commentedThis issue came up in the migrate meeting today. I took a closer look at the patch and the filter migration and now see why the process plugin is accessing the destination row. I don't tend to write process plugins like that but that is not the point. The point is that I withdraw my objection about accessing the destination row as sated in #9.
I would still like an answer to my question in #9.
Comment #19
wim leersIs that this question, @quietone? :)
Comment #20
danflanagan8I'm going to post a new patch where the fix from #4 runs against the tests from #14 (except with a whitespace removal reverted and another trivial simple test case added). This is going to fail still, but that's ok.
The new tests case is below. I don't think and interdiff adds much here so I'm not adding one.
Comment #21
danflanagan8Removing the use.
Comment #23
danflanagan8That one fails because the
$filter_plugin_managerisn't sufficiently mocked. I think at this point, I think the right thing to do is convert this to a Kernel test (it's a Unit test in the Kernel directory!?!?) so that theplugin.manager.filterservice exists in full.After making that conversion to a Kernel test, the cases with
any_filterstart failing because the plugin manager can't find that filter.In real migrations this isn't a problem because
$row->getDestinationProperty('id')would returnfilter_nullinstead ofany_filter. I opted to enable thefilter_test_pluginmodule and replaceany_filterwithfilter_sparkles, which is a dummy plugin provided by that module.Comment #25
danflanagan8Now we are to interesting test failures. The test cases where we pass in a string fail because of the
assert(is_array($value))that is part of the code block that gets and applies default values.What's the deal with passing a string anyway? Is that a real-world scenario? I guess we should try to maintain the existing behavior, which means this still needs work.
Comment #26
danflanagan8Here's me going a little nuts.
I've changed how the process plugin handles strings in the cases there's also default values: it goes with the default values. I also changed an
issetto a!empty()to make the first failing test case pass.I changed the second failing test case because the expectation should be that if a source string gets passed in, that string gets discarded and replaced by default settings if there are defaults settings.
I've also added a case or two, rearranged some cases for clarity, and changed some comments that were no longer accurate in the data provider.
This time I actually expect the tests to pass, FWIW.
Comment #27
danflanagan8Per a suggestion from @benjifisher at the most recent migrate meeting, I'm adding a test case for when the
iddestination property does not exist. That's a new code path my new test cases did not cover.Comment #28
benjifisherI plan to review this issue at DrupalCon Portland.
Comment #29
rachel_norfolktags update
Comment #30
benjifisherIt seems to me that there are two open questions. First, how does this issue affect Drupal 6. Second, should we convert the unit test to a kernel test?
From #8:
The
media_filterfilter is provided by themediamodule, which has only a dev release for Drupal 6. It is migrated by themedia_migrationmodule.I looked at the core
filter_idprocess plugin. The code comments mention Drupal 7 but not Drupal 6.So it looks to me as though this issue potentially affects Drupal 6, but I am not aware of any examples where it does. An example would consist of a Drupal 6 filter that has no settings and is migrated to a filter that does have setitngs.
From #23:
It is certainly odd that we had a unit test in the wrong directory.
My first thought is that I would rather keep this a unit test. I know it is a lot of effort to mock the plugin manager, but that makes the test more self-contained. As a kernel test, we either have to look at the plugin definitions or trust the code comments to see what is being tested. Of course, keeping it a unit test will also make the test run a little faster.
If you agree and switch back to a unit test, then you can remove at least one of the the changes (enabling the test module) added to fix the test. In my opinion, you can move it to the correct directory if you want.
From #25:
That code was in the original patch (Comment #4). The test did not change between Drupal 9.1.x and 9.4.x, so why didn’t it fail in #4?
I have a few suggestions for cleaning up the patch.
Thanks for paying attention to the doc block (and other code comments). But I think the proposed text is confusing. I would use something like “Update settings for migrated filters.” Then, instead of listing the filters that get updated in the doc block, I would have a regular comment at the start of each code block.
Now that we call
getDestinationProperty()three times, is it worth creating a variable for it? Like$destination_id = $row->getDestinationProperty('id').If we keep this as a kernel test, then we should use
$filter_plugin_manager = \Drupal::service('plugin.manager.filter');. This is a contentious issue: see #2066993: Use magic methods to sync container property to \Drupal::getContainer in functional tests.Comment #31
benjifisherComment #34
wim leers#3319582: Fix calls to methods with too many parameters passed in conflicted with this, but fortunately only trivially 👍
This is just a straight reroll, it does not yet address @benjifisher's feedback in #30.
Comment #35
wim leersSorry, misnamed the patch. Too many migration-D10-rerolls at the same time 🫣
Comment #36
smustgrave commented+ * Adds default filter settings; updates D7 core filters' default settings.Think this comment should include why it doesn't apply to D6 right?
Comment #38
ovilla commentedThis is a reroll of #34 for Drupal 10.3
Comment #39
quietone commentedThe Migrate Drupal Module was approved for removal in #3371229: [Policy] Migrate Drupal and Migrate Drupal UI after Drupal 7 EOL.
This is Postponed. The status is set according to two policies. The Remove a core extension and move it to a contributed project and the Extensions approved for removal policies.
The deprecation work is in #3522602: [meta] Tasks to remove Migrate Drupal module and the removal work in #3522602: [meta] Tasks to remove Migrate Drupal module.
Migrate Drupal will not be moved to a contributed project. It will be removed from core after the Drupal 12.x branch is open.
Comment #41
quietone commentedThe Migrate Drupal Module and Migrate Drupal UI are deprecated and they are not in Drupal 12.0.0.
Issues for these modules should now be on the 11.x branch. And the changes are limited to critical and major bug fixes. Other changes are allowed at the discretion of the core Release Managers in consultation with the Migrate subsystem maintainers.