- ๐ฌ๐งUnited Kingdom joachim
> would fix the root cause of why "id" and "group" are so intertwined and this issue is unnecessary.
Having looked at this code a bit more, I'm starting to understand why id and group behave like this.
And YES, it does need to be documented MUCH better.
> The two ALWAYS have to be identical when using a "deriver" such as "Drupal\Core\Entity\Plugin\Derivative\DefaultSelectionDeriver". If no deriver is used and the "id" is prefixed with the "group", the second part has to be the entity type ID, but then Drupal will expect to find a "base plugin" of some kind.
That's mostly right, but not entirely. When a plugin declares a deriver, then the base plugin ID is not registered as a plugin ID. So, core has:
#[EntityReferenceSelection( id: "default", group: "default", deriver: DefaultSelectionDeriver::class, )]
which means there is no plugin with ID just 'default'.
What's going on with the 'Notice: Undefined index: base_plugin_label' error is that EntityReferenceItem is expecting that a plugin with an ID of the form 'GROUP:ENTITY_TYPE' is made with a deriver, and the deriver does this:
$this->derivatives[$entity_type_id]['base_plugin_label'] = (string) $base_plugin_definition['label'];
So that's something else to fix -- if base_plugin_label isn't set, it should fall back to the plugin label.
Part of the complication here is that some of the assumptions about how id & group work are in the field system, in EntityReferenceItem. That's a code smell, because that should be a mere consumer. Technically, as the code stands, another consumer of these plugins could name a plugin 'cats:dogs' and specify that as '#selection_handler' in an entity_autocomplete form element. Except as you point out, an entityreference field would break.
So as well as documenting, we should open an issue to have the SelectionPluginManager's discovery process throw exceptions for plugin IDs that don't conform to the expected pattern, so that developers see the problem earlier.
The reason for all this is that basically, the plugin ID is NOT REALLY THE ID. Sort of. The thing the user actually is selecting when they configure an entityreference field is the group. The rest of the plugin ID is to specialise by entity type.
The expectation is that you either have:
- group and id match. There is only one plugin for all entity types (which it declares it can handle)
- group 'foo' and ids 'foo:ENTITY_TYPE'. AFAICT there is no point declaring a different foo-group plugin for an entity type, such as 'foo:node_extra', because it won't show in the field settings, even if you declare the 'entity_types' property. In fact, AFAICT the entity_types property is redundant because of this, and we could consider removing it.So in core we have the 'default' group, which uses a base class DefaultSelection, with a deriver which produces plugins 'default:ENTITY_TYPE'. Core then makes use of how you can override the class for a derived plugin, by having classes like NodeSelection with specialised handling for nodes.
If you wanted to provide an alternative way to handle nodes, you need to define a new *group*, and the plugin for nodes in that group, like this:
* @EntityReferenceSelection( * id = "test_3270898:node", * label = @Translation("Node test_3270898"), * base_plugin_label = @Translation("Node test_3270898"), * group = "test_3270898", * entity_types = { * "node", * }, * weight = 0, * )
Then, to complicate matters, there is automatic selection in SelectionPluginManager to do with the weight. If you call getInstance() with a plugin ID with no ':' in it it tries to find the 'best' plugin ID within that group which can handle the entity type. This is assuming that in the same group you might have, say:
- mygroup:node
- mygroup:node_extra
- mygroup:node_amazingand that it should pick the one with the highest weight. This seems all rather pointless, since EntityReferenceItem will have saved the field configuration with 'mygroup:node' as the handler ID.
- ๐ฌ๐งUnited Kingdom joachim
> So that's something else to fix -- if base_plugin_label isn't set, it should fall back to the plugin label.
I'm actually wondering whether that should be fixed.
If you want to create a plugin that applies to just one entity type, use a singleton with the same plugin ID and group name.
If you want to create plugins for several entity types, either create several singletons, or use a deriver so they apply to all entity types.
- ๐ง๐ชBelgium kristiaanvandeneynde Antwerp, Belgium
From what I can recall (from 8 years ago, mind you), the whole group thing is so you could specify an ER field where you don't care about the selection plugin, as long as it's tailored towards e.g. nodes. Then it would default to whatever core has, but if someone else came up with a "better" selection plugin, that one would be used instead.
In practice, I have yet to see anyone make use of that because often the one creating the selection plugin is the one consuming it. E.g.: I have a really specific group role selection plugin in Group that I do not expect anyone to ever "improve".
- ๐ฌ๐งUnited Kingdom joachim
The way I understand it is that the 'group' is SECRETLY the plugin ID. It's what you select in the UI.
So OOTB you get to pick between 'default' and 'views'.
But instead of making those the plugin IDs, they are the group instead, so that we can use the plugin derivative system to get specialised plugin classes for different entity types.
Which is a hack, really.
Conceptually, what we really want here are dynamically-selected plugin classes. But that would require a whole new concept and an additional way of declaring which plugin class to use for what condition.
- ๐ฎ๐ณIndia heykarthikwithu Bengaluru ๐
heykarthikwithu โ changed the visibility of the branch 3270898-misleading-documentation-in to hidden.