Skip to content

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.yml
  • vendor/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.

  • builder layout builder instance

framework_presentation_build_layout_after

Dispatched after the layout is built.

  • layout the built layout instance

framework_presentation_render_html_before

Dispatched before the full page HTML is rendered.

  • attributes HTML attributes of the layout head
  • layout the built layout instance

Note

attributes can be changed by event subscribers.

framework_presentation_render_head_before

Dispatched before the head is rendered.

  • layout the built layout instance
  • renderingContext the 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.

  • layout the built layout instance
  • bodyTag tag of the body content element
  • bodyClass class of the body content element
  • bodyAttributes attributes of the body content element
  • applicationStateContent application state content
  • bodyContent body content

Note

bodyContent can be changed by event subscribers.