TLDR; if you enable content_translation without enabling migrate_drupal, all migrations are broken because of plugin discovery issues.
#2953360: Experimental migrate_drupal_multilingual module introduced a major (critical?) bug on using the migration system with Drupal 8.6, when having content_translation enabled, but migrate_drupal disabled.
This is because d6_entity_reference_translation.yml and d7_entity_reference_translation.yml were moved to content_translation from migrate_drupal, but they use the Drupal\migrate_drupal\Plugin\migrate\EntityReferenceTranslationDeriver class that is only available if migrate_drupal is enabled.
In this probably very common setup (i.e. any new D8 site using content_translation), attempting to use the migration system will throw the following error:
In DerivativeDiscoveryDecorator.php line 218:
Plugin (d6_entity_reference_translation) deriver "Drupal\migrate_drupal\Plugin\migrate\EntityReferenceTranslationDeriver" does not exist.
Some possible solutions:
1. Move d6_entity_reference_translation.yml and d7_entity_reference_translation.yml back to migrate_drupal - reverts part of the cleanup done in this patch, but is simple to do.
2. Move EntityReferenceTranslationDeriver to content_translation - cleaner solution, but breaks the API, as it would no longer be Drupal\migrate_drupal\Plugin\migrate\EntityReferenceTranslationDeriver and instead Drupal\content_translation\Plugin\migrate\EntityReferenceTranslationDeriver. These migrations are the only references in core to this deriver, and migrate_drupal was an experimental module until now, so maybe we're OK to break the API?
| Comment | File | Size | Author |
|---|---|---|---|
| #27 | 2991710-27.patch | 3.76 KB | maxocub |
| #27 | 2991710-27-test-only.patch | 2.2 KB | maxocub |
Comments
Comment #2
jcnventuraThis patch implements option 2 (move EntityReferenceTranslationDeriver from migrate_drupal to content_translation).
Comment #3
catchThe patch seems OK to me with this small API break (given it's a critical regression due to last minute clean-up in order to mark the module as stable), but could do with a second or third opinion.
Comment #4
heddnWe still want to leave the old copy in MD and trigger_error on it and point to the new one here. We discussed this at great length in the migrate maintainers meeting today (phenaproxima, heddn, masipila, maxocub) and thought that would work. It isn't the cleanest, but perhaps its a way forward.
Comment #5
heddnBack to NW for the attempt at leaving a copy in MD and trigger_error on the BC nature of things.
Comment #6
jcnventuraLeft a copy in MD, and added the trigger_error.
This seems to be the only option, as the tests for option 1 (back in the parent issue) didn't pass.
Comment #7
heddnThis should @see a change record, not a previous issue. Let's add a new one for this. https://www.drupal.org/list-changes/drupal
Comment #8
jcnventuraChange record added and published (#2991774: \Drupal\migrate_drupal\Plugin\migrate\EntityReferenceTranslationDeriver deprecated in favor of \Drupal\content_translation\Plugin\migrate\EntityReferenceTranslationDeriver).
This patch updates the nid.
Comment #9
phenaproximaThanks, @jcnventura! I've unpublished the change record, though -- committers publish them when they land the patch :)
Comment #10
heddnI think all is in order here now.
Comment #11
maxocub commentedReal nitty, but it should be '@see' with an empty line above. See https://www.drupal.org/core/deprecation#how-class
Comment #12
jcnventuraUnfortunately, it isn't..
I just tested the patch in a fresh install and found another couple classes that needs to be deprecated and moved to content_translation. I guess the PHP cache was letting me get away with it before for some weird reason:
These are required by the deriver that needs the content_entity plugin.
We should move also the \Drupal\Tests\migrate_drupal\Kernel\Plugin\migrate\source\ContentEntityTest that tests this plugin, and which does not need to be deprecated as it is a test class.
Moving those 3 files, the migration system is able to survive all the cache rebuilds I throw at it...
However, it seems to me that moving all of migrate_drupal into content_translation is not the solution here.. As per #8, the system can now find the deriver.. Perhaps we can somehow make sure that the deriver only works if migrate_drupal is enabled? It honestly makes no sense that now the deriver is listing several d6_entity_reference_translation:node__* and d7_entity_reference_translation:node__* entries on drush ms.
Comment #13
jcnventuraI ended up using MigrationDeriverTrait and checking if the content_entity plugin exists..
Seems to be more robust than hardcoding a module name. The trouble is really if that plugin exists or not, so that’s what I tested for.
This way those non-translation classes do not have to be moved, and the deriver doesn't activate if migrate_drupal is not enabled, as that's the module where the 'content_entity' plugin is still located.
Comment #14
phenaproximaAnother possible approach, which might solve the problem in a more holistic way: why don't we just change the discovery mechanism of the migration plugin manager?
Normally, the plugin system will throw an exception if the deriver doesn't exist -- see \Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator::getDeriverClass() -- but we could easily make the migration plugin manager use a derivative decorator which, if it can't find the deriver class, simply logs an error somewhere and skips that plugin definition (and all of its derivatives).
Framework managers should probably confirm my understanding here, but I don't think this would constitute an API break because the actual deriver discovery mechanisms we use are internal to the plugin manager. As long as we provided some way for developers to know *why* their migration was not discovered (i.e., by logging the error), this might be a very elegant solution indeed, one which works the way the plugin system wants to work, and doesn't require us to duplicate a single line of code.
Comment #16
effulgentsia commentedMigrationPluginManager::getDiscovery()already invokesProviderFilterDecorator. Doesn't that mean that we could solve this by simply adding:to the
*_entity_reference_translation.ymlfiles?Comment #17
effulgentsia commentedOr if the module that it's in needs to be explicitly added too, then:
?
Comment #18
jcnventura@effulgentsia, applying #16did get rid of the error. I wonder if the tests pass. No interdiff as this is a completely different approach.
Comment #20
jcnventuraProper patch file now.
Comment #21
heddnI think that @effulgentsia is right and we should list both content_translation and migrate_drupal as both need to be enabled.
That said, do we need to log an error for this specific scenario or just silently discard these?
Lastly, still needs tests. Going to try working on this for the next few minutes.
Comment #22
heddnI'm obviously doing something wrong here. This will fail, but it doesn't seem to fail at the right point. At least on local. Going to upload for now and hopefully someone else can move this further along.
Comment #23
maxocub commentedYour $definitions array is always empty because, apparently, all migration plugins provided by core should depend on migrate_drupal. I found this by reading this test
Drupal\Tests\migrate\Kernel\Plugin\MigrationPluginListTest:So why does d6_entity_reference_translation do not already depends on migrate_drupal?
Comment #24
maxocub commentedAlso, the
EntityReferenceTranslationDeriverwill not derive any migrations unless there is some entity reference fields targeting nodes on the Drupal 8 (destination) site.Comment #26
quietone commentedSome special about the empty source plugin?
Comment #27
maxocub commented@quietone: Thanks! That's the reason why those migrations do not depend on migrate_drupal. Do you think adding the provider key to the yaml is a good solution or should we avoid using the empty source plugin?
@heddn: Sorry, I dropped your test and used
Drupal\Tests\migrate\Kernel\Plugin\MigrationPluginListTestinstead.Here's a failing patch. No interdiff since this is a small patch and the interdiff would be bigger than the patch.
Comment #28
quietone commented@maxocub, your welcome. I'm very glad it helped. I had been thinking about the problem and reading your comment made me think about requirements. Good team effort.
I think the provider idea is the way to go. However, what we discovered here needs to be documented. I'm thinking in the migrations yml files and in MigationWithFollowUpInterface just after the explanation of the tags. Right now, I even think there could a sub section on the design on the migration yml but I don't know enough of the doc standards.
I'm anxious to see the test results.
Comment #30
quietone commentedLet's do an assertArrayNotHasKey before migrate_drupal is enabled.Nevermind, there is an assertion later to confirm that getDefinitions returns an empty array.The test file has this comment at line 78. I think this would be a good time to add why that migration does not depend on migrate_drupal, especially in light of #23.
Comment #31
jcnventura@maxocub and @quietone: looks way better. Thanks for getting to the bottom of why these migrations did not depend on migrate_drupal, now that they were moved out. I trust this will go in shortly.
We can probably delete the CR node (https://www.drupal.org/node/2991774), now that we're no longer deprecating the deriver in migrate_node.
Even though to be honest, it should be moved to content_translation. Maybe the best solution in OO terms would be to change the migrations as in #27, while doing the move as per #8.
Comment #32
heddnThis is not a true statement.
Can we explicitly test the array does not contain these when MD is disabled?
Comment #33
maxocub commentedComment #34
heddnI take back my comments in #32. That is a true statement and we do have test coverage. Onward to RTBC?
BTW, I re-added a CR to discuss the very specific details of the changes in the parent issue. It probably isn't strictly needed, but we do have a couple pre releases of 8.6 and it would be good to document these things for the poor souls that hit this issue.
Comment #35
jcnventuraRTBC++
I've been using #27 in development and staging. It does the job.
Comment #36
alexpottCommitted and pushed 9273076d01 to 8.7.x and 596caa3e51 to 8.6.x. Thanks!
Comment #40
quietone commentedPublish change record.