Problem/Motivation
Drupal\content_translation\Plugin\migrate\source\I18nQueryTrait is also used in multiple migrate source plugins of other modules (e.g. Drupal\block_content\Plugin\migrate\source\d7\BlockCustomTranslation). This may make sense as translations usually require to have content_translation enabled. However it prevents e.g. the type checking of such plugins without instantiating them, as done in https://www.drupal.org/project/entity_import, Drupal\entity_import\EntityImportSourceManager::getDefinitions().
Having the trait in the content_translation module also creates problems in #3421014: Convert MigrateSource plugin discovery to attributes.
Steps to reproduce
- Install Drupal with the Standard profile. Make sure the
content_translationmodule is not enabled. - Install the
migrate_drupalmodule. - Enable a module with the stub version of the
d7_block_custom_translationmigration (see below). - Using
drush php, instantiate the migration and its source plugin.
Here is the stub migration:
id: d7_custom_block_translation
label: Content block translations
migration_tags:
- Drupal 7
- Content
source:
plugin: d7_block_custom_translation
process: {}
destination:
plugin: entity:block_content
migration_dependencies: {}
Here is a session with drush php, showing the error with the 11.x branch:
> \Drupal::service('plugin.manager.migration')->createInstance('d7_custom_block_translation')->getSourcePlugin();
PHP Fatal error: Trait "Drupal\content_translation\Plugin\migrate\source\I18nQueryTrait" not found in /var/www/html/core/modules/block_content/src/Plugin/migrate/source/d7/BlockCustomTranslation.php on line 22
Proposed resolution
I18nQueryTrait is used for source plugins that require migrate_drupal. So, move it to migrate_drupal. This is on MR 11081
User interface changes
None.
API changes
None.
Data model changes
None.
| Comment | File | Size | Author |
|---|
Issue fork drupal-3258581
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:
- 3258581-to-migrate-drupal
changes, plain diff MR !7616
- 3258581-move-contenttranslation-i18nquerytrait
changes, plain diff MR !1651
- 3258581-with-kernel-test
changes, plain diff MR !11081
- 3258581-move-trait-only
changes, plain diff MR !10426
- 3258581-tests-only
changes, plain diff MR !10779
Comments
Comment #2
boromino commentedComment #4
boromino commentedComment #5
boromino commentedComment #6
merlin06 commentedPatch applies against 9.3.3
Comment #7
merlin06 commentedSorry, I didn't intend to change the version number.
Comment #8
quietone commentedI tested this on 9.4.x, standard install and was not able to reproduce this error. I followed the steps given in the Issue Summary. Is there something else that needs to be done? Changing status to get more information.
The migrate maintainers work from the 'migration system' component, changing component.
This isn't a feature request and although I can't reproduce the problem, changing to a bug report.
Comment #9
sanduhrsJust ran into the exact same issue while trying to install entity_import module.
The 'Add entity importer' just gives a WSOD.
Comment #10
quietone commented@sanduhrs, thanks for reporting the problem.
I am still not able to reproduce the problem using the steps in the Issue Summary.
Doing more research I see that In the related issue the explanation for the problem is given and so is the workaround. I suggest using that method.
The i18nQuery trait is only needed for migrating a drupal database and thus will not be moving to the migrate module. What could be done in core is add checkRequirements to the source plugins using the trait to ensure that content_translation is enabled. Assigning this to myself to consider that later.
Comment #11
boromino commentedSorry for the confusion, migrate_drupal module has to be installed, too. I edited the issue description accordingly.
@quietone I see your point regarding migrate module.
Would you consider to add the trait to the migrate_drupal module, instead? Then I would provide a patch for that.As entity_import does not require migrate_drupal, another work-around makes probably more sense.Comment #15
quietone commentedI think this will be fixed by #3332998: Move migration code from content_translation to migrate_drupal
Comment #17
quietone commentedAdded a way to move this to migrate drupal.
This problem is about the source plugins, not migrations so I think we can just move the affected source plugins. I have not done the needed deprecations. I wanted to make sure there were no test failures.
Comment #18
smustgrave commentedNice no test failures. Moving to NW for deprecations mentioned in #17
Comment #20
godotislateThis is a blocker for #3421014: Convert MigrateSource plugin discovery to attributes, because instantiating reflection on classes that use I18nQueryTrait when content_translation is uninstalled causes a fatal error.
Comment #21
quietone commented@godotislate, I see you are working on this issue. It is currently assigned to me and I have been working on it locally for a while. :-(
Comment #22
godotislate@quietone I completely missed the assignee. Many apologies.
Comment #23
quietone commentedI've updated the title and unassigned.
Comment #24
quietone commentedThank you.
Comment #25
godotislateI have added deprecations to the moved classes and traits. Do deprecations still need tests? Or is phpstan covering that now?
And again, I apologize to @quietone for missing that you already were working on this and I didn't notice.
Comment #26
quietone commented@godotislate, no worries. It is just unfortunate that we both were doing the same thing. I think you got there first because I took a break to eat.
Comment #27
godotislateUpdated per MR feedback.
Note that moving the MenuLinkTranslation classes to migrate_drupal means they now extend MenuLink from menu_link_content, but this is an improvement in that extending an unknown class throws an exception and does not fatal.
Comment #28
andypostMaybe it will be less disruptive to move file and provide alias via composer autoloader?
Comment #29
mikelutzI'm not certain that we can do anything here, but we definitely can't do this. All of these sources being moved are scheduled to be deprecated and removed completely by d12 along with the migrate_drupal module, so we can't set a deprecation message telling people to use the migrate_drupal versions before d12 because those aren't going to exist anymore. I think at best we could introduce a copy of the trait to migrate_drupal and switch the sources over to it without doing any deprecation notices about moving things, and I'm not sure we should bother doing that at this point either.
Comment #31
godotislateAfter conversation with @benjifisher on Slack, I investigated the feasibility of moving just the Trait, without the plugin classes that depend on it, in context of #3421014: Convert MigrateSource plugin discovery to attributes, without running into a fatal error.
It turns out that since the plugins extend DrupalSqlBase, an exception is thrown, which avoid the fatal.
Created MR MR 10426 that copies the trait to migrate_drupal, with the original trait in content_translation using it.
Per #29, left off the deprecation messages.
Comment #33
godotislateComment #34
benjifisherI think you missed
core/modules/menu_link_content/src/Plugin/migrate/source/d7/MenuLinkTranslation.php, so NW for that.Can we really make the existing trait a wrapper for the new trait in the
migrate_drupalmodule and not add any deprecation notice? Maybe we can, but it feels too easy. I guess the idea is that when we deprecate the new trait, that will automatically deprecate the existing one (the wrapper), and we have to do that before the next major version (D12).The existing steps to reproduce (STR) involve a contrib module. That has two problems:
I know, I can add the issue fork for the D11 compatibility issue as a package repository and install the contrib module that way, or I could use the lenient composer plugin. I said it is complicated, not impossible. ;)
We can solve both problems if we give different STR. Using
drush php,Before running that code, I installed Drupal with the
standardprofile, enabledmigrate_drupaland a custom module with a simplified version ofd7_custom_block_translation:The original version of
d7_custom_block_translationis in thecontent_translationmodule.Can we turn these STR into an automated test? I think so. I am adding the tag for tests.
We should update the issue summary with the improved STR. I can do that, but not now. I need some sleep. For now, another tag.
When I check out the feature branch from the MR, it fixes my manual test:
It would be nice to get some manual testing of the original report: does the current MR fix the problem with the contrib
entity_importmodule? Or does that require moving a lot more into themigrate_drupalmodule?Comment #35
godotislateThanks for catching that. Rebased the MR and added the change.
Not sure what the appropriate deprecation message, given #29 and whatever is going to happen to
migrate_drupal, but I think I agree with the idea that the deprecation message should be set when migrate drupal moves out of core.Unfortunately, this is more difficult than you might think, because all classes are autoloaded when tests run. So the trait would never be missing, unless it just doesn't exist at all.
I did run the steps to reproduce with the Entity Import module. I had to
I was able to install entity_import against 11.x and this MR's branch. Confirmed that the fatal error was reproduced on 11.x and gone after the trait was moved.
Moving back to Needs Review. Leaving at needs tests in case there is another idea of how to test this proposed.
Comment #36
quietone commentedI added a Functional test that shows the error locally. But when I run the test-only changes it doesn't fail as expected. Gotta run.
Comment #37
bbralaAs it needs test, and IS needs updating and the added test doesn't fail on test only right now this is still needs work.
Comment #38
quietone commentedTo figure this out I would like to see the browser output from the test. However, the artifacts for the test-only changes test run does not include the browser output. Is this by design? Is there something that can be changed in the template so the browser output is saved?
To get the browser output I made an MR with just the test changes. And looking at all the pages of output hasn't given me an idea as to why the fail test passes in gitlab but fails locally.
Comment #39
larowlanComment #40
nikolay shapovalov commented@quitone I check test case you create at your MR, and left my feedback there.
Short summary between difference running I18nQueryTraitTest On Gitlab CI and localhost:
Comment #41
nikolay shapovalov commentedFound solution for checking fatal error at Drupal\FunctionalTests\Bootstrap\UncaughtExceptionTest.
Update test only MR 10779, and rebased and cherry picked changes to MR 10426.
Comment #42
nikolay shapovalov commentedTest is ready. Set status to NR.
Tests only MR 10779.
MR to review MR 10426
Comment #43
benjifisherThe test migration can be simpler, and the assertion messages (when the test fails) can give more information: see my comments on the MR. Back to NW for that.
The issue summary still needs an update. I offered to do that in Comment #34. I will try to find time tomorrow.
Comment #45
nikolay shapovalov commentedApplied changes suggested by @benjifisher.
Create new draft MR with tests only, to display error message.
MR is ready for review, but IS still need to be update, keep status to NW.
Can someone help with updating IS?
Comment #47
benjifisher@nikolay shapovalov:
Thanks for those updates. +1 for adding the helper method instead of suppressing the warning with
@file(...).GitLab CI has a test-only job. (It is not run automatically. You have to trigger it when you want it.) We do not need a test-only branch, so I am hiding the one you added.
I ran the test-only job: https://git.drupalcode.org/issue/drupal-3258581/-/jobs/3880198
I was not sure whether the optional message in an assertion method is supposed to be the expected result or the error condition, but that output looks right, so I think you made the right choice: "Fatal error during migrate."
I am satisfied with the code review, and the tests are green. If I can get the issue summary updated, then I will call this issue RTBC.
Comment #48
benjifisherIn Comment #34, I added the "Needs issue summary update" tag. I asked for STR that do not involve a contrib module. I have rewritten that part of the issue summary, so I am removing the tag.
Looking again at my previous comment, I think we do not need the custom message " Fatal error during migrate" at all. The detail I requested is in the default message:
So I will add one more suggestion to the MR but I will still mark this issue RTBC. (The only reason it was NW instead of NR was for the issue summary update.)
Comment #49
nikolay shapovalov commented@benjifisher thanks a lot for great review and your changes to IS. I applied suggested change to second assert and update fork to latest 11.x.
Thanks for sharing information about test-only job, didn't know.
Comment #50
quietone commentedComment #51
godotislateAddressed latest MR comments.
Comment #52
benjifisherI reviewed the latest changes, and I think all the requested changes have been made.
Really minor point (not enough to hold up this issue, in my opinion): I would have changed (shortened) the namespace of the test class instead of moving it (and creating two nested directories with no other contents).
I do not care much either way, but perhaps we should leave the trait in the
content_translationmodule intact (but still deprecate it) instead of making it a wrapper for the new version of the trait. The only reason for doing that is so that we can add type declarations to the new code. This is the current approach in #3498915: Move content_entity source plugin to migrate module.There is one remaining question, from @quietone:
It was hard to get a suitable test for this issue: I am still not sure why my STR do not generate an error in a test. @quietone created the first version of the current test, as a Functional test using
migrate_drupal_ui. (See Comments #36, #38.)Ideally, we should be able to write the test without using
migrate_drupal_ui, but it does not look easy. There is a lot of logic inCredentialForm::validateForm()and in other methods in that form class, such assetupMigrations().The test shows us that the man code is not well structured, but fixing that is out of scope for this issue and probably not worth the effort since
migrate_drupalis going away "soon". This issue is holding up #3421014: Convert MigrateSource plugin discovery to attributes and related issues, so I vote for leaving the test as is.I re-reviewed the changes in the MR: back to RTBC.
Comment #53
nikolay shapovalov commentedI spend some time trying to generate error without Migrate UI, but have no luck. I agree with @benjifisher to keep test as is.
Comment #55
catchI think this would be a good idea. We're still finalising how to add type hints to existing code in-place, so it would save at least two further issues if we were to do this now, based on the current plan for doing that (one to indicate we're going to add the type hints and another to actually add the type hints). Don't want to hold this issue up, but if someone has time to do it, it would save more time later I think.
#3498915: Move content_entity source plugin to migrate module is also RTBC but I haven't reviewed it yet, so I will try to look over there.
Comment #56
godotislateMade the changes per #55. Does it need to go back to NR?
Comment #57
benjifisherYes, the issue should go back to NR. I will review it soon, unless someone else does it first.
I think we made the same decision on #3498915: Move content_entity source plugin to migrate module: keep the existing class intact and add type declarations to the new one. That issue seems to have merge conflicts, and I think I have time to handle that now.
Comment #58
benjifisherI reviewed the changes. There is just one problem: we should add parameter type declarations as well as a return-type declaration. Back to NW for that.
On the plus side, I see that the earlier version of the MR only did part of the recommended deprecation. (It added
@trigger_error()below thenamespaceline, but it did not add@deprecatedand@see link-to-crto the doc block). The current version fixes that: thanks.Reference: https://www.drupal.org/about/core/policies/core-change-policies/how-to-d...
I also updated the change record (CR). It still targeted 10.3.x, and I updated that to 11.2.x. It said that several classes that use the trait were also being moved to
migrate_drupal, which was the plan before Comment #31. I removed that section of the CR.Comment #59
godotislateCan't believe I missed the parameter typehints, but everything should be addressed now.
Comment #60
benjifisherThe last few commits address the suggestion in Comment #55. Back to RTBC.
Comment #62
godotislateI took inspiration from #3502913: Add a fallback classloader that can handle missing traits for attribute discovery and took a look at seeing whether it's possible to set the class loader not to load namespaces for uninstalled modules in a test method. I did this in MR 11081 and was able to create a failing Kernel test. Setting back to NR, since it'll be much faster to use a Kernel test instead of a Functional test.
Comment #63
benjifisher@godotislate:
Good find! Yes, a kernel test is much better.
On the principle that no good deed goes unpunished, I made several suggestions for changes on the MR.
We do not need both MRs. Either cherry-pick the last two commits from MR 10246 to MR 11081 or else cherry-pick the last commit in the other direction. (Or make one commit on MR 10246, incorporating my feedback.)
Maybe use a data provider so that the test-only job fails on all 5 source plugins instead of getting a fatal error on just the first one.
Finally, I think we may want to reuse the first part of the test (the part that breaks discovery for uninstalled modules). Eventually, we should move it to a trait, but I think it is premature to do that now, so let's start by making it a separate method in the test class. It should have at least one argument: a list (array) of module names to update.
I am not sure: for this test, is it better to break class discovery for all uninstalled modules or just for
content_moderation? I am leaning toward the second option. That would also save a few lines of code.If you prefer the first option, then the new method should default to acting on all uninstalled modules. And it should have a required first argument: a list of module names that can be asserted to be on the other list: something like
disablePsr4(array $expected, ?array $disabled = NULL): void. Maybe use longer, more descriptive, parameter names.Comment #66
godotislateI created new MR 11081 in case the old test was preferred, but I forgot that the last two commits on MR 10426 weren't on my local.
Anyway, I've closed MR 10426 and decided to go ahead with 11081 so that the last commit diff specifically addresses the MR feedback. I've also rebased to include the two missing commits.
Back to NR.
Comment #67
benjifisherWe now have a version that addresses the request in #55 and also replaces the Functional test with a Kernel test. Back to RTBC.
Comment #69
catchJust re-read @mikelutz comment and sort of agree but also think where we ended up is fine. For modules integrating with migrate_drupal now, we should tell them the class is moved, this can help with dependency issues in contrib etc. Then when we deprecate migrate_drupal as a whole, they'll get different deprecation message again, but sometimes this is what happens.
Comment #71
benjifisherI published the change record, and I am about to un-postpone #3421014: Convert MigrateSource plugin discovery to attributes.