Overview
Layout builder
Layouts are identified by a unique textual identifier we call a "handle".
By default, the handle is usually the currently matched route's name.
For example, if we visited a route named as:
- route_name
- route.name
- route-name
The expected handle would be "route.name".
Important
The route name is normalized, which means characters _, - are converted to dots (.), spaces
are removed and the resulting text is converted to lowercase.
The controller must use a page renderer to return a page result. The page renderer accepts optional parameters, like a list of handles and a rendering context which it then uses to configure the layout builder.
If not explicitly specified, page renderer will use the current route name as the handle.
The builder will accept the handles given by the page renderer and will search for all possible locations of the handles, depending on the theme and the area currently in.
Important
Layout file names must end with .amarant-layout.yml.
Layout directories
Application modules
Resources/{area}/layout
Where {area} is one of: frontend, backend.
Themes
layout/{module_name}
Where {module_name} is a particular application module's name.
The default layout, default.amarant-layout.yml, should be placed in layout subdirectory.
Example
If a route named route_name is defined in a module called Vendor_ModuleName inside the code project directory,
and we're currently in the frontend area, using the Lux theme, these would be the locations of the layout files:
code/Vendor/ModuleName/Resources/frontend/layout/route.name.amarant-layout.ymlvendor/amarant2/theme-lux/layout/Vendor_ModuleName/route.name.amarant-layout.yml
If none of the layouts found so far have set the no-default directive to true, first it would
load all default.amarant-layout.yml layouts that exist in application modules,
ordered by the module dependency chain. The default layout is intended to be a base layout
for all others.
Then it would continue loading the other layouts found.
In the merging process, some properties override the previous ones while some are merged or replaced recursively. Layouts can inherit a layout and containers can be moved into other containers or removed entirely.
The page renderer passes the resulting builder to the layout renderer which then renders it to HTML.
Layout renderer
Note
If the layout cache is enabled and the layout exists in the cache, the building process is skipped.
Accepts the layout builder and a rendering context as parameters, builds the layout and renders it, element by element, to HTML.
Context
The rendering context is a simple data storage object that all templates in the rendering process can use to get or set data and tags.
Note
Tags are used to create page and block cache keys.
Usually, a context is set by a controller or an email renderer. For example, a product view adds the current product data model to the rendering context, so templates can use it to access product data.
Not all data is required to be put into the context as blocks can have view models which can provide data to their templates.
Elements
Container
Each container has nested content consisting of other elements, which can be containers, blocks or text. A layout has at least one container, which we call the "root container".
A container is basically just an HTML element that serves as a wrapper for its child elements. By default, its tag is "div" and can be changed.
Block
A block is an element that defines a template to be rendered.
Optionally, it can have a view model defined, which must be a class
implementing the Amarant\Framework\Contract\View\ViewModel\ViewModelInterface. The block's template
can then access the view model with the viewModel variable.
A container can also define a view model. The purpose of this is that its child blocks will be automatically injected with it, unless they don't specify a view model themselves.
Text
A text element is just static text wrapped in a defined tag which is "div" by default.
Component
This element mounts a Vue or React component.
Pending reimplementation
This feature is pending reimplementation from version 1.0.
Fragments
Fragments are not rendered automatically. Instead, they can be fetched from
the rendering context using the getFragments and getFragmentContent methods.
Fragments are useful for embedding content in a block's template. For example, content can
be added to the beginning or end of a page's head element by tagging a fragment
with page-layout-head-start or page-layout-head-end tags, respectively.
Important
When inheriting layouts, child fragments automatically override parent fragments if they have the same id.
This is not the case as with elements, where this kind of behavior would trigger an error.
Click here to see how a fragment is placed into a layout.
Rendering process
Note
If the page cache is enabled and the page exists in the cache, the rendering process is skipped.
All elements are iterated through, generating a single text result.
This becomes the main content and is wrapped together with the application state into a body tag.
If the layout has HTML head defined, page head is rendered and both the head and the body are wrapped in an html tag.
Note
The idea behind ommiting the page head is to be able to render layouts which are only parts of a page, for example to load/refresh parts of a page via AJAX.
Events
framework_presentation_build_layout_before
Dispatched before the layout is built.
builderlayout builder instance
framework_presentation_build_layout_after
Dispatched after the layout is built.
layoutthe built layout instance
framework_presentation_render_html_before
Dispatched before the full page HTML is rendered.
attributesHTML attributes of the layout headlayoutthe built layout instance
Note
attributes can be changed by event subscribers.
framework_presentation_render_head_before
Dispatched before the head is rendered.
layoutthe built layout instancerenderingContextthe current rendering context
Note
Rendering context can be used by event subscribers to get or set data and tags.
framework_presentation_render_body_after
Dispatched after the body is rendered.
layoutthe built layout instancebodyTagtag of the body content elementbodyClassclass of the body content elementbodyAttributesattributes of the body content elementapplicationStateContentapplication state contentbodyContentbody content
Note
bodyContent can be changed by event subscribers.