YAML inherit and include
This page describes the Magnolia-specific directives !inherit
,
!include
and !override
. With these directives, you can reuse
YAML file-based configurations. !include
allows you to reuse an
arbitrary resource, whereas !inherit
is useful for
extending a definition.
YAML include
Use !include
to add a reusable chunk. Include a YAML fragment one level
below your new definition, or include a complete YAML definition
on top of your new definition. You can also
modify the included part of the definition.
Reference the file you want to include by its
resource path. The path to such a resource
has the following pattern:
/<module-name>/path/to/the/reusable/chunk.yaml
.
Typically, you include YAML snippets that are not proper
definitions. Do not add snippets to folders that are meant for
definitions (templates, dialogs, apps). Instead, add these snippets
to a folder that is not scanned (for instance, |
If your |
Syntactic variants of the directive
The !include
directive has existed since Magnolia 5.4, which introduced
configuration by YAML. With the release of 5.5.6, the directive syntax
has changed slightly. While the old syntax still works, the new one
makes it possible to modify and override the included part of the
definition. The new syntax uses a colon instead of a space between
!include
and the path to the resource.
Syntax | Requires version | Functions | |
---|---|---|---|
Deprecated syntax |
|
Magnolia 5.4+ |
|
New syntax |
|
Magnolia 5.5.6+ |
Generic recipe
-
Prepare a fragment that can be reused in many item definitions.
-
Include a resource with the
!include
directive. The included resource can contain a fragment or a complete definition. -
Modify parts of the included definition.
Example definitions
Simple include
Include one tab and all the action definitions in a dialog definition.
This example works with both the old (deprecated) and the new syntax. |
Includable files
name: tabCategories
label: Categories
fields:
- name: categories
label: Categories
class: info.magnolia.ui.form.field.definition.MultiValueFieldDefinition
label: Select category
field:
name: linkField
class: info.magnolia.ui.form.field.definition.LinkFieldDefinition
targetWorkspace: category
appName: categories
identifierToPathConverter:
class: info.magnolia.ui.form.field.converter.BaseIdentifierToPathConverter
- name: blackOrWhite
label: Black or white
class: info.magnolia.ui.form.field.definition.SelectFieldDefinition
options:
- name: black
value: black
selected: true
label: Black
- name: white
value: white
label: White
commit:
class: info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition
cancel:
class: info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition
A dialog file with includes
form:
label: another-component
tabs:
- name: tabMain
label: Main
fields:
- name: title
label: Text
class: info.magnolia.ui.form.field.definition.TextFieldDefinition
label: Title
# an include within a list, add a complete tab
- !include:/module-a/includes/categorization-tab.yaml
# an include within a map, add the actions for the root (map) item "actions"
actions: !include:/module-a/includes/common-actions.yaml
Include and modify a fragment
Include one tab and all the action definitions in a dialog definition. Additionally, modify the included parts of the definition.
This example works only with the new syntax (see syntactic variants). |
Includable files
name: tabCategories
label: Categories
fields:
- name: categories
label: Categories
class: info.magnolia.ui.form.field.definition.MultiValueFieldDefinition
label: Select category
field:
name: linkField
class: info.magnolia.ui.form.field.definition.LinkFieldDefinition
targetWorkspace: category
appName: categories
identifierToPathConverter:
class: info.magnolia.ui.form.field.converter.BaseIdentifierToPathConverter
- name: blackOrWhite
label: Black or white
class: info.magnolia.ui.form.field.definition.SelectFieldDefinition
options:
- name: black
value: black
selected: true
label: Black
- name: white
value: white
label: White
commit:
class: info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition
cancel:
class: info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition
A dialog file with includes
form:
label: lazy-component
tabs:
# an include within a list, add a complete tab
- !include:/module-a/includes/categorization-tab.yaml
label: Yo! 1-tab-only!
fields:
# modify properties of the field blackOrWhite, which comes from the include
- name: blackOrWhite
label: Choose color
# an include within a map, add the actions for the root (map) item "actions"
actions: !include:/module-a/includes/common-actions.yaml
# add another action to those imported from the include
doit:
label: Same as cancel
class: info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition
-
Line 6: Modify the label of the included tab.
-
Lines 9 and 10: Modify the label of the
blackOrWhite
field from the include. -
Lines 14 to 16: Add another action to the imported actions.
Include a complete file and modify
Create a dialog based on a dialog from the basic
page template of the
MTK module. Override its second tabMeta
tab. This is similar to the
example in the Modifying reused configuration section,
but here you use !include
instead of !inherit
.
!include:/mtk/dialogs/pages/basic.yaml
form:
tabs:
- name: tabMeta
fields: !override
YAML inherit
With this directive, you can inherit from an existing registered definition item in order to create a new definition item. Registered items can originate from YAML files, JCR configurations or even Blossom Java code.
It is not a good idea to inherit from a definition that resides in the same module as the dependent one. Module files are loaded in order of discovery, which can vary over time. This means that after one reload, a definition might work while the next time you edit the definition or restart your application, it may fail to discover an intra-modular dependency and to load correctly. Due to this behavior, you should not create such dependencies as they are inherently unstable. |
You can inherit only at the root level, which means you can inherit a complete app but not a subapp. Modify the new item according to your needs.
Registered definition items are known to a registry and can be seen in the Definitions app. Every registered definition item has an identifier that is unique among all items of the same type within their registry. Some of the items are defined by name, others by ID. To inherit an item, reference it by its identifier.
Items are inherited along with their state as known by the registry. For instance, if an item has been decorated, the registry knows its decorated state. Inheriting a decorated item means inheriting the decorated state of the item.
Item definition type | Identifier type | Example identifier |
---|---|---|
ID |
|
|
ID |
|
|
Name |
|
|
Name |
|
|
Name |
|
Module dependencies due to inherit
When using !inherit
, you may rely on a definition item that is
configured in another module. In this case, you must take care of the
loading order. If you rely on another module, make sure it is loaded
upfront. Use module dependencies to define the loading order of the
modules.
The module dependencies define the order in which modules are loaded
during startup. For example, if module-a
depends on module-b
,
module-b
will be loaded before module-a.
The order becomes
important, for example, if both module-a
and module-b
decorate the
same definition or if module-a
inherits a definition from module-b
.
Module dependencies can be defined within a module descriptor. |
Generic recipe
-
On the first line of your YAML definition, use the
!inherit
directive followed by a colon and the identifier of the definition you want to inherit from. -
Modify the inherited definition.
Example definitions
Inherit and override a renderer
A new definition
!inherit:freemarker
contentType: application/json
The new renderer named json
inherits everything from the freemarker
renderer but has different contentType
.
Inherit and override a template definition
The original definition you inherit from
title: a-component
renderType: freemarker
templateScript: /module-a/templates/components/a-component.ftl
dialog: module-a:components/a-component
modelClass: info.magnolia.module.jsmodels.rendering.JavascriptRenderingModel
parameters:
color: blue
size: 50
A new definition that inherits
!inherit:module-a:components/a-component
title: b-component
description: This is a b-bombastic component to test cool YAML features!
subtype: dummy-components
parameters: !override
-
Line 1: Inherit.
-
Line 2: Override the
title
property. -
Lines 3 and 4: Add more properties.
-
Line 5: Suppress the
parameters
property.
The module descriptor of module-b
version: 1.0
dependencies:
module-a:
version: 1.0/*
By setting this dependency, we make sure that module-a
is loaded
before module-b
. As a result, b-component
, which depends on
a-component
, can be initialized properly.
Modifying reused configuration
Reused configuration originating from !inherit
or !include
(when using the new !include
syntax) can be
modified. You can:
-
Add and modify properties originating from
!include
or!inherit
. This will merge the included or inherited node with the modifications. -
Use
!override
to completely ignore the properties of an inherited or included node. As a consequence, you have to add properties to the given node.
YAML override
The |
Example definitions
A definition to inherit or include
title: L page
templateScript: /mtk/templates/pages/basic.ftl
renderType: freemarker
dialog: module-a:pages/l-page
visible: true
areas:
main:
availableComponents:
textImage:
id: mtk:components/textImage
teaser:
id: mtk:components/teaser
image:
id: mtk:components/image
link:
id: mtk:components/link
Inherit
!inherit:module-a:pages/l-page
title: XXL page
dialog: module-a:pages/xxl-page
areas:
main:
availableComponents:
html:
id: mtk:components/html
The resulting definition merges the inherited definition and the
modifications area, rendering five available components in the main
area.
Inherit and override
!inherit:module-a:pages/l-page
title: XS page
dialog: module-a:pages/xs-page
areas:
main:
availableComponents: !override
link:
id: mtk:components/html
The resulting definition ignores all the properties of availableComponents
in the inherited definition, rendering only one available component in the main
area.
Overriding list items
Due to the syntax of a YAML list, you cannot apply |
Example definitions
A definition to inherit or include
form:
label: Page properties
tabs:
- name: tabMain
label: L page
fields:
- name: title
class: info.magnolia.ui.form.field.definition.TextFieldDefinition
i18n: true
label: title
- name: navigationTitle
class: info.magnolia.ui.form.field.definition.TextFieldDefinition
i18n: true
label: navigation title
- name: windowTitle
class: info.magnolia.ui.form.field.definition.TextFieldDefinition
i18n: true
label: window title
- name: tabMeta
label: Meta Data
fields:
- name: keywords
class: info.magnolia.ui.form.field.definition.TextFieldDefinition
i18n: true
label: keywords
rows: 3
- name: description
class: info.magnolia.ui.form.field.definition.TextFieldDefinition
i18n: true
label: description
rows: 5
actions:
commit:
class: info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition
cancel:
class: info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition
Both tabs
and fields
are defined here as a list. To define these
properties, you can also use the map syntax.
Include and override
!include:/module-a/dialogs/pages/l-page.yaml
form:
tabs:
tabMeta: !override
tabMain:
fields:
title: !override
required: true
class: info.magnolia.ui.form.field.definition.RichTextFieldDefinition
label: Title ...
To apply !override
to the tabMeta
tab and the title
field, we use here
the map syntax.
Preserving the order of nodes
The order of nodes as defined in a decoration via !override
is
preserved. This is useful especially if the only change needed to the
existing configuration of nodes is their order. Previously, when
providing a new configuration with !override
, the configuration would be
picked up by the system, but any change in the order of the nodes (at
the level of the !override
) would not be respected.
For example, the list view in the workbench of the Tours app may be
adjusted with the following definition decoration placing the path
column before the name
column:
subApps:
browser:
workbench:
contentViews:
list:
columns: !override
path:
name:
- Related topics