YAML Plugin Definitions¶
The Modeler API provides three YAML-based plugin types that allow any module to contribute metadata for Model Owners without writing PHP code. These are ideal for curating component palettes, defining ordering constraints, and providing template tokens.
Contexts¶
Contexts define which components are available in a particular use case. They allow modeler UIs to show a focused subset of plugins rather than the full list.
File naming¶
Place a YAML file named my_module.modeler_api.contexts.yml in your module's
root directory.
Structure¶
my_context:
topic: 'Description of this context'
model_owner: target_owner_id
includes:
- base_context_id
components:
start:
plugins:
- event_plugin_1
- event_plugin_2
element:
plugins:
- action_plugin_1
- action_plugin_2
link:
plugins:
- condition_plugin_1
Key reference¶
| Key | Type | Required | Description |
|---|---|---|---|
topic |
string |
Yes | Human-readable name (shown in UI) |
model_owner |
string |
Yes | Target Model Owner plugin ID |
includes |
string[] |
No | Other context IDs to inherit from |
components |
object |
No | Plugin lists per component type |
components.{type}.plugins |
string[] |
No | Plugin IDs available in this context |
Valid component types¶
start, subprocess, swimlane, element, link, gateway, annotation
Include resolution¶
Includes are resolved transitively. Given:
base:
topic: 'Base'
model_owner: my_owner
components:
element:
plugins: [a, b]
extended:
topic: 'Extended'
model_owner: my_owner
includes: [base]
components:
element:
plugins: [c]
The resolved extended context contains element plugins [a, b, c].
Multiple contexts per file¶
You can define multiple contexts in a single file. Each top-level key is a separate context:
context_a:
topic: 'Context A'
model_owner: my_owner
components:
start:
plugins: [event_1]
context_b:
topic: 'Context B'
model_owner: my_owner
includes: [context_a]
components:
start:
plugins: [event_2]
Real-world example¶
From eca_ng.modeler_api.contexts.yml:
eca_base:
topic: 'Commonly used ECA components'
model_owner: eca
components:
start:
plugins:
- kernel:controller
link:
plugins:
- eca_scalar
- eca_count
- eca_route_match
element:
plugins:
- action_message_action
- eca_token_set_value
- eca_switch_account
- eca_token_load_entity
eca_form:
topic: 'Altering Drupal forms'
model_owner: eca
includes:
- eca_base
components:
start:
plugins:
- form:form_build
- form:form_submit
- form:form_validate
link:
plugins:
- eca_form_field_value
- eca_form_field_exists
element:
plugins:
- eca_form_add_textfield
- eca_form_field_set_value
Dependencies¶
Dependencies define predecessor constraints: which components can only be used as successors of specific other components.
File naming¶
Place a YAML file named my_module.modeler_api.dependencies.yml in your
module's root directory.
Structure¶
my_dependencies:
model_owner: target_owner_id
components:
link:
condition_plugin_id:
- type: start
id: required_event_id
element:
action_plugin_pattern:
- type: start
id: required_event_pattern
- type: element
id: required_action_pattern
Key reference¶
| Key | Type | Required | Description |
|---|---|---|---|
model_owner |
string |
Yes | Target Model Owner plugin ID |
components |
object |
Yes | Rules per component type |
components.{type}.{pluginPattern} |
array |
Yes | Plugin pattern (supports * wildcards) |
components.{type}.{pluginPattern}[].type |
string |
Yes | Predecessor's component type name |
components.{type}.{pluginPattern}[].id |
string |
Yes | Predecessor's plugin ID (supports * wildcards) |
Wildcard support¶
Both the plugin ID key and the predecessor id value support glob-style
wildcards:
my_dependencies:
model_owner: my_owner
components:
element:
my_form_*: # Matches my_form_add, my_form_edit, etc.
- type: start
id: form:* # Matches form:build, form:submit, etc.
Semantic meaning¶
A dependency rule means: the plugin matching the key can only be used in a model that has one of the listed predecessors as an ancestor (directly or transitively).
For example:
This means: eca_form_add_textfield can only be used in a model where
form:form_build is the starting event. If a user creates a model starting
with kernel:controller, this action will be filtered out.
Real-world example¶
From eca_ng.modeler_api.dependencies.yml:
eca:
model_owner: eca
components:
link:
eca_route_match:
- type: start
id: kernel:controller
eca_form_field_value:
- type: start
id: form:form_build
- type: start
id: form:form_submit
- type: start
id: form:form_validate
element:
eca_form_build_entity:
- type: start
id: form:form_submit
- type: start
id: form:form_validate
Template tokens¶
Template tokens define hierarchical token trees used in model templates. When a model is marked as a template, these tokens can be used as placeholders that are replaced when the template is instantiated.
File naming¶
Place a YAML file named my_module.modeler_api.template_tokens.yml in your
module's root directory.
Structure¶
my_tokens:
model_owner: target_owner_id
tokens:
root-key:
name: 'Root Token Group'
token: root-key
children:
child-key:
name: 'Child Token'
token: 'root-key:child-key'
value: 'Default value'
children:
leaf:
name: 'Leaf Token'
token: 'root-key:child-key:leaf'
value: 'Leaf value'
Key reference¶
| Key | Type | Required | Description |
|---|---|---|---|
model_owner |
string |
Yes | Target Model Owner plugin ID |
tokens |
object |
Yes | Token tree (recursive) |
Each token entry:
| Key | Type | Required | Description |
|---|---|---|---|
name |
string |
Yes | Human-readable name (translatable) |
token |
string |
Yes | Token identifier (colon-separated path) |
value |
string |
No | Sample or default value |
children |
object |
No | Nested child tokens (same structure) |
Token path convention¶
Tokens use colon-separated paths that mirror the tree structure:
The list builder wraps these in a raw token format like
[template:root-key:child-key:leaf] for use in template expressions.
Merging across modules¶
When multiple modules define tokens for the same Model Owner, trees are deep merged. For example, if module A defines:
my_tokens:
model_owner: my_owner
tokens:
config:
name: Config
token: config
children:
global:
name: Global
token: config:global
And module B defines:
more_tokens:
model_owner: my_owner
tokens:
config:
name: Config
token: config
children:
local:
name: Local
token: config:local
The merged result will have config with both global and local children.
Real-world example¶
From eca_ng.modeler_api.template_tokens.yml:
eca:
model_owner: eca
tokens:
eca-template:
name: 'ECA Templates'
token: eca-template
children:
config:
name: 'Configuration'
token: 'eca-template:config'
children:
global:
name: 'Global'
token: 'eca-template:config:global'
children:
value:
name: 'Value'
token: 'eca-template:config:global:value'
children:
VALUE:
name: 'Value'
token: 'eca-template:config:global:value:VALUE'
value: 'Configurable value'
Best practices¶
Contexts¶
- Define a base context with commonly used plugins, then create specialized contexts that include the base.
- Keep contexts focused -- it's better to have many small contexts than one giant one.
- Use meaningful, descriptive
topicvalues since they appear in the modeler UI.
Dependencies¶
- Use wildcards sparingly -- overly broad patterns can be confusing.
- Only define dependencies when there is a genuine technical constraint (e.g., a form action only works during form build events).
- Test dependency rules by switching contexts in the modeler UI.
Template tokens¶
- Follow the colon-separated path convention consistently.
- Provide meaningful
valuedefaults for leaf tokens to help users understand what the token represents. - Group related tokens under common parent nodes for better organization.
Alter hooks¶
All three YAML-based plugin types support alter hooks for programmatic modifications:
/**
* Implements hook_modeler_api_context_info_alter().
*/
function my_module_modeler_api_context_info_alter(array &$definitions): void {
// Add a plugin to an existing context.
if (isset($definitions['eca_base'])) {
$definitions['eca_base']['components']['element']['plugins'][] = 'my_custom_action';
}
}
/**
* Implements hook_modeler_api_dependency_info_alter().
*/
function my_module_modeler_api_dependency_info_alter(array &$definitions): void {
// Modify dependency rules.
}
/**
* Implements hook_modeler_api_template_token_info_alter().
*/
function my_module_modeler_api_template_token_info_alter(array &$definitions): void {
// Modify template token definitions.
}