Updated as of #70
Problem/Motivation
Most, if not all derivers do not set plugin IDs for derivative definitions explicitly, but provide it by merging in the base plugin definition for defaults. This means that for any derivative definition, the specified ID is that of the base plugin, even though the keys in the definitions array are correct (see #2458723: Incomplete documentation for DiscoveryInterface::getDefinitions()).
\Drupal\system\Plugin\Derivative\SystemMenuBlock is a concise example:
public function getDerivativeDefinitions($base_plugin_definition) {
foreach ($this->menuStorage->loadMultiple() as $menu => $entity) {
$this->derivatives[$menu] = $base_plugin_definition;
$this->derivatives[$menu]['admin_label'] = $entity->label();
$this->derivatives[$menu]['config_dependencies']['config'] = [$entity->getConfigDependencyName()];
}
return $this->derivatives;
}
In the above example the derivative ID will be $menue main and for derivatives will be of the form $base_plugin_id:$derivative_id system_menu_block:main, but for derivatives, the $definition item contains only the $base_plugin_id system_menu_block, so that multiple $definition values will have the same ID in them.
Proposed resolution
Merge in the derivative ID in \Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator.
Remaining tasks
Find a way to set the derivative ID.
User interface changes
None.
API changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| #109 | 2458769-nr-bot.txt | 149 bytes | needs-review-queue-bot |
Issue fork drupal-2458769
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:
Comments
Comment #1
xanoBefore we can fix this, we need to make a fundamental decision about what to do with plugin code that applies to both object and array plugin definitions. Seeing as object definitions are custom and we are in beta, I propose all code is standardized for array definitions. Child classes are then used to support object definitions.
Comment #2
xanoSee #2458789: Introduce PluginDefinitionInterface.
Comment #3
xanoComment #4
xanoI removed the object definition test, because they are simply not supported. The test was faulty anyway, as the definition merge only supports arrays.
Comment #5
berdirShould we add a short comment here, something like '// Ensure that the plugin id is set to the derivative plugin id'?
Comment #6
xanoComment #9
xanoWe're encountering more and more issues that are caused by the fundamental problem of having multiple definition types. Multiple workarounds have bee suggested and they all greatly reduce DX and maintainability. Let's fix this once and for all in #2458789: Introduce PluginDefinitionInterface.
Comment #10
xanoWe may fix this in #2458789: Introduce PluginDefinitionInterface, as this bug is causing test errors there.
Comment #11
xano#2458789: Introduce PluginDefinitionInterface now passes all tests and is ready for manual review. The patches there contain the fix for the bug this issue is about, because it caused test failures there.
Comment #12
fabianx commentedTagging for framework manager review as #2458789: Introduce PluginDefinitionInterface was pushed back.
Comment #13
xanoBump.
Comment #14
jibran#2458789: Introduce PluginDefinitionInterface is postponed to 9.x so no need for framework manager review. Let's fix it without #2458789: Introduce PluginDefinitionInterface.
Comment #15
xano#2485513: DefaultFactory cannot deal with objects as plugin definitions introduces the most minimal
PluginDefinitionInterfacepossible. When that's committed, we can extend the interface with::setId()and::getId()to fix this issue in the same way as we fixed the bug in the other issue.This also requires a completely new patch, so removing the needs reroll tag.
Comment #16
xanoThis is a first stab at fixing the problem using the new interface. This patch depends on the one from #2485513: DefaultFactory cannot deal with objects as plugin definitions and will not apply without it.
This patch introduces two new interfaces: one for merging plugin definitions, and one for plugin definitions to define derivers. No implementations of these interfaces exist.
It also extends #2485513: DefaultFactory cannot deal with objects as plugin definitions's
PluginDefinitionInterfacewith methods for plugin IDs, which really cannot live in any optional interface.The newly introduced methods and interfaces are then used by
DefaultFactoryto be able to deal with both array and object plugin definitions.Comment #17
xanoComment #19
xanoComment #21
xanoComment #23
xanoI am not able to reproduce all of the remaining test failures locally. Is someone else?
Comment #25
xanoThis removes the BC breaks.
Comment #27
xanoSince all our code that handles array-based plugin definitions assumes every definition contains an
idkey, we could argue object definitions must provide IDs as well, and that we should break BC by adding methods to\Drupal\Component\Plugin\Definition\PluginDefinitionInterface. If we do not expand this interface, we end up with methods that are simple for arrays (because those assume easy array access with required keys), and with several lines of type checks for classed definitions.Comment #29
xanoBump. This issue could use feedback from other contributors.
Comment #30
xanoRe-roll.
The new
\Drupal\Component\Plugin\Definition\MergeablePluginDefinitionInterfacedoes conflict with\Drupal\plugin\PluginDefinition\PluginDefinitionInterface, unfortunately.Comment #34
xanoComment #35
xanoComment #37
berdir@file needs to be removed now.
so this doesn't actually return $this, it returns $other_definition, right? I think we use "@return static" (same class, but not this object) in this case? could be wrong.
uh.. what interfaces? :) Also 80 characters..
is this rename necessary, makes the diff harder to read.
I'm not sure how exactly you use plugin definition objects in plugin.module. you have some kind of decorators, but they will only come in play later, right?
but afaik at least in core, entity types are still the only example that use objects. Which actually do not support derivers *at all* (":" is not a valid character for an entity type)
IMHO, it would be acceptable to only solve it here for arrays, which would solve it at least for the core plugin types. Because that would *greatly* simply this patch and remove all the controversial parts. Right now, you're doing much more than what the issue says.
Comment #38
tim.plunkettNot that we really need a getProvider() on these, for \Drupal\Core\Plugin\DefaultPluginManager::findDefinitions() to use. Having to work around this currently in #2296423: Implement layout plugin type in core
Comment #39
xanoFixed.
It does. The docblocks describe the methods of merging
$other_definitioninto$this. Plugin definitions are assumed to be mutable, but I'm fine with changing this to@return staticas that's more conservative and would potentially allow immutability at some point in the future, especially asreturn $this;does not violate@return static.Fixed.
Not necessary. I renamed
$derivative_definitionto$derivative_plugin_definitionfor consistency with$plugin_definitionin the same bit of code to help me understand the code better, and kept it because I thought it would help.If you disagree with this change, we can revert it.
Not doing this for object-based definition means core actively discourages people even more from improving DX on their own. We officially allow definitions to be arrays or objects, so my opinion is that any code must support both in such a way that we don't make object support worse than it currently is. If we solve this problem for arrays, but not for objects, there's not technically a regression, but we do introduce an inconsistency.
Not or Note? We can introduce another optional interface and document its usage on
PluginDefinitionInterface. I don't know to which extent we can enforce its usage, though. Any thoughts on that?Comment #40
tim.plunkettI meant "Note". And my idea was to include getProvider/setProvider methods on this interface, rather than add Yet Another Plugin Definition Interface.
We can check for it in DefaultPluginManager in a follow-up.
Also I think this should be marked to be merged into PDI itself for D9. Class, ID, Provider are all really essential, and are Component level stuff (Compare to \Drupal\Component\Annotation\AnnotationInterface)
Comment #41
tim.plunkettI withdraw my request to include getProvider here, that is squarely out of scope, and since we can't change PluginDefinitionInterface anyway, it might as well stay separate: #2818653: Allow object-based plugin definitions to be processed in DefaultPluginManager::findDefinitions()
Comment #43
joachim commented> Most, if not all derivers do not set plugin IDs for derivative definitions explicitly, but provide it by merging in the base field definition for defaults
'base field definition'?
Also, it would really help to have some examples in this explanation.
Comment #44
tim.plunkettI believe that was meant to say "base plugin definition", as in the parameter name of the method
public function getDerivativeDefinitions($base_plugin_definition) {\Drupal\system\Plugin\Derivative\SystemMenuBlock is a concise example:
Comment #45
joachim commentedSo, just to check I get it -- what this issues is about is that if I do:
then all the $plugin_id values are correct, and for derivatives will be of the form base_plugin_id:derivative_id, but for derivatives, the $definition item contains only the base_plugin_id, so that multiple $definition values will have the same ID in them.
Where:
- the base_plugin_id is the ID specified in the plugin class annotation alongside the deriver property that gives the deriver class name
- the derivative_id is the ID keyed into $this->derivatives[$plugin_id] in DeriverBase::getDerivativeDefinitions()
If that's the case, then yup, it's a pain, as all plugin deriver classes are having to put this into the definition themselves in getDerivativeDefinitions().
Comment #51
psf_ commentedThe last patch doesn't apply to D8.7.10.
I have this problem witch field types, I extend from EntityReferenceItem and it's listed with the same label that it, it not use the new label.
Comment #52
jungleComment #53
swatichouhan012 commentedRe rolled patch.
Comment #55
hardik_patel_12 commentedRe-roll for 9.1.x.
Comment #56
hardik_patel_12 commentedKindly ignore last patch , because patch at #55 and #53 are identical , i am triggering test for 9.1.x branch on #53. So patch at #55 is not needed sorry for that.
Comment #57
jofitzRe-roll based on last patch that successfully applied (#39).
Comment #59
deepakaryan1988Comment #60
deepakaryan1988Rerolled the patch based on #57
Comment #61
deepakaryan1988Comment #62
deepakaryan1988Rerolled it again.
Comment #64
jpatel657 commentedComment #65
jpatel657 commentedCode sniffer issue has been fixed.
Comment #66
martin107 commentedComment #68
quietone commentedThanks everyone for the recent patches and moving this issue forward. To make it easier to review please provide an interdiff or a diff when uploading a patch.
Comment #69
jibranFirst of all, thank you all for looking into the issue and try to reroll the patch. There is a major problem with rerolls.
#2296423: Implement layout plugin type in core Added
\Drupal\Component\Plugin\Definition\DerivablePluginDefinitionInterfacewhich is almost same as\Drupal\Component\Plugin\Definition\PluginDeriverDefinitionInterfacein this patch that is why this patch needs be recreated from #39 again.All the rerolls since #39 are useless and missing the pieces of the code and no one tried to understand the code changes while removing conflicts so I'm removing commit credit from all the patch rerolls.
Comment #70
jibranTo all the who tried to help with the reroll. If you can't understand the code conflict feel free to ask questions here or in the drupal slack contribute channel.
Please, please don't overwhelm the reviewers with too many patches which are not helpful in moving the issue forward.
We need to create a new patch by looking at #39. We don't want to reroll #39.
Updated IS from the discussion #43, #44, and #45.
Comment #71
quietone commented@jibran, thanks for the clarification.
I read through the issue and noted that Berdir commented in the last paragraph of #37 that it would be fine to solve it here for arrays and simplify the patch. In reply, #39, Xano makes a good argument that not doing this for object based definitions introduces an inconsistency. For myself, I don't like inconsistencies at all and support that idea. However, adding it here does make the patch more complex and perhaps that is one of the factors why this issue hasn't been resolved yet. So, despite my preference for consistency let's stick to solving for arrays here. Anything else can be a followup.
In that light I have made a new patch. And then to see if it actually work I used it in Migration. Specifically, \Drupal\migrate\Plugin\MigrationPluginManager::expandPluginIds() can be removed. That functionality is still needed in tests so it now resides in MigrateTestBase.
Comment #73
quietone commentedSo, that isn't going to work. Many of the migrate failures are in \Drupal\migrate\Plugin\Migration::checkRequirements() and even if that passed it would fail in the MigrateLookup service anyway. So, this removes the migrate changes.
Comment #75
quietone commentedThis should fix the two failing migration tests. As for the other tests, I don't know. Can someone else look into the remaining failures?
Comment #77
quietone commentedThis may fix the migrate failures.
Comment #79
jibranNice work with recreating the patch.
Maybe set a base_id as well on all the plugins?
Comment #80
quietone commentedI was thinking the same thing.
Comment #82
quietone commentedFixing tests and a bit of cleanup.
Comment #84
jibranThis can just be
strpos($migration_id, $base_id) === 0.Comment #85
quietone commentedActually, I prefer
if ($base_id === ($migration['base_id'] ?? NULL))where we actually use the new base_id on the plugin definition.I have looked into the three remaining errors and haven't made any progress on fixing them. Two are in areas I don't know at all. One is a FuncationalJavascript test and I have never been able to run them locally let alone debug them. Another is in content_moderation\Functional\ModerationActionsTest. I must admit that there are two migration issues related to content_moderation so I will have to dabble in it but I haven't started yet. The final one is Derivative test and it eludes me why adding the base_id to the expected causes the failure.
Comment #87
hash6 commentedComment #89
quietone commented@hash6, are you still planning to work on this?
I noticed this needs a reroll, so here it is. There are still failing tests.
Comment #91
vsujeetkumar commentedFixing fail tests.
Comment #92
tim.plunkett$this->mockBlockExpectedDefinitionsshould be changed directly, where it is defined.This is violating the coding standards, that's why the test failed. elseif should start a newline.
But no need to fix it, due to my first point of feedback
Comment #93
vsujeetkumar commentedDone with the changes advised by @tim.plunkett
Comment #95
vsujeetkumar commentedFixing fail test.
Comment #98
dhirendra.mishra commentedRe-rolled this against 9.3.x as previous patch was not applied to 9.3.x automatically.
Comment #99
mohit_aghera commentedChanging to needs review so test bot can pick it up.
Comment #102
tim.plunkettAddressed my own feedback from #92, switched from patches to a MR, and fixed the tests.
Comment #103
berdirAdded a comment about the comments, for the id change I guess we just have to do a change notice and hope that we don't break too many things :)
Comment #104
tim.plunkettThe last thing to consider is the addition of
base_id.As seen in the changes to
content_moderation_action_info_alter()andlayout_builder_plugin_filter_block_alter(), it is helpful for any code dealing with checking definitions.It also covers up a bug in the actions system, see #2916740-117: Add generic entity actions
Comment #108
wim leersThis came up again at #3313473-33: CKEditor 5 plugin definitions should be derivable.
Comment #109
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.