Problem/Motivation
Some of Migrate’s cckfield plugin's method naming are not describing clear enough what they do and therefore may confuse developers using the API (therefore giving poor DX).
Proposed resolution
- Rename processFieldValues() to defineValueProcessPipeline()
- Rename processField() to alterFieldMigration()/li>
- Rename processFieldInstance() to alterFieldInstanceMigration()
- Rename processFieldWidget() to alterFieldWidgetMigration()
- Rename processFieldFormatter() to alterFieldFormatterMigration()
- Update tests
- Add BC layer
Remaining tasks
Review
Commit
User interface changes
None.
API changes
Yes.
processCckFieldValues()will be deprecatedThis wad deprecated in #2683435: CCK does not exist in Drupal 7, rename Migrate's cckfield plugins to field pluginsprocessFieldValues()will be deprecatedprocessField()will be deprecatedprocessFieldInstance()will be deprecatedprocessFieldWidget()will be deprecatedprocessFieldFormatter()will be deprecated
Data model changes
None.
Original report
Those who know me know that I’m fairly fanatical about good DX in core APIs (or, indeed, any APIs). Because of that, certain aspects of Migrate’s cckfield plugins have been bugging me for a long time.
I have three main bones to pick:
- processField() is poorly named. Its actual purpose is altering the migrations that transform CCK fields (in D6) and Field API field definitions (in D7) into D8 field_storage_config entities. This should be renamed to processFieldMigration() or alterFieldMigration().
- processFieldInstance() has the same problem. It should be called processFieldInstanceMigration() or alterFieldInstanceMigration().
- processCckFieldValues() is on another planet entirely. Its purpose is to define the processing pipeline for values of the field type that the plugin handles, but this does not come through at all in the method name. I think this should be called something like defineFieldValueProcess() or defineValueProcessPipline().
The doc blocks for each of these methods in MigrateCckFieldInterface need to be improved as well. These plugins are crucial for contrib migrations from D6 and D7, so the interface should include short snippets of example code in the doc comments.
| Comment | File | Size | Author |
|---|---|---|---|
| #134 | 2631698-134.patch | 5.5 KB | phenaproxima |
| #132 | 2631698-132.patch | 5.51 KB | phenaproxima |
| #131 | 2631698-131.patch | 7.04 KB | phenaproxima |
| #121 | 2631698-121.patch | 1.49 KB | heddn |
Comments
Comment #2
phenaproximaComment #3
benjy commentedYeah I think we can do better here as well, I think the process in processField initially came about because we are updating the "process" array for the field.
Anyway, I like the alter* method suggestions in the summary, I think alter is a better word since we're altering the migration not the actual data.
Comment #5
quietone commentedComment #6
mikeryanComment #7
mikeryanAs with #2683435: CCK does not exist in Drupal 7, rename Migrate's cckfield plugins to field plugins, renaming stuff would disrupt the patch for #2631736: Cckfield Plugins must distinguish core versions, which is both more important and close to RTBC - let's postpone considering this until that is in.
Comment #8
mikeryanUnblocked.
Comment #9
phenaproximaPostponing on #2683435: CCK does not exist in Drupal 7, rename Migrate's cckfield plugins to field plugins to avoid reroll hell.
Comment #11
mikeryanIf I'm not mistaken, these would all be simple renames and easily covered by a BC layer passing through to the new names, so not really a BC break.
Comment #12
phenaproximaUnblocked!
Comment #13
mikeryanRename patch was reverted.
Comment #14
heddnComment #15
heddnThis can be done with a BC shim layer, so removing the BC break tag.
Comment #16
imiksuChanges:
, if doesn't land to 8.2.x (right?)What needs more information
if it doesn't land to 8.2.x?EDIT: Whoops completely forgot 8.2 was released, lol :)
Comment #17
imiksuAdded tasks to wait until #2683435: CCK does not exist in Drupal 7, rename Migrate's cckfield plugins to field plugins gets fixed
Comment #18
imiksuComment #20
jofitzNo longer blocked.
Comment #21
quietone commentedWhat about proccessFieldWidget() and processFieldFormatter()?
Comment #23
jofitzWIP. Before I go too far can someone confirm that I am doing the right thing, please?
So far I have:
Comment #24
heddnI liked defineValueProcessPipline from the IS better.
Comment #25
jofitzChanged defineFieldValueProcess() to defineValueProcessPipeline(). Otherwise am I on the right track? Shall I do similar for processField() and processFieldInstance()? What about proccessFieldWidget() and processFieldFormatter()?
Comment #26
quietone commentedYea, I think this is the right track.
I too was wondering about that. Both are doing a
$migration->mergeProcessOfProperty('options/type', $process);so they seem like a good candidate for renaming, by replacing process with alter. It makes sense to me, at least.Comment #27
phenaproximaI agree. Let's do this. How about names like alterFieldInstanceMigration()?
Comment #28
jofitzUpdated IS.
Renamed instances of:
Comment #29
heddnThe BC layer still needs tests.
Comment #30
jofitzRetained previous tests for BC.
While making the changes I noticed that:
modules/text/tests/src/Unit/Plugin/migrate/field/d6/TextFieldTest.php
and
modules/text/tests/src/Unit/Migrate/d6/TextFieldTest.php
are almost identical. Is there any need for both? I realise that is not within the scope of this issue, but is it worth creating a new issue to remove one or the other?
Comment #31
quietone commentedThe issue of the 'duplicate' test files d6/TextFieldTest.php seems to apply to the d7 versions as well. And it looks like I separated the test into two versions in #2833206: Convert Migrate's cckfield plugins to use the new field plugins in #70
Seems like a separate issue to me, but it is late and I should be asleep...
Comment #32
heddnWe could also update the IS with the proposed renames? That would make this easier to review.
Comment #33
jofitz@heddn the proposed renames are in the "Remaining tasks" section.
Comment #34
quietone commentedUpdated the IS.
Comment #35
quietone commentedUpdate the remaining tasks.
Comment #37
heddnI think this is pretty close. But let's re-roll it again first.
Comment #38
jofitzRe-roll.
Comment #40
heddnLooks like a rename of iterator => sub_process is in order here. Tagging Novice.
Comment #41
robpowellI am working on this as part of SprintWeekend2018.
Comment #42
phenaproximaComment #43
robpowellComment #44
robpowellComment #45
robpowellhere's the interdiff
Comment #46
robpowellComment #47
phenaproximaLooks great. Thank you, @robpowell!
Unfortunately, I think this still needs some work, mostly to bring it in line with the core deprecation policy.
As per the deprecation policy, let's always add a @trigger_error() call before calling defineValueProcessPipeline() from processFieldValues().
This won't work, because the test method will exit as soon as defineValueProcessPipeline() throws its expected exception. I think we will have to copy this entire test method, and in the copy we'll call processFieldValues(). Those cloned methods should also mention in their doc comment that they are testing backwards compatibility and should be removed.
We also need to do the proper @trigger_error() thing here too.
Comment #48
robpowellSpoke to @phenaproxima, processFieldValues() is being inherited by FieldPluginBase.php. We can make the change recommended in #47.1 in FieldPluginBase::processFieldValues() and remove the child class declarations of processFieldValues().
Comment #49
robpowellWent ahead and followed the same cleanup for four depracated methods, here's the total list:
#47.2 This was the case in field/fieldDateTest.php and d6/fieldDateTest.php. To complete the requirements of the deprecation policy,
#47.3 done
Comment #50
robpowellComment #51
phenaproximaI've taken the fine work @robpowell did and tweaked it a bit.
The main thing here is that, rather than repeat entire test methods just to call a single deprecated method, I've created separate test classes to exercise the deprecated methods and assert that the proper deprecation errors are raised.
No interdiff because the changes are complex enough that it will be easier to parse this cleanly.
Comment #54
phenaproximaLet's try that again.
Comment #55
phenaproximaAlso removing the Novice tag, because I no longer think it applies.
Comment #57
robpowell`processCckFieldValues` does not return expectedDepraction removing it passes tests locally.
Comment #58
robpowellComment #59
heddnLots of changes are in place. Tests are passing.
FieldPluginBasehas deprecation triggers in place, so we can be pretty sure we caught all re-names. If we didn't, then we can grab them in follow-ups. I'm good with RTBC, as I don't see any issues in here.Comment #60
alexpottWe need a change record here and all the deprecation notices should be pointing to it as per https://www.drupal.org/core/deprecation
I'm not 100% convinced we should be removing stuff from the interface. However of course things are still implemented by the base classes that everyone would extend so that's good. Love the deprecation work and testing - really good to have all the testing still in place. However I think that there might be a problem. For example, Example module has a migrate field plugin that implements \Drupal\migrate_drupal\Plugin\MigrateFieldInterface::processFieldValues how would it ever be called by node derivers?
Comment #61
robpowellI'll take care of this tonight
#60 .1
Comment #62
robpowellComment #63
robpowellAlright, should be all set now.
Comment #64
robpowellComment #65
robpowellIf someone could also review the change record, that would be great #2944598: Update method names to be more meaningful in MigrateFieldInterface
Comment #67
heddnLooks like this is just updating the tests to account for the link to the change record. Or am I wrong? Tagging novice for that. And removing the CR tag as we already seem to have a CR.
Comment #68
heddnUnassigning since this seems like anyone could pick up the novice tasks.
Comment #69
robpowell@heddn, I can fix the failed errors if someone will weigh in on the syntax change of the error message. I believe when I picked this up the error message was :
per the example on https://www.drupal.org/core/deprecation, I saw that the versions ended in .0 so I went ahead and updated that without being 100% clear if that was the right step forward. Here is an example of what an error message looks like now (with the change record link):
See how the versions changed from 8.5.x to 8.6.0 and 9.0.x to 9.0.0, is that OK?
Comment #70
heddnChanging the version is correct. Because 8.5.0 was already released. And API changes to interfaces should occur in minor releases. Not point releases within a minor.
Comment #71
robpowellI removed the changes to file d7/ImageField.php because issue 2934145 changed this file and it looks like the change in this ticket is no longer needed:
Comment #72
robpowellComment #74
robpowellThis should fix the file.file and text.text failures. I ended up removing the changes introduced by this patch to ImageFieldTest.php because of the changes in issue 2934145
Comment #75
robpowellComment #76
robpowellComment #78
jofitzI'm worried that this is beginning to wander away from the point. Here's my take on it, based on the patch in #63, but also with an interdiff against #74.
Comment #80
jofitzAdd @expectedDeprecation to fix final test failure.
Comment #82
jofitzNearly there...
Comment #83
robpowell@Jo Fitzgerald thanks for picking this up, I too was concerned that I was removing too much. The multiple interdiffs really helped me review the changes you made vs my changes.
If possible, can you summarize in laymen terms what your patches do? I hit a lot of problems trying to wrap my head around the changes to d7/ImageFieldTest.php due to the other issue and how I should implement this patch on top of it. Can you speak to how you knew what to do here?
Comment #84
heddnThis seems strange. All the rest of the deprecations are about 8.6. What's this about?
I also reviewed the CR. It looks pretty nice. Almost there, only the question here before RTBC.
Comment #85
jofitz@heddn I'm not convinced it is relevant to this patch, it covers the
@trigger_error()in Drupal\datetime\Plugin\migrate\field\d6\DateField. Shall I remove it?Comment #86
heddnRemove it, but if we need that test coverage, we should open a follow-up.
Comment #87
jofitzRemoved out of scope test. Added follow-up to add the removed test: #2960056: Add deprecation test to d6/DateField
Comment #88
heddnThat was my only concern. So onto RTBC. We've got a CR, we've got docs and tests and deprecation notices and @see links to the CR.
Comment #90
yogeshmpawarComment #91
yogeshmpawar#87 failed to apply on 8.6.x branch, so i have rerolled the patch.
Comment #92
heddnDiff stats are the same. Back to RTBC.
Comment #93
heddnDiscussed in the migrate maintainers meeting today with alexpott, phenaproxima, heddn, maxocub, quieone. In summary, we all think the BC test layer is good. The consensus though it we don't want to do another CCK => field plugin rename here and cause a lot of heartache for folks. On the flip-side, the current method names are so dense and obtuse, there is much less adoption (outside of core fields) than we'd like to see. Contrib isn't using field plugins that much. And custom migrations have even less adoption. By renaming, we can actually provide some good tutorials and docs that are intuitive. And hopefully make it much easier for folks to use these things.
Still leaving in RTBC while we think about it.
Comment #95
jofitzRe-roll.
Comment #96
heddnDiff stats identical. Back to RTBC.
Comment #97
quietone commentedWorking with fields will be less confusing when we can use these descriptive method names. No more having to take a extra time to recall what the 'process' really does, the method name will tell you!
Comment #99
phenaproximaBecause this is an API addition, we should try to land it for 8.6.0. There's no reason we can't go back to RTBC here once Drupal CI passes, which I expect it will.
Although I also don't want to go through another "let's rename the things" nightmare either, I think this has pretty decent explicit test coverage, in that we're executing and confirming all the deprecations. I feel like we've meditated on this one long enough, and with the 8.6.0 alpha deadline approaching, it's decision time. Seeing as how this is a major DX win -- the method names we are deprecating would never have landed in core to begin with if they were being introduced in this patch -- I think the benefits outweigh the risks. So, as one of the subsystem maintainers, I vote we go ahead here.
Comment #100
heddnFor all the same reasons #99, +1 from me.
Comment #102
phenaproximaI think we need a reroll here to account for recently-committed changes.
Comment #103
jofitzComment #104
phenaproximaThanks! RTBC on the assumption that all backends will pass tests.
Comment #106
phenaproximaWat? Methinks that is a testbot hiccup.
Comment #108
catchI was also iffy on removing things from the interface here, but given migrate_drupal isn't stable yet, I think I agree with @alexpott's #60 "However of course things are still implemented by the base classes that everyone would extend so that's good." Just noting this here so it's clear what the decision was if it comes back to bite us.
The only people who could get in trouble would be people calling the classes implementing the interface directly, but in this case we don't expect people to do that, we expect most people to implement it, or just use the classes indirectly via the migrate system. And for people implementing the interfaces, having the deprecated methods isn't helpful at all.
So. Committed 14a769b and pushed to 8.6.x. Thanks!
Comment #109
neclimdulThe tests added here broke phpunit.
Comment #110
quietone commented@neclimdul, I can't reproduce those errors, those tests pass for me locally.
Comment #111
neclimdulEasy enough to reproduce. Try this:
Comment #112
heddnI cannot reproduce either.
Comment #113
neclimdultry
./vendor/bin/phpunit -c core/phpunit.xml.dist --testsuite unitas noted in #111Comment #114
quietone commentedUsing the steps in #11 I got two failures.
The tests pass when specifying the configuration file, that is, the following resulted in passing tests.
Two questions. One, what is the difference between running the test individually and running a whole testsuit? Two, why didn't testbot report an error?
Comment #115
neclimdulSure, good questions. Because of the legacy of Drupal 5 and 6
stupidnessstate complexity, testbot/run-tests.sh runs every test in its own process. For unit tests, phpunit runs in a single process because it is orders of magnitude faster and by definition those tests are supposed to be non deterministic/stateful (We change this behavior for kernel and web tests). Running tests individually obviously runs only that test and so in its own process.Ideally we shouldn't test auto-loading because load order isn't explicit and is a sort of state we can't control. In reality our deprecation procedure needs tests and tests exactly that. When testing code inclusion(autoloading) like this, the tests must run in their own process. How to do that is documented here:
https://phpunit.de/manual/6.5/en/appendixes.annotations.html#appendixes....
Comment #117
neclimdulComment #118
heddnassigning to myself
Comment #119
heddnComment #120
neclimdul@runInSeparateProcess on works on the method. :(
Comment #121
heddnNo interdiff.
Comment #122
neclimdulRockin! Thanks
Comment #123
alexpott@heddn, @neclimdul in an ideal world the PHPUnit fix would have in a followup. Re-opening issues for this is not great bbecause it just adds noise and work for people to figure out what's going on.
Committed and pushed e41655d1a3 to 8.7.x and 361b3188b7 to 8.6.x. Thanks!
Comment #124
alexpottComment #127
berdir> I was also iffy on removing things from the interface here, but given migrate_drupal isn't stable yet, I think I agree with @alexpott's #60 "However of course things are still implemented by the base classes that everyone would extend so that's good." Just noting this here so it's clear what the decision was if it comes back to bite us.
The stable/not stable with migrate and migrate_drupal is a pretty thin line, I actually didn't know that only migrate.module is stable :)
I don't think the argument makes quite sense about the base class and things being good. This broke paragraphs, and to be able to be compatible with 8.5 and 8.6 requires us to not rename but duplicate the methods and have both around (at least that's what we will try now, no patch uploaded yet).
Because if you don't implement both, then your logic will not be called in either 8.5 or 8.6. And we would probably not have even noticed if we wouldn't have test for our migrations.
See #2985549: Fix incorrect view display settings in LibraryItem (has a bunch of other test fixes too, but those at least are test-only).
Not quite sure that fixing "sub-optimal DX" (per issue title) is worth this API change?
Comment #128
heddnDue to the poorly previous names of functions, the adoption of field plugins has been very slow and very confusing. And vastly less adoption for that very reason. Field plugins have unfortunately seen a lot of iteration and lots of BC duck-tape holding it together. I'm sorry that paragraphs got effected.
Comment #129
berdirYeah, I get that, but this is punishing those that *did* implement them now :)
I think the BC layer goes into the wrong direction here, I don't think anything cares about code *calling* those methods, why would anything except migrate do that? What it should care about is existing implementations that override the old methods that are no longer called, either by having an actual BC layer for that (but that's really hard without causing loops or something) or we could just be honest about this being a hard API break and do something like if
method_exists($this, 'oldMethod') throw new \Exception('Rename X to Y!').Then instead of silently no longer being called, invoking the non-updated plugins would actually fail hard with clear instructions on how to update it.
Comment #130
alexpottIs there anyway to fix offer BC this was supposed to go in with a full BC layer. migrate_drupal has been beta stability which means we should only break API when we have to. This clearly is not a case of that so we invested time and effort in a BC layer. If that is not working then that is a problem.
Comment #131
phenaproximaWell, this hack totally sucks, and I hate it, but maybe it'll do the trick. I offer it for your consideration.
Comment #132
phenaproximaAnother idea, which also totally sucks, but might work a little better. This is built on the assumption that no field plugin will implement both a deprecated method and its interface counterpart (i.e., nothing will explicitly implement both processFieldValues() and defineValueProcessPipeline()). Not sure how safe of an assumption that is, but it might do for now.
Comment #133
catchWe should probably either roll this back or open up a follow-up, but since the discussion is currently happening here, re-opening.
Comment #134
phenaproximaMaybe this will work?
Comment #135
phenaproximaSo, @webchick (being the very helpful lioness that she is), gave me this: http://grep.xnddx.ru/
It's a site that lets one search all of Drupal contrib's code. Wow!
With that, I discovered that only a handful of modules are using the FieldPluginBase class: http://grep.xnddx.ru/search?text=Drupal%5Cmigrate_drupal%5CPlugin%5Cmigr...
It might be easiest, then, to just file patches against contrib to stop the bleeding. I will get on that shortly; it won't take long, and we should be able to maintain compatibility with both the 8.6+ and pre-8.6 APIs.
The question is...are we worried about custom migrations at all?
IMHO, one compromise that would not involve crazy reflection-based call chains is to simply implement a constructor in FieldPluginBase which detects if the concrete class is implementing the old methods, and throw deprecation notices if so. That would at least make the problem, and its change record, more visible.
Thoughts?
Comment #137
heddnI really like this option. The number of custom folks who have written their own field plugins is very likely low. I'm not aware of any who's done that. Perhaps Berdir or others can correct me, but only contrib (and even there, that was few) were able to reverse engineer the esoteric field plugins.
Comment #138
berdirI'm fine with closing this again.
Deprecation messages are really tricky to get right here as this shows. Lets make sure we open issues in the known contrib modules to update this and move on.
The problem with the suggestion of looking for old methods is actually problematic because it's fine to implement both, which is what we are doing in the paragraphs patch that I'm committing now. So we would need to specifically look for plugins that implement *only* the old method of each pair.
Comment #139
heddnPer #138, marking fixed again.
Comment #141
wim leersPublished https://www.drupal.org/node/2944598 since this was committed in #125.