Problem/Motivation
Currently, the set of properties for a particular plugin type is only defined in one place - previously the plugin type's annotation class, and now the plugin type's attribute class.
This leads to some problems, such as:
- The long-standing problem where the EntityType annotation/attribute defines a 'field_ui_base_route' which is actually for field_ui, an optional module
- The long-standing feature needed for Views, where we'd like to add a property to FieldType plugins for Views, which is, again, an optional module -- #2337515: Allow @FieldType to customize views data
Proposed resolution
Provide a PluginProperty
attribute class that can be used to add property data to plugin class definitions parsed from Plugin attributes. The PluginProperty
class includes these properties:
- key: The property key/name within the plugin definition to set the value for. If
key
is an array, then it is treated as a set of nested array keys, with the outer keys coming first. When plugin definitions are arrays, NestedArray::set()
is used to set the value at key
- value: The property value to set
- allowedPluginClasses: A list of plugin attribute classes the plugin property can modify the definition for. This is really only useful for subclasses of
PluginProperty
Because of the way plugin attributed-based discovery is cached, it is difficult to read data from PHP attributes that exist only when certain modules are installed. As a result, subclasses of the PluginProperty
are not allowed outside of Drupal\Core
and Drupal\Component
. In order to allow module-specific properties to be added to plugin definitions, the PluginProperty
class also has these properties:
- moduleDependencies: Machine names of modules that need to be installed in order for the property to be set, if any
- addToDefinitionCallback: If the
PluginProperty
attribute is being used with a plugin type definition that is not a an array, and there doesn't exist a core PluginProperty
subclass that works with the plugin type, then custom/contrib developers can pass in a callable to PluginProperty
that sets the property value on the definition object
Once we have something like PluginProperty
, we can also create subclasses in core that allow us to set properties on entity type definitions, in order to split up the large entity type attribute definition into multiple attributes, as suggested in #18:
#[ContentEntityType(
id: 'node',
label: new TranslatableMarkup('Content'),
...
)]
#[Handler('storage', NodeStorage::class)]
// Or maybe even more specific subclasses for common handlers
#[StorageHandler(NodeStorage::class)]
#[Link('canonical', '/node/{node}']
With an EntityTypeProperty
subclass, we can define the field_ui_base_route
on entity type definitions to be added only when Field UI is installed as such:
#[ContentEntityType(
id: 'node',
label: new TranslatableMarkup('Content'),
...
)]
#[EntityTypeProperty(
key: 'field_ui_base_route',
value: 'entity.node_type.edit_form',
moduleDependencies: ['field_ui'],
)]
Other entity type definition subclasses such as Handler
, StorageHandler
, Link
will be added in follow up #3488054: Make it possible to define entity types with multiple smaller attributes. EntityTypeProperty
is added in MR 10218 here, as well as the Field UI example change in Node
.
Note: field_ui_base_route
is used as the base route for local tasks on entity bundle admin paths: https://git.drupalcode.org/project/drupal/-/blob/11.x/core/modules/user/.... Changing it so that it is only defined when Field UI is installed might have some unexpected UI changes.
Remaining tasks
User interface changes
None.
API changes
Plugin classes can use PluginProperty attributes to add supplemental properties to their definitions.
Data model changes
Release notes snippet