Problem/Motivation
You cannot save entity_view_display
configuration for the menu_link_content
entity type.
During the saving process, a PluginNotFoundException
exception is thrown regarding the weight
field.
This bug was introduced in #2271419: Allow field types, widgets, formatters to specify config dependencies. When base field definitions were updated, fields formatted for the weight
field were replaced with number
instead of number_integer
.
Steps to reproduce are described in comment #39
The reason this bug does not throw exception previously is that the weight
field is not used in the rendering process using the FieldFormatter
plugin.
Workaround:
You can avoid the bug using a custom implementation of hook_entity_base_field_info_alter()
.
Details are described in comment #3.
Proposed resolution
Replace the incorrect integer
FieldFormatter id with the correct number_integer
FieldFormatter id.
Remaining tasks
The one-line patch in comment #2 fixes the problem.
The hard part is creating tests.
The single-line fix shows no effect on testing results. That means that existing tests do not cover the FieldFormatter
and FieldWidget id
in the base field definition of entities from core modules.
Based on the comment in #42, later commments suggested using the one-line patch from #2 and moving the tests to the follow-up issue #2915024: FieldWidget and FieldFormatter usage test. Comment #57 clarified that this was not the right thing to do, so later comments restored the tests.
Update path:
Comment #42 suggets we might need to test that this issue fixes the upgrade issues reported in #2883949: The "integer" plugin does not exist.. Perhaps we can leave that issue open for further discussion. (See comment #42 for details. This summary may not be accurate.)
@voleger points out,
Manually reproduced the bug on Drupal 8.0.0. That means no broken data were recorded into the active configuration, so we don't need any update path for this fix.
User interface changes
No changes.
API changes
No changes
Data model changes
No changes.
Original report by voleger
Wrong field view display option type "integer" for weight field. It throw PluginNotFoundException
in some cases.
Proposed resolution: Change type to correct value "number_integer"
Comment | File | Size | Author |
---|---|---|---|
#78 | menu_link_content-fix_used_widget_formatter_id-2903161-66-8.5.x.patch | 7.49 KB | benjifisher |
Comments
Comment #2
volegerComment #3
volegerThat code help me in module to avoid
PluginNotFoundException
:I guess it also related to #2895464: The "integer" plugin does not exist. issue.
Comment #4
volegerComment #5
tacituseu CreditAttribution: tacituseu commentedFix looks good, at the very least it is a
Major
.Comment #6
andypost@voleger please provide steps to reproduce & to add test
Comment #7
volegerThis is a patch with the test only.
Not sure about correct placement and naming.
But this test enables all modules with Entity Type definitions, then load their Base Field Definitions, then check if it possible to load required formatter and widget plugins using types from display options of loaded Base Field Definitions.
Comment #9
tacituseu CreditAttribution: tacituseu commentedThis part:
&& is_readable($module->getPath() . '/src/Entity')
is most likely responsible for tripping on
"link_default"
and"text_textfield"
as neither oflink
nortext
defines an entity.Comment #10
volegerin #7 test I tried to check all defined entity types. Who knew, maybe there are some similar problems?
Another iteration of the test:
Testing only menu_link_content module now. Loading "menu_link_content" entity type definition and checking if plugins exist that used in field display options of base field definitions.
Comment #11
volegerComment #12
tacituseu CreditAttribution: tacituseu commentedI like the test in #7, I think checking all of them is the right way to go, it acted like
link
andtext
modules were not enabled fortaxonomy
,menu_link_content
,shortcut
.Thought it might have exposed bad dependencies but checked that and all of them have them defined properly, so either
$this->enableModules()
isn't enforcing dependencies or there is something else going on here.Comment #13
tacituseu CreditAttribution: tacituseu commentedComment #14
volegerI got it)
I will also check if the module has field plugin definitions.
is_readable($module->getPath() . '/src/Plugin/Field')
So here is new test only patch:
Comment #16
volegerAnd patch with fixes and test.
Comment #18
volegerYep, there was a problem with dependencies, so in this test, all modules will be enabled.
And small changes in the message.
Comment #19
volegerComment #20
volegerComments
Comment #21
volegerSo here we have working test without fixes in #14
and test with fixes in #18.
Latest version of patch is in #20.
Comment #22
tacituseu CreditAttribution: tacituseu commented1.
+ * Tests the availability of field plugin definitions.
2.
+ $this->assertEmpty($plugin_not_found, implode(" ", $plugin_not_found));
why the
implode()
? instead of separate:Comment #23
volegerComment #25
volegerComment #26
tacituseu CreditAttribution: tacituseu commentedLooks good to me.
Comment #27
volegerComment #28
volegerComment #29
tacituseu CreditAttribution: tacituseu commentedAlternatively, instead of enabling all modules, it can be done like in #2901692-18: FieldDefinitionIntegrityTest does not respect module dependencies.
Comment #30
volegerComment #31
volegerBack to RTBC?
Comment #32
tacituseu CreditAttribution: tacituseu commentedTest only patch with the latest change would be useful too, otherwise all good.
Comment #33
volegerhere the test only patch
Comment #35
tacituseu CreditAttribution: tacituseu commentedComment #36
BerdirOh, is this (one of the?) things that are causing the reported update errors on the missing integer plugin?
Did someone test what happens when this information is saved into a view display, which should happen when you create a configurable field on menu link entities. Does a cache clear update that?
Comment #37
volegerI can't imagine how to reproduce the case when inexistent plugin recorded into the entity view display in active configuration. For now is not possible to save display mode for menu_link_content, because of
PluginNotFoundException
. Plugin manager will try to load plugins that used by field definitions before entity view display will be created.Comment #38
xjmOh whoops. That's really subtle. It makes me wonder if we have the same bug anywhere else in core because I totally would not have caught this in a code review.
I blamed the changed line and it was introduced in #2301239: MenuLinkNG part1 (no UI or conversions): plugins (static + MenuLinkContent) + MenuLinkManager + MenuTreeStorage and not changed since. If it is indeed what was causing #2883949: The "integer" plugin does not exist. I wonder what new code would have been exercising it that wasn't before?
Nice work on the tests @voleger; good idea to check other definitions as well. What are the manual steps under which you normally encounter this bug? Is it only when using https://www.drupal.org/project/menu_item_extras?
I'm wondering whether we actually need this helper method (versus just letting the test fail when the exception is thrown). Setting NR to discuss that at least.
This seems really likely to trip people up in the future and to be wrong elsewhere. Compare:
versus:
#2218199: Move email and number field types to \Drupal\Core\Field, remove modules seems to have created a disconnect between the field type and the formatter, when we made number a core field type.
Compare
core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/IntegerFormatter.php
versus
core/lib/Drupal/Core/Field/Plugin/Field/FieldType/IntegerItem.php
I wonder if we can fix the naming to be what people expect, with a deprecated wrapper or such?
Comment #39
volegerWith that bug, I faced during next steps (it requires some code):
1. Set "bundle_entity_type" and "field_ui_base_route" for "menu_link_content" entity type defnition and set "bundle_of" for "menu" entity type defnition:
Cache clear and entity update.
2a. Go to 'Manage fields' tab (for example "/admin/structure/menu/manage/main/fields");
3a. Try to add field:
2b. Go to 'Manage display' tab (for example "/admin/structure/menu/manage/main/display");
3b. Try to save view display:
Comment #40
volegerIn both situations fail message become before saving/updating entity view display. In the result - entity_view_display can't be saved in active config.
Comment #41
volegerThe helper method is needed because the original exception message is not enough to completely understand where is that problem.
The lack of information is the reason why there so many issues created. Without understanding why an exception is thrown, the situation will not change. So let's leave a little bit of information in the tests.
Comment #42
BerdirOk, so it fails already before saving, which means we don't need an update path. People did report this on updating to 8.3 for example, so I'm wondering if it was possible to save it in an earlier version. But to fix *that*, we'd actually have to inject it into/before the update function that resaves those entities (which might actually work if it's a post update hook).
However, I'm not sure if it's worth doing that and it might not be trivial. Maybe we can update those postponed issues, reference this and then discuss there whether we need an upgrade path for that.
Re the naming, yes, that the name is different is a bit unfortunate, but that's actually quite common to have mismatches between field types, widgets and formatter plugin ID's, e.g. link has link_default widget and link formatter, string has string_textfield widget and string as formatter, string_long has string_textarea widget and basic_string as default formatter. I don't think we need to change that, we don't really have a BC system for plugin ID's. But maybe instead we could add stricter, earlier validation, so that when you use an invalid type when defining a base field, it throws an exception immediately with helpful context?
In that sense, I also think the exception handling in the test is useful, as it does tell you which entity/field this happens on.
Long story short, I'd vote to get this in asap, with those possible follow-ups/updates on related existing issues.
Comment #43
xjmAlright, would very much like to see those followups so we can fix this one and hopefully fix some of the fatals, but I do want to make sure we have for checking for more and planning for more in the long term. Thanks @Berdir and @voleger.
Comment #44
xjmCan we file the followups descreibed in #42? It would really help for reviewing and defining the scope of this patch, because otherwise the scope feels like "look at everything called
integer
andnumber_integer
in all of core.Comment #45
xjmFor me we need the followups before reviewing and committing this, given that similar bugs may be causing other criticals.
Comment #46
voleger\Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem::class
plugin has idinteger
;\Drupal\Core\Field\Plugin\Field\FieldFormatter\IntegerFormatter::class
plugin has idnumber_integer
;\Drupal\Core\Field\Plugin\Field\FieldWidget\NumberWidget::class
plugin has idnumber
;In the provided test we check usage of
FieldFormatter
andFieldWidget
plugins by core entity type definitions.So it does not mean that we should everywhere replace
integer
bynumber_integer
.The case with
menu_link_content
entity type show that somehow in configuration placed usage ofFieldType
instead ofFieldFormatter
plugin.Comment #47
volegerMaybe it will be better to add some validation for
setDisplayOptions
method in\Drupal\Core\Field\BaseFieldDefinition::class
?Comment #48
volegerI manually reproduced steps from #39 using Drupal 8.0.0. The same behaviour.
So I don't think that we should provide an upgrade path for that.
Comment #49
volegerComment #50
volegerIn #2271419: Allow field types, widgets, formatters to specify config dependencies updated usage related
FieldWidget
plugin id, but forgot to update usageFieldFormatter
plugin id.That's the reason of this bug.
Commit http://cgit.drupalcode.org/drupal/commit/?id=1508939
Diff of changes in menu_link_content http://cgit.drupalcode.org/drupal/diff/core/modules/menu_link_content/src/Entity/MenuLinkContent.php?id=1508939
Comment #51
volegerComment #52
volegerDiscussed that issue with @andypost
So I create the followup issue that shows wrong used plugin id in entity base field definition.
That incorrect value used from 8.0.x-dev version of Drupal core.
Plugin system does not allow to save that incorrect value to the entity view display. That was manually tested on 8.0.0 version of Drupal core.
To make possible to pass the test from #2915024: FieldWidget and FieldFormatter usage test is the commit a patch from #2 comment.
Comment #53
benjifisher@volegar:
Please update the issue summary. Why are all the patches hidden except the one from Comment #2? Is that because the tests will be added in a follow-up issue? Also, the comment in #3 looks like a work-around, and that should be mentioned in the issue summary.
In short: if you want someone to review the issue, then make it easier.
Also, remember to un-assign yourself when you are done.
P.S. If the tests are not to be included, then it would help to have steps to reproduce added to the summary.
Comment #54
volegerThanks for the comment.
This issue shows that actually validation mechanism is missed in the field component of Drupal core. That's why we have such a bug since 8.0.x-dev.
Anyway, I will update the issue summary.
Comment #55
volegerUpdated summary.
Comment #56
andypostLet's make title actionable & patch #2 fix that, also there's follow-up for test for all base fields #2915024: FieldWidget and FieldFormatter usage test
Comment #57
xjmAutomated test coverage for bug fixes is a Drupal core gate. We should not scope test coverage to followup issues. Please update the shown files on the issue to show the correct patch; #2 is lacking the test coverage that is required for this to be committed. Thanks!
Comment #58
volegerComment #60
andypostRTBC again
I thought that the issue will add specific test for menu link entity only but having test coverage for all fields looks impressive!
Comment #61
benjifisherThis looks like a really good piece of work, but I think there are some things that should be fixed. I am trying to save one of the core committers the trouble of pointing these out.
1. Do we really need this?
I am not sure: do we use
{@inheritdoc}
for properties or just for methods? If you want to leave it in, I will not insist.2. Nice job of DRY (It would have been easier to copy and paste the code) but I think we can do better:
This method is called twice: the second time is this:
There are a few reasons I do not like this method.
First, I am an old-fashioned guy, with no experience in functional programming, and functions that accept
callable
arguments are just more confusing than functions that acceptstring
and returnarray
.Second, the
enableModulesByFilter()
method captures only about half the complexity. Each of the two places that call it need to create thecallable
argument.Third, this method violates the single-responsibility principle. It generates a list of modules and then it enables those modules. I like functions that return information better than functions that have global effects.
I think it would be clearer if you defined a function like this:
and then you could use the function like this:
3. This looks like an unrelated fix:
Yes, that is the right way to do it, but unless it affects the results of the tests, I think you should leave this for another issue. Maybe that issue is already out there, and someone is trying to fix it in all of Drupal core. If so, then we do not want to break that patch.
4. Same idea:
and three similar changes. Unless we really need this change now, we should leave it out. Leaving it out will make the patch easier to review and get it accepted sooner.
5. Maybe PHP's
empty()
is one of my pet peeves.This is exactly the same as
The difference between
if (!empty($display_options['type']))
andif ($display_options['type'])
is that theempty()
version works (without even a Notice) even if$display_options
is unset.Comment #62
benjifisherCopy-editing the issue summary.
I am not sure that my summary of @Berdir's comments in #42 is correct.
Comment #63
volegerThanks for the review.
Regarding #62:
1). Reverted changes. It's out of the scope of this issue.
2). I agree. It's better to return meaningful data for existing
enableModules()
method. Updated.3). Reverted changes. It's out of the scope of this issue.
4). Reverted changes. It's out of the scope of this issue.
5). Yep, a little bit messy expression here. Fixed.
Comment #65
benjifisher@volegar: Thanks for the updated patch.
Please replace this with another call to the new method
modulesWithSubdirectory()
. Other than that, the changes look good.Funny: when I first looked at the interdiff, I wondered why you were replacing
$this->container->get('plugin.manager.field.field_type')
with\Drupal::service('plugin.manager.field.field_type')
. I had to reread my own comments to remind myself that I asked you to remove unrelated fixes.Comment #66
volegerHere few changes related to modules enabling.
Comment #68
benjifisherThanks, that is much more DRY!
My understanding is that
DIRECTORY_SEPARATOR
is not needed here, although some consider it a good idea. I see that it is used in a few other places in Drupal core, and I am not aware of any coding standard for or against using it. So I think we can leave this to your discretion.This patch satisfies all the points I raised in #61, so back to RTBC.
Comment #69
catchCommitted/pushed to 8.5.x, thanks!
This should be backported to 8.4.x, but it doesn't cherry-pick cleanly so needs a re-roll against that branch.
Comment #70
catchComment #71
volegerAdded
array_diff()
for list of module to enable regardingself::$modules
because Drupal test throws an exception till 8.5.x version if test try to enablesystem
module again.Comment #73
benjifisherThe attached is not a standard interdiff. To generate it, I applied the patch from #71 to the current HEAD of 8.4.x, then compared the single file
FieldDefinitionIntegrityTest.php
to the version in 8.5.x, which now includes the patch from #66.Note that the comment was changed by Commit 3a4f6f2979b from #2901692: FieldDefinitionIntegrityTest does not respect module dependencies. The original patch for that issue was applied to both 8.4.x and 8.5.x, then reverted on both branches, and then a new patch was committed on just the 8.5.x branch.
Unfortunately, the current patch changes the behavior of
testFieldPluginDefinitionIntegrity()
, in effect applying the patch from #2901692: FieldDefinitionIntegrityTest does not respect module dependencies. I am not sure why that patch was not applied to 8.4.x, but I do not think that we should mix up the two issues by applying it here.I will leave the status at NR, add the related issue, and see if I can get some comments on why it was not fixed in 8.4.x.
Comment #74
benjifisher@dawehner reopened #2901692: FieldDefinitionIntegrityTest does not respect module dependencies. I suggest that we put off this issue until that one is resolved. If that does not get committed to the 8.4.x branch, then on this issue we can either put in just the bug fix, no change to tests, or else put in the bug fix and the new test, without changing the existing one. That last option would break the DRY principle.
Comment #75
voleger#2901692: FieldDefinitionIntegrityTest does not respect module dependencies fixed!
Lets try to run test for 8.4.x with patch from #66 comment.
Comment #76
benjifisherRight, the patch from #66 applies cleanly. That is not surprising, because the only commits on 8.4.x or 8.5.x that are not on the other branch are related to this issue or to #2901692.
Let's start by re-testing the test-only patch from #66. (I will do that.) If that fails in the expected way, then we should re-upload the real patch from #66.
Comment #77
volegerSame behavior as 8.5.x.
It looks like the patch from #66 comment ready to go in 8.4.x.
Comment #78
benjifisherRight, the test-only patch fails in the expected way:
I will re-upload the patch from #66.
Comment #79
volegerNo failures. Back to RTBC?
Comment #80
benjifisherYes. To summarize the last few comments:
In #69, @catch committed the patch from #66 to 8.5.x and wrote,
The patch did not apply to the 8.4.x branch because #2901692: FieldDefinitionIntegrityTest does not respect module dependencies was committed only on the 8.5.x branch. Now that that issue has been committed to the 8.4.x branch, the files affected by this patch are the same on 8.4.x and 8.5.x.
Just to be sure, we re-tested the patch from #66 and the test-only patch there, and got the expected results.
Comment #82
larowlanthis seems like the wrong comment? Technically its loading the definition, but its loading and testing.
Perhaps we should rename to
assertValidDisplayOption
and then the description would be 'Asserts that display options reference valid plugins'?this is slick
Nice work here
Comment #83
andypost@larowlan If we gonna rename method for 8.4 then it needs follow-up to rename in 8.5 where the patch already accepted #69
Comment #84
larowlanOh. missed that - thanks @andypost
Comment #85
andypostPatch from #78 applies to 8.4 without offsets
Comment #87
xjmIt cherry-picks cleanly now, so I just cherry-picked it. Thanks!
I don't think the followup I asked for in #42 ever got filed; can we file it and link here?
Comment #88
benjifisherWhen I updated the issue summary, I read through #42 a few times. It was not clear to me what follow-up should be filed. Are we looking for a test of the upgrade path to 8.3?
I think that @Berdir in #42 suggested either a follow-up or else updates to #2869449: The "media" entity type does not exist after update to Drupal 8.3 and/or #2883949: The "integer" plugin does not exist., both currently marked as "postponed".
Comment #89
xjmThanks @benjifisher. What I'm looking for is a followup to check over other places where
integer
is used that should maybe benumber_integer
instead, and for this:Thanks!
Comment #90
BerdirI created #2924861: Add validation for chosen widget/formatter plugin in base fields for the second part, but I wouldn't know where to look for the first. This issue already added a test for all base fields to have a valid type and the follow-up that I created would then take care of whatever this would have missed, if anything.
Comment #91
benjifisherThanks, @Berdir. I have added that as a related issue. I think that satisfies @xjm's request, so I am removing the "Needs followup" tag.