Netgen Layouts Documentation¶
Netgen Layouts is an easy and flexible way of managing all page layouts on your website. Use it to manage and maintain the website layout structure in a slick and agile but at the same time extensible way.
Note
This documentation assumes you have a working knowledge of the Symfony Framework. If you’re not familiar with Symfony, please start with reading the Quick Tour from the Symfony documentation.
Note
Netgen Layouts does not force or otherwise define where your configuration, code, or templates live. Examples in this documentation will use YAML as a configuration format, but you can ofcourse use any format available in Symfony and you can place templates in folder structure that fits your needs best.
Reference¶
Reference¶
Install instructions¶
To install Netgen Layouts, you need to have an existing Symfony full stack installation. For example, Netgen Layouts can be installed on eZ Platform, Sylius or Symfony Demo app.
Use Composer¶
Add the following to your composer.json
. During installation, you will be
asked for username and password to packagist.netgen.biz
, make sure you have
them ready:
{
"repositories": [
{ "type": "composer", "url": "https://packagist.netgen.biz" }
]
}
Execute the following from your installation root:
$ composer require netgen/block-manager-standard netgen/block-manager
Note
If you’re installing Netgen Layouts on eZ Platform, execute the following instead:
# On any eZ Platform version
$ composer require netgen/block-manager-standard netgen/block-manager-ezpublish
# On eZ Platform 1.x only (in addition to packages above)
$ composer require netgen/platform-ui-layouts-bundle
# On eZ Platform 2.x only (in addition to packages above)
$ composer require netgen/ez-admin-ui-layouts-bundle
Note
If you use Netgen Admin UI, you can also install netgen/admin-ui-layouts-bundle package and activate Netgen\Bundle\AdminUILayoutsBundle\NetgenAdminUILayoutsBundle bundle in your AppKernel to enable integration of Netgen Layouts into Netgen Admin UI.
Activate the bundles¶
Add the following bundles to your kernel:
new Knp\Bundle\MenuBundle\KnpMenuBundle(),
new FOS\HttpCacheBundle\FOSHttpCacheBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
new Netgen\Bundle\CoreUIBundle\NetgenCoreUIBundle(),
new Netgen\Bundle\ContentBrowserBundle\NetgenContentBrowserBundle(),
new Netgen\Bundle\ContentBrowserUIBundle\NetgenContentBrowserUIBundle(),
new Netgen\Bundle\BlockManagerBundle\NetgenBlockManagerBundle(),
new Netgen\Bundle\BlockManagerStandardBundle\NetgenBlockManagerStandardBundle(),
new Netgen\Bundle\BlockManagerUIBundle\NetgenBlockManagerUIBundle(),
new Netgen\Bundle\BlockManagerAdminBundle\NetgenBlockManagerAdminBundle(),
Note
If you’re installing Netgen Layouts on eZ Platform, activate the following bundles too:
// On any eZ Platform version
new Netgen\Bundle\EzPublishBlockManagerBundle\NetgenEzPublishBlockManagerBundle(),
// On eZ Platform 1.x only (in addition to bundle above)
new Netgen\Bundle\PlatformUILayoutsBundle\NetgenPlatformUILayoutsBundle(),
// On eZ Platform 2.x only (in addition to bundle above)
new Netgen\Bundle\EzPlatformAdminUILayoutsBundle\NetgenEzPlatformAdminUILayoutsBundle(),
Add the following bundle to your kernel only for dev environment:
new Netgen\Bundle\BlockManagerDebugBundle\NetgenBlockManagerDebugBundle(),
Import database tables¶
Execute the following from your installation root to import Netgen Layouts database tables:
$ php app/console doctrine:migrations:migrate --configuration=vendor/netgen/block-manager/migrations/doctrine.yml
Configuration¶
Starting from version 1.12 of eZ Platform, there is a configuration that caches 404 pages with a low TTL to increase performance. This cache interferes with Netgen Layouts REST API endpoints which return 404 responses in their normal operation workflow.
To disable cache on Netgen Layouts API endpoints, add the following options to
app/config/config.yml
under the match
key of fos_http_cache
configuration responsible for caching 404 pages:
attributes:
_route: "^(?!ngbm_api_|ngcb_api_)"
The whole match
configuration should then look like this:
match:
attributes:
_route: "^(?!ngbm_api_|ngcb_api_)"
match_response: '!response.isFresh() && response.isNotFound()'
Routing and assets¶
Add the following routes to your main routing config file:
netgen_block_manager:
resource: "@NetgenBlockManagerBundle/Resources/config/routing.yml"
prefix: "%netgen_block_manager.route_prefix%"
netgen_content_browser:
resource: "@NetgenContentBrowserBundle/Resources/config/routing.yml"
prefix: "%netgen_content_browser.route_prefix%"
Run the following from your installation root to symlink assets:
$ php app/console assets:install --symlink --relative
Note
If you’re installing Netgen Layouts on eZ Platform, you also need to dump Assetic assets:
$ php app/console assetic:dump
Adjusting your full views¶
All of your full views need to extend ngbm.layoutTemplate
variable (see
below for example). If layout was resolved, this variable will hold the name of
the template belonging to the resolved layout. In case when layout was not
resolved, it will hold the name of your main pagelayout template (the one your
full views previously extended). This makes it possible for your full view
templates to be fully generic, that is, not depend whether there is a resolved
layout or not:
{% extends ngbm.layoutTemplate %}
{% block content %}
{# My full view code #}
{% endblock %}
Adjusting your base pagelayout template¶
To actually display the resolved layout template in your page, you need to
modify your main pagelayout template to include a Twig block named layout which
wraps everything between your opening and closing <body>
tag:
<body>
{% block layout %}
{# Other Twig code #}
{% block content %}{% endblock %}
{# Other Twig code #}
{% endblock %}
</body>
There are two goals to achieve with the above Twig block:
- If no layout could be resolved for current page, your full view templates will just keep on working as before
- If layout is resolved, it will use the
layout
block, in which casecontent
Twig block and other Twig code will not be used. You will of course need to make sure that in this case, all your layouts have a full view block in one of the zones which will display yourcontent
Twig block from full view templates
Configuring the pagelayout¶
As written before, Netgen Layouts replaces the pagelayout in your full views
with its dynamic variable called ngbm.layoutTemplate
. It basically injects
itself between rendering of your full view and your pagelayout. Since your full
views do not extend from your main pagelayout any more, Netgen Layouts needs to
know what was your original full view to fallback to it. You can configure your
pagelayout in Netgen Layouts config like this:
netgen_block_manager:
pagelayout: '@App/pagelayout.html.twig'
Note
If you’re installing Netgen Layouts on eZ Platform, your main pagelayout is taken from existing eZ Platform configuration, so you can skip this step.
Update Varnish VCL configuration¶
To enable caching and later cache clearing of block and layout HTTP caches, you
will need to use Varnish. To make the cache clearing work, you need to modify
your Varnish VCL and add the following rules somewhere in your vcl_recv
function.
Note
If you’re using eZ Platform and the VCL supplied by it, the best place
to put this is in ez_purge
function (which is called from vcl_recv
),
right after if (req.http.X-Location-Id) { ... }
block.
For Varnish 3:
if (req.http.X-Layout-Id) {
ban( "obj.http.X-Layout-Id ~ " + req.http.X-Layout-Id);
if (client.ip ~ debuggers) {
set req.http.X-Debug = "Ban done for layout with ID " + req.http.X-Layout-Id;
}
error 200 "Banned";
}
if (req.http.X-Block-Id) {
ban( "obj.http.X-Block-Id ~ " + req.http.X-Block-Id);
if (client.ip ~ debuggers) {
set req.http.X-Debug = "Ban done for block with ID " + req.http.X-Block-Id;
}
error 200 "Banned";
}
For Varnish 4 and later:
if (req.http.X-Layout-Id) {
ban("obj.http.X-Layout-Id ~ " + req.http.X-Layout-Id);
if (client.ip ~ debuggers) {
set req.http.X-Debug = "Ban done for layout with ID " + req.http.X-Layout-Id;
}
return (synth(200, "Banned"));
}
if (req.http.X-Block-Id) {
ban("obj.http.X-Block-Id ~ " + req.http.X-Block-Id);
if (client.ip ~ debuggers) {
set req.http.X-Debug = "Ban done for block with ID " + req.http.X-Block-Id;
}
return (synth(200, "Banned"));
}
Configuration reference¶
Layout type configuration¶
The following lists all available layout type configuration options:
netgen_block_manager:
layout_types:
# Layout type identifier
my_layout:
# The switch to enable or disable showing of the layout type in the interface
enabled: true
# Layout type name, required
name: 'My layout'
# The full path to layout icon
icon: '/path/to/icon/my_layout.svg'
# A collection of zones available in the layout type, required
zones:
# Zone identifier
left:
# Zone name, required
name: 'Left'
# List of block definitions which are allowed in the zone
allowed_block_definitions: []
right:
name: 'Right'
allowed_block_definitions: [title]
Block definition configuration¶
The following lists all available block definition configuration options:
netgen_block_manager:
block_definitions:
# Block definition identifier
my_block:
# The switch to enable or disable showing of all block types
# related to block definition in the interface
enabled: true
# Identifier of a handler which the block definition will use.
# The value used here needs to be the same as the identifier
# specified in handler tag in Symfony DIC.
# If undefined, the handler with the same identifier as the
# block definition itself will be used.
handler: ~
# Block definition name, required
name: 'My block'
# The full path to block definition icon
icon: '/path/to/icon/my_block.svg'
# Specifies if the block will be translatable once created
translatable: false
# The list of collections the block has. Only one collection named
# "default" is supported for now. Omit the config to disable the collection.
collections:
default:
# The list of valid items for the collection. Use null to
# allow all items, an empty array to disable adding manual
# items, and a list of items to limit the collection to
# to only those items.
valid_item_types: null
# The list of valid query types for the collection. Use null to
# allow all query types, an empty array to disable dynamic collections,
# and a list of query types to limit the collection to
# only those query types.
valid_query_types: null
# This controls which forms will be available to the block.
# You can either enable the full form, or content and design forms.
# If full form is enabled, all block options in the right sidebar
# in the Block Manager app will be shown at once, otherwise,
# Content and Design tabs will be created in the right sidebar
forms:
full:
enabled: true
type: Netgen\BlockManager\Block\Form\FullEditType
design:
enabled: false
type: Netgen\BlockManager\Block\Form\DesignEditType
content:
enabled: false
type: Netgen\BlockManager\Block\Form\ContentEditType
# The list of all view types in a block definition, required
view_types:
# View type identifier
my_view_type:
# Switch to control if the view type is shown in the interface or not
enabled: true
# View type name, required
name: 'My view type'
# The list of allowed item view types for this block view type
item_view_types:
# Item view type identifier
my_item_view_type:
# Switch to control if the item view type is shown in the interface or not
enabled: true
# Item view type name, required
name: 'My item view type'
# Use this configuration to control which block parameters will be displayed
# when editing a block in specified view type. Use null to display all
# parameters, an empty array to hide all parameters and a list of parameter
# names to list specific parameters to show. You can also prefix the parameter
# with exclamation mark to exclude it.
valid_parameters: null
Block type and block type group configuration¶
The following lists all available block type and block type group configuration options:
netgen_block_manager:
block_types:
# Block type identifier
my_block_type:
# The switch to enable or disable showing the block type in the interface
enabled: true
# Block type name, if undefined, will use the name of a block definition
# with the same identifier as the block type itself.
name: ~
# The full path to block type icon
icon: '/path/to/icon/my_block_type.svg'
# Block definition identifier of the block type, if undefined, will use the
# block definition with the same identifier as the block type itself.
definition_identifier: ~
# Default values for the block
defaults:
# Default name (label) of the block
name: ''
# Default view type of the block. If empty, will use the first available view type.
view_type: ''
# Default item view type of items inside the block. If empty, will use the first
# available item view type in regards to chosen block view type.
item_view_type: ''
# Default values for block parameters
parameters:
param1: value1
param2: value2
block_type_groups:
# Block type group identifier
my_group:
# The switch to enable or disable showing the block type group in the interface
enabled: true
# Block type group name, required
name: 'My group'
# List of block types to show inside the group
block_types: [my_type_1, my_type_2]
Query type configuration¶
The following lists all available query type configuration options:
netgen_block_manager:
query_types:
# Query type identifier
my_query_type:
# Identifier of a handler which the query type will use.
# The value used here needs to be the same as the identifier
# specified in handler tag in Symfony DIC.
# If undefined, the handler with the same identifier as the
# query type itself will be used.
handler: ~
# Query type name, required
name: 'My query type'
# This controls the PHP class for the form which is used to
# edit the query type in the Block Manager app interface
forms:
full:
enabled: true
type: Netgen\BlockManager\Collection\Query\Form\FullEditType
Item configuration¶
The following lists all available item configuration options:
netgen_block_manager:
items:
# The list of value types available to build items from
value_types:
# Value type identifier
my_value_type:
# Value type name, required
name: 'My value type'
# The switch to enable or disable showing the value type in the interface
enabled: true
View configuration¶
The complete configuration reference for the view layer is documented in a dedicated chapter.
Design configuration¶
The following lists all available design configuration options:
netgen_block_manager:
# The list of all designs available in the system
design_list:
# Key is the design identifier, while value is the list of all
# themes available for the design. Note that ``standard`` theme
# is automatically included as a fallback and there's no need to
# specify it
my_design: [theme1, theme2]
# Specifies which design, from the list of configured designs, is currently active
design: my_design
Tip
In eZ Platform integration, currently active design is siteaccess aware, meaning, you can use configuration similar to this:
netgen_block_manager:
system:
cro:
design: my_design
eng:
design: my_other_design
Administration interface configuration¶
The following lists all available configuration options for Netgen Layouts admin interface:
netgen_block_manager:
admin:
# The list of JavaScript files which will be injected into admin interface
javascripts:
- /path/to/script1.js
- /path/to/script2.js
# The list of stylesheets which will be injected into admin interface
stylesheets:
- /path/to/style1.css
- /path/to/style2.css
Block Manager app interface configuration¶
The following lists all available configuration options for Netgen Layouts Block Manager interface:
netgen_block_manager:
app:
# The list of JavaScript files which will be injected into Block Manager interface
javascripts:
- /path/to/script1.js
- /path/to/script2.js
# The list of stylesheets which will be injected into Block Manager interface
stylesheets:
- /path/to/style1.css
- /path/to/style2.css
Other configuration¶
The following lists assorted configuration options that do not fit in other categories:
netgen_block_manager:
# This flag activates debug mode in Netgen Layouts. This flag is primarily used
# for development of Netgen Layouts themselves and is not useful in project context
# and should be kept disabled
debug: false
# This configures the main pagelayout of your app which resolved layout templates
# will extend and which will be used as a fallback if no layout is resolved
pagelayout: '@NetgenBlockManager/empty_pagelayout.html.twig'
# Generic configuration used for specifying various API keys for 3rd party services.
# Currently used only internally, and cannot be extended.
api_keys:
# API key used for displaying a Google Maps map inside the Maps block
google_maps: 'foo'
View layer¶
All entities in Netgen Layouts (layouts, blocks, mapping rules, forms) are rendered through the same API called the view layer. View layer revolves around three concepts:
- View
- Match configuration
- View context
View¶
All entities in Netgen Layouts specify their own view, which defines what
variables will be available in the Twig templates when the entity is rendered.
For example, layout view (identified by layout_view
identifier), specifies
that all layout templates will have a variable called layout
, which will
hold the currently rendered template, while item view (identified by
item_view
identifier), specifies that all block item templates will have two
variables: item
, which holds the currently rendered block item, and
view_type
, which will hold the item view type with which the item is
rendered.
There are a handful predefined views available in Netgen Layouts, but most interesting ones are ofcourse views for rendering layouts, blocks and block items. The other ones are used by administration interface of Netgen Layouts (list of mappings, layouts and shared layouts) and are rarely needed, e.g. when developing custom mapping targets and conditions.
Match configuration¶
Match configuration is a single rule which specifies which template will be rendered for a specific view when all configured conditions are met. Those conditions are called matches, and services which perform the matching process are called matchers.
View context¶
View context is a set of match configuration rules and each view context is used in different parts of Netgen Layouts. View contexts are what makes it possible for example to use different templates for frontend and backend for your layout types and blocks. Match configurations in a view context are processed sequentially and template from first configuration that matches the rules will be used to render the value.
Netgen Layouts uses five view contexts to render its’ templates: default
for
rendering the frontend templates, ajax
for rendering collection pages
rendered view AJAX, api
for rendering the Block Manager app templates and
admin
and value
view contexts for rendering the administration
interface.
Configuring the view layer¶
The following configuration shows an example on how to configure layout_view
and block_view
views, specifying some match rules in two different view
contexts (default
and api
).
netgen_block_manager:
view:
# The identifier of the view
layout_view:
# The name of the view context
default:
# The identifier of a match configuration (unused, but needs to specified in YAML)
# The first match configuration for which all conditions match will be picked up and used to render the view
layout_1:
# The template that will be used when conditions specified below match
template: "@App/layout/layout_1.html.twig"
# The list of custom parameters that will be injected in the template if the conditions specified below match
parameters:
param1: value1
param2: value2
# The list of conditions that will need to match for this rule to be used
match:
layout\type: layout_1
layout_2:
template: "@App/api/layout/layout_2.html.twig"
match:
layout\type: layout_2
block_view:
api:
title:
template: "@App/block/title.html.twig"
match:
block\definition: title
text:
template: "@App/api/block/text.html.twig"
match:
block\definition: text
# This configuration is used to specify a fallback template for
# a view/context combination. It is used when none of match rules
# were able to select the template. It is implemented as a separate
# configuration in order not to depend on bundle order and priority of
# configuration when merging Symfony semantic config.
default_view_templates:
# The identifier of the view
block_view:
# Key is the name of the view context, and the value is a
# default template
my_context: '@App/block/block.html.twig'
Tip
If you use eZ Platform, view configuration is siteaccess aware. This means you can have different templates for different siteaccesses or siteaccess groups for the same block views or layout types.
For example, you can use the following config to use two different templates
for my_layout
layout type for eng
and cro
siteaccesses:
netgen_block_manager:
system:
eng:
view:
layout_view:
default:
my_layout:
template: "@App/layouts/my_layout_eng.html.twig"
match:
layout\type: my_layout
cro:
view:
layout_view:
default:
my_layout:
template: "@App/layouts/my_layout_cro.html.twig"
match:
layout\type: my_layout
Tip
For parameters that you inject into your templates, you can use expression
language to build dynamic parameters. Expression language currently has one
variable available named view
which holds the view object which is being
displayed. To use the expression language, prefix the parameter value with
@=
:
block\my_block:
template: '@App/my_template.html.twig'
match:
block\definition: my_block
parameters:
custom_param: '@=view.parameter("custom_param")'
Custom view contexts¶
If, for some reason, you would want to render some layouts or blocks by hand in your PHP code, you can create custom view contexts (and custom templates, ofcourse) on the fly and use them directly when rendering the layouts or blocks, without touching and compromising the existing frontend templates.
So for example, to render a block view with your custom view context called
my_context
, you would define a configuration similar to this:
netgen_block_manager:
view:
block_view:
my_context:
title:
template: "@App/block/my_context/title.html.twig"
match:
block\definition: title
and then somewhere in your controller:
$block = $this->get('netgen_block_manager.api.service.block')->loadBlock(42);
return $this->get('netgen_block_manager.view.builder')->buildView($block, 'my_context');
Note
You don’t need to return Symfony Response
object from your controllers,
instead, you can just return the built view object. Netgen Layouts will
render it on the fly with a built in event listener.
List of built in views¶
The following lists all built in views with their identifiers, supported interfaces and the list of variables available in the rendered template.
block_view
¶
This view is used to render entities implementing
Netgen\BlockManager\API\Values\Block\Block
interface.
Variable name | Description |
---|---|
block |
The block which is being rendered |
layout_view
¶
This view is used to render entities implementing
Netgen\BlockManager\API\Values\Layout\Layout
interface.
Variable name | Description |
---|---|
layout |
The layout which is being rendered |
Warning
Frontend templates for layouts (default
context) are an exception and
are not rendered through the Netgen Layouts view layer. Instead, they are
rendered by extending from a special ngbm.layoutTemplate
variable,
available in your full view templates. Because of that, in frontend layout
templates, layout
variable is not available. Instead, the rendered
layout is accessed by using ngbm.layout
variable.
Warning
This view reuses backend templates for layout types to render the layouts
themselves. For this reason, those templates sometimes receive the
layout
variable, and sometimes layout_type
variable, based on what
is being rendered. Your own templates need to be aware of this and act
accordingly, i.e. check for existence of both variables prior using them.
item_view
¶
This view is used to render entities implementing
Netgen\BlockManager\Item\ItemInterface
interface.
Variable name | Description |
---|---|
item |
The item which is being rendered |
view_type |
Item view type that the item is being rendered with |
parameter_view
¶
This view is used to render entities implementing
Netgen\BlockManager\Parameters\ParameterValue
interface.
Variable name | Description |
---|---|
parameter |
The parameter which is being rendered |
Note
While rendering other views will throw an exception if there is no template
match in requested view context, this view will fallback to the default
view context. This is due to the fact that in most of the cases, rendering
a block parameter will look exactly the same in the backend and in the
frontend.
This makes it possible to only specify one match configuration rule (in the
default
context) and one template to render the parameter in any view
context.
placeholder_view
¶
This view is used to render entities implementing
Netgen\BlockManager\API\Values\Block\Placeholder
interface.
Variable name | Description |
---|---|
placeholder |
The placeholder which is being rendered |
block |
The block to which the rendered placeholder belongs |
rule_condition_view
¶
This view is used to render entities implementing
Netgen\BlockManager\API\Values\LayoutResolver\Condition
interface.
Variable name | Description |
---|---|
condition |
The condition which is being rendered |
rule_target_view
¶
This view is used to render entities implementing
Netgen\BlockManager\API\Values\LayoutResolver\Target
interface.
Variable name | Description |
---|---|
target |
The target which is being rendered |
rule_view
¶
This view is used to render entities implementing
Netgen\BlockManager\API\Values\LayoutResolver\Rule
interface.
Variable name | Description |
---|---|
rule |
The rule which is being rendered |
form_view
¶
This view is used to render entities implementing
Symfony\Component\Form\FormView
interface.
Variable name | Description |
---|---|
form |
The Symfony form view which is being rendered |
form_object |
The underlying Symfony form from which the view was built |
layout_type_view
¶
Sometimes, in Block Manager app, it is needed to render an empty template for a
layout type, for example in the interface for changing the layout type of a
layout. This view is used to render layout types. It renders objects of
Netgen\BlockManager\Layout\Type\LayoutTypeInterface
type.
Variable name | Description |
---|---|
layout_type |
The layout type which is being rendered |
Warning
This view reuses backend templates for layouts to render the types
themselves. For this reason, those templates sometimes receive the
layout
variable, and sometimes layout_type
variable, based on what
is being rendered. Your own templates need to be aware of this and act
accordingly, i.e. check for existence of both variables prior using them.
List of built in matchers¶
The following lists all built in view matchers. As a rule of thumb, all matchers accept either a scalar or an array of scalars as their value. If an array is provided, the matcher will match if any of the values in the provided array is matched.
Note
While you can use all matchers in all views, most of the combinations do not
make sense and will simply not match. For example, using layout\type
matcher in block_view
view will never match since block_view
renders
a block, while layout\type
matches on layout type of a rendered layout.
block\definition
¶
Matches on block definition of the rendered block. Used in block_view
view.
netgen_block_manager:
view:
block_view:
default:
title:
template: '@App/block/title.html.twig'
match:
block\definition: title
block\view_type
¶
Matches on view type of the rendered block. Used in block_view
view.
Tip
This matcher is usually used with block\definition
matcher to specify
for which exactly block and view type will the template be used.
netgen_block_manager:
view:
block_view:
default:
title\title:
template: '@App/block/title.html.twig'
match:
block\definition: title
block\view_type: title
block\locale
¶
Matches on locale of the rendered block. Used in block_view
view.
Tip
This matcher is usually used with block\definition
matcher to specify
for which exactly block type will the template be used.
netgen_block_manager:
view:
block_view:
default:
title\hr_HR:
template: '@App/block/title/hr_HR.html.twig'
match:
block\definition: title
block\locale: hr_HR
block\collection\identifier
¶
Matches on a collection identifier of the rendered collection page. Used in block_view
view.
Tip
This matcher is usually used in ajax
block view context to specify the
template for the collection page rendered via AJAX block view controller.
netgen_block_manager:
view:
block_view:
ajax:
title\ajax\featured:
template: '@App/block/title/ajax/featured.html.twig'
match:
block\definition: title
block\collection\identifier: featured
layout\type
¶
Matches on layout type of the rendered layout. Used in layout_view
and layout_type_view
views.
netgen_block_manager:
view:
layout_view:
default:
layout_3:
template: '@App/layout/layout_3.html.twig'
match:
layout\type: layout_3
item\value_type
¶
Matches on the type of rendered item. Used in item_view
view.
netgen_block_manager:
view:
item_view:
default:
my_item:
template: '@App/item/my_item.html.twig'
match:
item\value_type: my_item
item\view_type
¶
Matches on item view type of the rendered item. Used in item_view
view.
Tip
This matcher is usually used with item\value_type
matcher to specify
for which exactly item and item view type will the template be used.
netgen_block_manager:
view:
item_view:
default:
my_item\standard_with_intro:
template: '@App/item/my_item.html.twig'
match:
item\value_type: my_item
item\view_type: standard_with_intro
parameter\type
¶
Matches on type of the rendered parameter. Used in parameter_view
view.
netgen_block_manager:
view:
parameter_view:
default:
link:
template: '@App/parameter/link.html.twig'
match:
parameter\type: link
rule_condition\type
¶
Matches on type of the rendered condition. Used in rule_condition_view
view.
netgen_block_manager:
view:
rule_condition_view:
default:
query_parameter:
template: '@App/condition/query_parameter.html.twig'
match:
rule\condition_type: query_parameter
rule_target\type
¶
Matches on type of the rendered target. Used in rule_target_view
view.
netgen_block_manager:
view:
rule_target_view:
default:
route:
template: '@App/target/route.html.twig'
match:
rule\target_type: route
form\type
¶
Matches on type of the Symfony form which is rendered. Used in form_view
view.
Tip
This matcher is usually used with other form\*
matchers if you wish, for
example, to separate templates for rendering block create and block edit
forms.
netgen_block_manager:
view:
form_view:
default:
layout\edit:
template: '@App/layout/edit.html.twig'
match:
form\type: Netgen\BlockManager\Layout\Form\EditType
form\block\definition
¶
Matches on block definition of a block which is edited through the Symfony form.
Used in form_view
view.
netgen_block_manager:
view:
form_view:
default:
block\title\edit:
template: '@App/block/title/edit.html.twig'
match:
form\type: Netgen\BlockManager\Block\Form\FullEditType
form\block\definition: title
form\block\locale
¶
Matches on block locale of a block which is edited through the Symfony form.
Used in form_view
view.
netgen_block_manager:
view:
form_view:
default:
block\title\edit\hr_HR:
template: '@App/block/title/edit/hr_HR.html.twig'
match:
form\type: Netgen\BlockManager\Block\Form\FullEditType
form\block\definition: title
form\block\locale: hr_HR
form\query\type
¶
Matches on query type of a query which is edited through the Symfony form. Used
in form_view
view.
netgen_block_manager:
view:
form_view:
default:
query\my_query\edit:
template: '@App/query/my_query/edit.html.twig'
match:
form\type: Netgen\BlockManager\Collection\Query\Form\FullEditType
form\query\type: my_query
form\query\locale
¶
Matches on locale of a query which is edited through the Symfony form. Used in
form_view
view.
netgen_block_manager:
view:
form_view:
default:
query\my_query\edit\hr_HR:
template: '@App/query/my_query/edit/hr_HR.html.twig'
match:
form\type: Netgen\BlockManager\Collection\Query\Form\FullEditType
form\query\type: my_query
form\query\locale: hr_HR
form\config\config_key
¶
Matches on the config key of a config which is edited through the Symfony form.
Used in form_view
view.
Tip
This matcher is usually used with form\config\value_type
matcher because
most of the time, forms for rendering different aspects of value
configuration will be different.
netgen_block_manager:
view:
form_view:
default:
config\block\http_cache\edit:
template: '@App/config/block/http_cache/edit.html.twig'
match:
form\type: Netgen\BlockManager\Config\Form\EditType
form\config\value_type: Netgen\BlockManager\API\Values\Block\Block
form\config\config_key: http_cache
form\config\value_type
¶
Matches on the type of value for which the config is edited through the Symfony
form. Used in form_view
view.
Tip
This matcher is usually used with form\config\config_key
matcher because
most of the time, forms for rendering different aspects of value
configuration will be different.
netgen_block_manager:
view:
form_view:
default:
config\block\http_cache\edit:
template: '@App/config/block/http_cache/edit.html.twig'
match:
form\type: Netgen\BlockManager\Config\Form\EditType
form\config\value_type: Netgen\BlockManager\API\Values\Block\Block
form\config\config_key: http_cache
Parameter types¶
When adding a parameter to the block or a query in your block definition or a query type, you can specify the parameter name, the type of the parameter and parameter options. This is achieved through an object called parameter builder which is provided to you in your block definition or a query type.
Parameter builder has methods for working with the parameters: adding, removing and fetching the parameters as well as setting parameter options.
When adding parameters to block definitions or queries, referencing the parameter type is done by specifying FQCN of the parameter type.
Common parameter options¶
In addition to the list of options specific to each parameter type, all types
have five common options: required
, default_value
, group
, label
and constraints
.
required
¶
type: bool
, required: No, default value: false
Specifies if the parameter value is required or not.
default_value
¶
type: mixed
, required: No, default value: null
Specifies the default value of the parameter.
group
¶
type: array
of string
values, required: No, default value: array()
Specifies the parameter group. Groups are a generic concept when working with parameters. Netgen Layouts does not enforce or otherwise define how you use parameter groups. Internally, Netgen Layouts uses groups in block definitions to specify to which form (content or design) the parameter belongs and in query types to specify which parameters are advanced and hidden by default.
constraints
¶
type: array
of Symfony constraints or closures, required: No, default value: array()
This parameter specifies the list of constraints that will be applied to a parameter in addition to constraints specified by the parameter type itself. These can be useful if some of your parameters have special needs from validation.
You can provide either a list of Symfony constraints, or closures that return a constraint. Closures can be useful when you need to validate the value of a parameter against other fields in the block or query. This is achieved by providing three parameters when your closure constraint is called, respectively:
- the value of the parameter
- an array of all parameters
- the parameter definition of the parameter, which is an instance of
Netgen\BlockManager\Parameters\ParameterDefinition
An example closure constraint would be one that checks that one datetime
parameter value is larger than the other datetime
parameter value:
$builder->add(
'visible_to',
ParameterType\DateTimeType::class,
[
'constraints' => [
function ($visibleTo, array $parameters) {
$visibleFrom = $parameters['visible_from'];
if (
!$visibleFrom instanceof \DateTimeInterface ||
!$visibleTo instanceof \DateTimeInterface
) {
return;
}
return new Constraints\GreaterThan(['value' => $visibleFrom]);
},
],
]
);
label
¶
type: string
, false
or null
, required: No, default value: null
Specifies the human readable name of the parameter. In Netgen Layouts this label is for example used in Symfony forms which edit blocks or queries.
Tip
Use false
to disable parameter label in Symfony forms. If null
is
specified, the label will be generated by using Symfony translation
component from the parameter name.
List of built in parameter types¶
The following lists all parameter types built into Netgen Layouts together with the options available in each parameter type.
BooleanType
¶
Identifier | boolean |
Overridden options | |
Class | Netgen\BlockManager\Parameters\ParameterType\BooleanType |
Valid value | A boolean |
Compound\BooleanType
¶
Identifier | compound_boolean |
Available options | |
Overridden options | |
Class | Netgen\BlockManager\Parameters\ParameterType\Compound\BooleanType |
Valid value | A boolean |
This parameter is a special one in a manner that it can hold other parameters.
The main purpose of the parameter is not functional, but presentational. That is, it allows building Symfony forms that have parameters which can be shown and hidden by checking and un-checking the checkbox input.
The value of the parameter is preserved with all other parameters and its sub-parameters in a flat list, without hierarchy.
ChoiceType
¶
Identifier | choice |
Available options | |
Overridden options | |
Class | Netgen\BlockManager\Parameters\ParameterType\ChoiceType |
Valid value | One (or more) of the values specified in options option |
multiple
¶type: bool
, required: No, default value: false
Specifies if the parameter type will accept multiple values.
expanded
¶type: bool
, required: No, default value: false
If true, the parameter will be rendered as checkbox list or radio button list,
depending if multiple
option is true
or false
, respectivelly.
options
¶type: non empty array
or callable
, required: Yes
Specifies the list of values allowed in the parameter. The list of values needs to be a hash where keys represent option label and value represents option value.
If callback is used, the callback needs to return the array in the same format.
DateTimeType
¶
Identifier | datetime |
Class | Netgen\BlockManager\Parameters\ParameterType\DateTimeType |
Valid value | An object implementing DateTimeInterface from PHP core. |
EmailType
¶
Identifier | email |
Class | Netgen\BlockManager\Parameters\ParameterType\EmailType |
Valid value | A valid e-mail address |
HtmlType
¶
Identifier | html |
Class | Netgen\BlockManager\Parameters\ParameterType\HtmlType |
Valid value | A valid HTML markup |
This parameter type represents a valid HTML markup. The reason why there’s a custom parameter type is HTML filtering. This parameter type will filter all input to get a valid HTML markup which is free of potential security issues, like XSS.
IdentifierType
¶
Identifier | identifier |
Class | Netgen\BlockManager\Parameters\ParameterType\IdentifierType |
Valid value | A string matching the ^[A-Za-z]([A-Za-z0-9_])*$ regex |
IntegerType
¶
Identifier | integer |
Available options | |
Overridden options | |
Class | Netgen\BlockManager\Parameters\ParameterType\IntegerType |
Valid value | An integer |
ItemLinkType
¶
Identifier | item_link |
Available options | |
Class | Netgen\BlockManager\Parameters\ParameterType\ItemLinkType |
Valid value | The identifier of an existing value in the form
value_type://value , for example ezlocation://42 |
value_types
¶type: array
of string
values, required: No, default value: All enabled value types
The list of accepted value types.
allow_invalid
¶type: bool
, required: No, default value: false
If true, the parameter will allow storing IDs of items which does not exist or are invalid.
LinkType
¶
Identifier | link |
Available options | |
Class | Netgen\BlockManager\Parameters\ParameterType\LinkType |
Valid value | A structure containing valid URL, e-mail address, phone
number or internal link, together with link suffix and
target. This structure is represented by
Netgen\BlockManager\Parameters\Value\LinkValue object. |
This parameter type represents a link. Multiple link types are supported:
- URL
- E-mail address
- Phone number
- Internal link (link to valid value of an item)
value_types
¶type: array
of string
values, required: No, default value: All enabled value types
The list of accepted value types.
allow_invalid_internal
¶type: bool
, required: No, default value: false
If true and internal link is selected, the parameter will allow storing IDs of items which does not exist or are invalid.
NumberType
¶
Identifier | number |
Available options | |
Overridden options | |
Class | Netgen\BlockManager\Parameters\ParameterType\NumberType |
Valid value | Any number (integer or float) |
RangeType
¶
Identifier | range |
Available options | |
Overridden options | |
Class | Netgen\BlockManager\Parameters\ParameterType\RangeType |
Valid value | An integer |
This parameter type represents a range. While in IntegerType
, min
and
max
options are optional, here, they are required.
TextLineType
¶
Identifier | text_line |
Class | Netgen\BlockManager\Parameters\ParameterType\TextLineType |
Valid value | A string without line breaks |
TextType
¶
Identifier | text |
Class | Netgen\BlockManager\Parameters\ParameterType\TextType |
Valid value | A multi-line string |
UrlType
¶
Identifier | url |
Class | Netgen\BlockManager\Parameters\ParameterType\UrlType |
Valid value | A valid URL |
ContentTypeType
¶
Identifier | ez_content_type |
Available options | |
Class | Netgen\BlockManager\Ez\Parameters\ParameterType\ContentTypeType |
Valid value | One (or more) of the valid eZ Platform content types |
This parameter allows to input one or more existing eZ Platform content types as its value. The parameter automatically shows the list of all content types in eZ Platform.
This parameter type is available only if using Netgen Layouts on top of eZ Platform.
multiple
¶type: bool
, required: No, default value: false
Specifies if the parameter type will accept multiple values.
types
¶type: array
, required: No, default value: array()
Specifies which content types are allowed. This parameter is a multidimensional array, where the keys are group names, and the values are arrays of content types allowed within the group.
Warning
Group names are case sensitive, while content type identifiers are not.
array(
'Group1' => array('image', 'file'),
'Group2' => array('article', 'blog_post'),
);
If a group is missing from the array or the value of a group is true
, all
content types within that group are allowed.
If the value of a group is set to false
or an empty array, none of the
content types within that group are allowed.
array(
'Group1' => true,
'Group2' => false,
'Group3' => array(),
);
LocationType
¶
Identifier | ezlocation |
Available options | |
Class | Netgen\BlockManager\Ez\Parameters\ParameterType\LocationType |
Valid value | ID of an existing eZ Platform location |
This parameter allows to input the ID of an existing eZ Platform location as its value.
Note
This parameter type is available only if using Netgen Layouts on top of eZ Platform.
ContentType
¶
Identifier | ezcontent |
Available options | |
Class | Netgen\BlockManager\Ez\Parameters\ParameterType\ContentType |
Valid value | ID of an existing eZ Platform content |
This parameter allows to input the ID of an existing eZ Platform content as its value.
Note
This parameter type is available only if using Netgen Layouts on top of eZ Platform.
TagsType
¶
Identifier | eztags |
Available options | |
Class | Netgen\BlockManager\Ez\Parameters\ParameterType\TagsType |
Valid value | Array of IDs of existing tags in Netgen Tags bundle |
This parameter allows to input the list of existing IDs of tags available in Netgen Tags.
Note
Requires eZ Platform with Netgen Tags Bundle to be activated work.
min
¶type: int
, required: No, default value: null
Specifies the minimum number of tags that can be set as value. Use null
to
disable the limit.
max
¶type: int
, required: No, default value: null
Specifies the maximum number of tags that can be set as value. Use null
to
disable the limit.
allow_invalid
¶type: bool
, required: No, default value: false
If true, the parameter will allow storing IDs of tags which do not exist in the system.
Twig usage¶
Netgen Layouts includes a number of Twig functions and tags to make it easier to work with layouts and blocks in your Twig templates.
Some of the functions are used by the frontend and backend layout and block templates, while others are used exclusively in the administration interface of Netgen Layouts.
List of built in Twig functions¶
The following lists all Twig functions built into Netgen Layouts.
ngbm_render_block
¶
This function is used to render a block:
{{ ngbm_render_block(block) }}
This will render the provided block in the view context of the template from
which you called the function or in the default
view context if the calling
template is not rendered by the Netgen Layouts view layer.
You can transfer a list of custom parameters to the function, which will be injected as variables into the block template:
{# layout.html.twig #}
{{ ngbm_render_block(block, {'the_answer': 42}) }}
{# block.html.twig #}
{{ the_answer }}
Finally, you can render the block with a view context different from the current one:
{{ ngbm_render_block(block, {}, 'my_context') }}
ngbm_render_layout
¶
Warning
Since all frontend templates for layouts use ngbm.layout
variable to
access the layout instead of the default layout
variable, this function
cannot be used by default to render the layouts in the frontend (i.e. in
default
view context). Instead, it is available for usage in
Netgen Layouts administration interface and for rendering the layout with
custom view contexts.
This function is used to render a layout:
{{ ngbm_render_layout(layout) }}
This will render the provided layout in the view context of the template from
which you called the function or in the default
view context if the calling
template is not rendered by the Netgen Layouts view layer.
You can transfer a list of custom parameters to the function, which will be injected as variables into the layout template:
{# my.html.twig #}
{{ ngbm_render_layout(layout, {'the_answer': 42}) }}
{# layout.html.twig #}
{{ the_answer }}
Finally, you can render the layout with a view context different from the current one:
{{ ngbm_render_layout(layout, {}, 'my_context') }}
ngbm_render_item
¶
This function is used to render a block item.
In addition to the item you’re rendering, you need to provide the item view type with which you wish to render the item:
{{ ngbm_render_item(item, 'overlay') }}
This will render the provided item in the view context of the template from
which you called the function or in the default
view context if the calling
template is not rendered by the Netgen Layouts view layer.
You can transfer a list of custom parameters to the function, which will be injected as variables into the item template:
{# block.html.twig #}
{{ ngbm_render_item(item, 'overlay', {'the_answer': 42}) }}
{# item.html.twig #}
{{ the_answer }}
Tip
Normally, parameters provided here are not transferred to content views in
eZ Platform, but only to the item template, which in case of eZ Platform is
only a proxy to eZ content view layer. However, you can use a special
parameter called ezparams
whose contents will be transferred. For
example:
{# block.html.twig #}
{{ ngbm_render_item(item, 'overlay', {'ezparams': {'the_answer': 42}}) }}
{# overlay.html.twig from eZ Platform #}
{{ the_answer }}
Finally, you can render the item with a view context different from the current one:
{{ ngbm_render_item(item, 'overlay', {}, 'my_context') }}
ngbm_render_parameter
¶
This function is used to render a parameter:
{{ ngbm_render_parameter(parameter) }}
This will render the provided parameter in the view context of the template from
which you called the function or in the default
view context if the calling
template is not rendered by the Netgen Layouts view layer.
You can transfer a list of custom parameters to the function, which will be injected as variables into the parameter template:
{# block.html.twig #}
{{ ngbm_render_parameter(parameter, {'the_answer': 42}) }}
{# parameter.html.twig #}
{{ the_answer }}
Finally, you can render the parameter with a view context different from the current one:
{{ ngbm_render_parameter(parameter, {}, 'my_context') }}
ngbm_render_placeholder
¶
This function is used to render a placeholder of a container block.
To render the placeholder, you need to provide the block from which you want to render the placeholder, as well as placeholder identifier:
{{ ngbm_render_placeholder(block, 'left') }}
This will render the provided placeholder in the view context of the template
from which you called the function or in the default
view context if the
calling template is not rendered by the Netgen Layouts view layer.
You can transfer a list of custom parameters to the function, which will be injected as variables into the placeholder template:
{# block.html.twig #}
{{ ngbm_render_placeholder(block, 'left', {'the_answer': 42}) }}
{# placeholder.html.twig #}
{{ the_answer }}
Finally, you can render the placeholder with a view context different from the current one:
{{ ngbm_render_placeholder(block, 'left', {}, 'my_context') }}
ngbm_render_rule
¶
This function is used to render a rule:
{{ ngbm_render_rule(rule) }}
This will render the provided rule in the view context of the template from
which you called the function or in the default
view context if the calling
template is not rendered by the Netgen Layouts view layer.
You can transfer a list of custom parameters to the function, which will be injected as variables into the rule template:
{# my.html.twig #}
{{ ngbm_render_rule(rule, {'the_answer': 42}) }}
{# rule.html.twig #}
{{ the_answer }}
Finally, you can render the rule with a view context different from the current one:
{{ ngbm_render_rule(rule, {}, 'my_context') }}
ngbm_render_rule_target
¶
This function is used to render a rule target:
{{ ngbm_render_rule_target(target) }}
This will render the provided target in the view context of the template from
which you called the function or in the default
view context if the calling
template is not rendered by the Netgen Layouts view layer.
You can transfer a list of custom parameters to the function, which will be injected as variables into the target template:
{# my.html.twig #}
{{ ngbm_render_rule_target(target, {'the_answer': 42}) }}
{# target.html.twig #}
{{ the_answer }}
Finally, you can render the target with a view context different from the current one:
{{ ngbm_render_rule_target(target, {}, 'my_context') }}
ngbm_render_rule_condition
¶
This function is used to render a rule condition:
{{ ngbm_render_rule_condition(condition) }}
This will render the provided condition in the view context of the template from
which you called the function or in the default
view context if the calling
template is not rendered by the Netgen Layouts view layer.
You can transfer a list of custom parameters to the function, which will be injected as variables into the condition template:
{# my.html.twig #}
{{ ngbm_render_rule_condition(condition, {'the_answer': 42}) }}
{# condition.html.twig #}
{{ the_answer }}
Finally, you can render the condition with a view context different from the current one:
{{ ngbm_render_rule_condition(condition, {}, 'my_context') }}
ngbm_render_value
¶
This function is used to render any value supported by Netgen Layouts view layer. All other rendering extensions reuse this function in one form or another.
To render the value (for example, a block), just transfer it to the function:
{{ ngbm_render_value(block) }}
This will render the provided value in the view context of the template from
which you called the function or in the default
view context if the calling
template is not rendered by the Netgen Layouts view layer.
You can transfer a list of custom parameters to the function, which will be injected as variables into the template:
{# my.html.twig #}
{{ ngbm_render_value(block, {'the_answer': 42}) }}
{# block.html.twig #}
{{ the_answer }}
Finally, you can render the value with a view context different from the current one:
{{ ngbm_render_value(block, {}, 'my_context') }}
ngbm_item_path
¶
This function is used to generate an URL to an item from your CMS.
Note
To be able to generate the URL, you need to implement an instance of
Netgen\BlockManager\Item\ValueUrlGeneratorInterface
for your item.
To generate the URL, you can simply call the function with the item in question:
<a href="{{ ngbm_item_path(item) }}">{{ item.name }}</a>
If you do not have access to the item object, you can generate the URL with ID and value type of the item:
<a href="{{ ngbm_item_path(42, 'ezlocation') }}">{{ 'My item' }}</a>
Alternatively, you can use a special format used by Netgen Layouts in the form
of an URI scheme value_type://value
:
<a href="{{ ngbm_item_path('ezlocation://42') }}">{{ 'My item' }}</a>
ngbm_collection_pager
¶
This function is used to render a pager for a collection:
{{ ngbm_collection_pager(pager, block, 'default') }}
This will render the pager for provided collection (specified by the block and
collection identifier (default
)). pager
variable is an instance of
Pagerfanta\Pagerfanta
class, provided to block view templates automatically
by Netgen Layouts.
The default template is @NetgenBlockManager/collection/default_pager.html.twig
and you can override it by providing a fourth parameter which is a hash of
configuration options:
{{ ngbm_collection_pager(pager, block, 'default', {template: '@App/my_pager.html.twig'}) }}
ngbm_collection_page_url
¶
This function returns the base URL for rendering a collection page via AJAX:
{% set page = ngbm_collection_page_url(pager, block, 'default') %}
This will return the base URL for provided collection (specified by the block
and collection identifier (default
)). pager
variable is an instance of
Pagerfanta\Pagerfanta
class, provided to block view templates automatically
by Netgen Layouts.
You can also provide a page number as the fourth parameter, to render the URL for that page:
{% set page = ngbm_collection_page_url(pager, block, 'default', 3) %}
This however will throw an exception if page you provide is out of range as
specified by pager.nbPages
.
ngbm_ezcontent_name
¶
This function is used to retrieve the name of a content from eZ Platform by its ID.
Note
This function exists because eZ Platform does not provide a way to retrieve the content name from its ID. The function is only available if Netgen Layouts is installed on top of eZ Platform.
To retrieve the content name, call the function with the content ID:
{{ ngbm_ezcontent_name(42) }}
If the content with provided ID does not exist, an empty string will be returned.
ngbm_ezlocation_path
¶
This function is used to retrieve the names of all parent locations for eZ Platform location with provided ID.
Note
This function exists because eZ Platform does not provide a way to retrieve the location name from its ID. The function is only available if Netgen Layouts is installed on top of eZ Platform.
To retrieve the names of parent locations, call the function with the location ID:
{% set names = ngbm_ezlocation_path(42) %}
{{ names|join(' / ') }}
This will return the array of parent names, starting from the top most parent.
If the location with provided ID does not exist, null
will be returned.
ngbm_ez_content_type_name
¶
This function is used to retrieve the name of a content type from eZ Platform by its identifier.
Note
This function exists because eZ Platform does not provide a way to retrieve the content type name from its identifier. The function is only available if Netgen Layouts is installed on top of eZ Platform.
To retrieve the content type name, call the function with the content type identifier:
{{ ngbm_ez_content_type_name('article') }}
If the content type with provided identifier does not exist, an empty string will be returned.
List of built in Twig tags¶
The following lists all Twig tags built into Netgen Layouts.
ngbm_render_zone
¶
This tag is used to render an entire layout zone. Since zones do not have their own template, this tag simply renders all blocks one after another.
Note
Examples below show usage as if the tag is used in frontend layout templates
which load the zone from ngbm.layout
variable available in those
templates. This does not mean you can’t transfer an instance of
Netgen\BlockManager\API\Values\Layout\Zone
object manually.
To render a zone, you can simply call the tag with the zone in question:
{% ngbm_render_zone ngbm.layout.zone('left') %}
This will render the provided zone in the default
view context.
You can also render the zone with your own custom view context:
{% ngbm_render_zone ngbm.layout.zone('left') context='my_context' %}
Warning
When rendering a zone with a custom view context, all blocks and block items which do not specify custom view context will be rendered with the view context you provided. You need to make sure all your blocks and block items have the templates for specified view context, otherwise, you will get an exception while rendering the page.
List of built in Twig global variables¶
The following lists all Twig global variables built into Netgen Layouts.
ngbm
¶
This global variable has a couple of purposes, three main ones being:
- to provide currently resolved layout to frontend layout templates
- to provide currently resolved layout template to your full views
- to provide a way to load Netgen Layouts configuration in Twig templates without having to write custom code
The following is a list of variables available:
ngbm.debug
This variable defines if Netgen Layouts debug mode is activated. This flag is mainly used for development of Netgen Layouts and is not useful in normal operation of a website (either in production or development mode).
To activate Netgen Layouts debug mode, use a configuration similar to this:
netgen_block_manager: debug: true
ngbm.layout
This variable holds the layout resolved in the current request (instance ofNetgen\BlockManager\API\Values\Layout\Layout
). It is mostly used in frontend layout templates to access the layout and render the zones.
ngbm.layoutView
This variable holds the layout view of the layout resolved in current request (instance ofNetgen\BlockManager\View\View\LayoutViewInterface
). You can use it to access any data from the view, like the view context or the name of the layout template. If no layout was resolved, this variable will be set tofalse
and if layout resolving process was not ran, it will be set tonull
.
ngbm.rule
This variable holds the rule (instance ofNetgen\BlockManager\API\Values\LayoutResolver\Rule
) that was used to resolve the layout for the current request. You can use it to access targets and conditions that were responsible for resolving the layout.
ngbm.config
This variable is an instance of
Netgen\Bundle\BlockManagerBundle\Configuration\ConfigurationInterface
. It makes it possible to access configuration of Netgen Layouts (basically, any container parameter which name starts withnetgen_block_manager.
).For example, to access a container parameter called
netgen_block_manager.some_config
, you can usengbm.config.parameter('some_config')
.Tip
In cases when Netgen Layouts is used on top of eZ Platform, you can use this variable to access siteaccess aware container parameters too. For example, accessing parameter called
netgen_block_manager.cro.some_value
can be done with the same code as before:ngbm.config.parameter('some_config')
.In addition to container parameters, this variable makes it possible to access the list of entities provided by Netgen Layouts, like block definitions, query types and so on. You can access them by using the same
ngbm.config.parameter()
function call as before, with the parameter names specified below:
block_definitions
- Provides a list of all block definitionsblock_types
- Provides a list of all block typesblock_type_groups
- Provides a list of all block type groupslayout_types
- Provides a list of all layout typesquery_types
- Provides a list of all query typesvalue_types
- Provides a list of all value typestarget_types
- Provides a list of all target typescondition_types
- Provides a list of all condition typesparameter_types
- Provides a list of all parameter types
ngbm.layoutTemplate
This variable is a shortcut to access the template name of the layout resolved in current request (available asngbm.layoutView.template
). You will mostly use this variable in your full views to extend from instead of your default pagelayout. Using this variable starts the layout resolving process if it was not ran already. In case when no layout was resolved, this variable holds the name of your default pagelayout, so your full views can fallback to it without need to modify them.
ngbm.pageLayoutTemplate
This variable holds the name of your default pagelayout which you configured inside Netgen Layouts. It is mostly used to extend from in frontend layout templates, so those templates can fallback to it to render the page head, header, footer and so on.
ngbm_admin
¶
This global variable is used by the administration interface of Netgen Layouts. Currently, only one variable is available:
ngbm_admin.pageLayoutTemplate
This variable holds the name of the pagelayout template for the admin interface. The idea behind it is that you can change the pagelayout of the administration interface without having to change the administration templates themselves. This can be achieved by setting this variable to a desired template name before admin interface is rendered (e.g. in an event listener).
Events¶
Netgen Layouts dispatches some events in a lifecycle of displaying the page with a resolved layout that you can listen to and act upon.
The following lists all available events.
ngbm.view.build_view¶
Event class: Netgen\BlockManager\Event\CollectViewParametersEvent
This event will be dispatched when the view of a value is being built. It can be used to inject custom variables into the view before the view is built.
For example, you can use the following to inject a variable into the block view:
public function onBuildView(CollectViewParametersEvent $event)
{
$view = $event->getView();
if (!$view instanceof BlockViewInterface) {
// Do nothing if the view does not belong to a block
return;
}
if ($view->getContext() !== 'default') {
// Do nothing if the view context is not for the frontend
return;
}
$event->addParameter('the_answer', 42);
}
ngbm.view.render_view¶
Event class: Netgen\BlockManager\Event\CollectViewParametersEvent
This event will be dispatched when the view of a value is being rendered. It can be used to inject custom variables into the view before the view is sent to Twig for rendering.
The example for injecting a variable into the view is the same as with
build_view
event.
ngbm.admin.match¶
Event class: Netgen\Bundle\BlockManagerAdminBundle\Event\AdminMatchEvent
This event will be dispatched when the request is matched as being a Netgen Layouts admin interface request. It is usually used if you want to override the pagelayout of Netgen Layouts admin interface for integrating it in other admin panels.
Symfony services¶
Netgen Layouts provides a number of Symfony services that you can use to work in PHP code with layouts, blocks, collections, queries and so on.
API services¶
The following services are the entry point and central place for all operations with any entity available in Netgen Layouts. It is used by Netgen Layouts itself to render the layouts in the frontend, in REST API used in Block Manager app and in the admin interface. Basically, they provide a CRUD interface to work with layouts, blocks, collections and layout resolver rules.
Service name | Description |
---|---|
netgen_block_manager.api.service.layout |
CRUD operations for layouts |
netgen_block_manager.api.service.block |
CRUD operations for blocks |
netgen_block_manager.api.service.collection |
CRUD operations for collections |
netgen_block_manager.api.service.layout_resolver |
CRUD operations for layout resolver rules |
View API¶
The following services can be used to manually render any entity in Netgen Layouts.
Service name | Description |
---|---|
netgen_block_manager.view.view_builder |
Used to manually build the view for the entity. |
netgen_block_manager.view.view_renderer |
Used to manually render the entity view once it has been built. |
netgen_block_manager.view.renderer |
Shortcut service that uses view builder and view renderer services to render the provided entity. |
Block items¶
The following services can be used to manually load and build block items to inject them into blocks and link to them.
Service name | Description |
---|---|
netgen_block_manager.item.item_builder |
Used to manually build the item from the provided entity. |
netgen_block_manager.item.item_loader |
Used to manually load the item from provided value type and value. |
netgen_block_manager.item.url_generator |
Used to generate the URL to the item. |
Registries¶
A number of registries is provided so you can access the list of all available block definitions, query types and so on.
Service name | Description |
---|---|
netgen_block_manager.block.registry.block_definition |
Used to access all available block definitions |
netgen_block_manager.block.registry.block_type |
Used to access all available block types |
netgen_block_manager.block.registry.block_type_group |
Used to access all available block type groups |
netgen_block_manager.collection.registry.query_type |
Used to access all available query types |
netgen_block_manager.parameters.registry.parameter_type |
Used to access all available parameter types |
netgen_block_manager.item.registry.value_type |
Used to access all available value types |
netgen_block_manager.layout.registry.layout_type |
Used to access all available layout types |
netgen_block_manager.layout.resolver.registry.target_type |
Used to access all available target types |
netgen_block_manager.layout.resolver.registry.condition_type |
Used to access all available condition types |
Shortcut services¶
Some of the entities that can be accessed through one of the above registries
can also be accessed directly by using a unique service name. All of those
service names are in the form of <prefix>.<identifier>
. Prefix is the same
for all entities that implement the same interface, while identifier identifies
a single entity.
The following table lists all available service prefixes:
Entity type | Service prefix |
---|---|
Block definition | netgen_block_manager.block.block_definition. |
Block type | netgen_block_manager.block.block_type. |
Block type group | netgen_block_manager.block.block_type_group. |
Query type | netgen_block_manager.collection.query_type. |
Value type | netgen_block_manager.item.value_type. |
Layout type | netgen_block_manager.layout.layout_type. |
As an example, if you wish to load the service for title
block definition,
you would use a service name
netgen_block_manager.block.block_definition.title
.
Other services¶
The following lists various other useful services which can be used by client code:
Service name | Description |
---|---|
netgen_block_manager.http_cache.client |
Provides APIs for invalidating layout and block HTTP caches |
netgen_block_manager.configuration |
Provides a way to access Netgen Layouts configuration values |
netgen_block_manager.collection.result_builder |
Generates the collection result (items) from a provided collection |
netgen_block_manager.layout.resolver |
Exposes APIs to manually run the layout resolving process on a request |
eZ Platform specific services¶
The following lists various useful services available when Netgen Layouts is installed on top of eZ Platform.
Service name | Description |
---|---|
netgen_block_manager.ezpublish.content_provider |
Used to extract current content and location for use by contextual blocks and queries |
Symfony dependency injection tags¶
The following lists all dependency injection tags and their usage available in Netgen Layouts:
netgen_block_manager.block.block_definition_handler
¶
Purpose: Adds a new block definition handler
When registering a new block definition handler, you need to use the
identifier
attribute in the tag to specify the unique identifier of the
block definition:
app.block.block_definition.handler.my_block:
class: AppBundle\Block\BlockDefinition\Handler\MyBlockHandler
tags:
- { name: netgen_block_manager.block.block_definition_handler, identifier: my_block }
netgen_block_manager.block.block_definition_handler.plugin
¶
Purpose: Adds a new block handler plugin
When registering a new block definition handler plugin, you can use the
priority
attribute in the tag to specify the order in which your handler
plugin is executed in regard to other existing plugins:
app.block.block_definition.handler.plugin.my_plugin:
class: AppBundle\Block\BlockDefinition\Handler\MyPlugin
tags:
- { name: netgen_block_manager.block.block_definition_handler.plugin, priority: 10 }
netgen_block_manager.collection.query_type_handler
¶
Purpose: Adds a new query type handler
When registering a new query type handler, you need to use the type
attribute in the tag to specify the unique identifier of the query type:
app.collection.query_type.handler.my_handler:
class: AppBundle\Collection\QueryType\Handler\MyHandler
tags:
- { name: netgen_block_manager.collection.query_type_handler, type: my_handler }
netgen_block_manager.parameters.parameter_type
¶
Purpose: Adds a new parameter type
app.parameters.parameter_type.my_type:
class: AppBundle\Parameters\ParameterType\MyType
tags:
- { name: netgen_block_manager.parameters.parameter_type }
netgen_block_manager.parameters.form.mapper
¶
Purpose: Adds a new parameter type form mapper
When registering a new parameter type form mapper, you need to use the type
attribute in the tag to specify to which parameter type this mapper applies:
app.parameters.form.mapper.my_type:
class: AppBundle\Parameters\Form\Mapper\MyTypeMapper
tags:
- { name: netgen_block_manager.parameters.form.mapper, type: my_type }
netgen_block_manager.layout.resolver.target_type
¶
Purpose: Adds a new target type
When registering a new target type, you can use the priority
attribute in
the tag to specify the order in which your target type is considered when
resolving the layout in regard to other existing target types:
app.layout.resolver.target_type.my_target:
class: AppBundle\Layout\Resolver\TargetType\MyTarget
tags:
- { name: netgen_block_manager.layout.resolver.target_type, priority: 10 }
netgen_block_manager.layout.resolver.form.target_type.mapper
¶
Purpose: Adds a new target type form mapper
When registering a new target type form mapper, you need to use the
target_type
attribute in the tag to specify to which target type this mapper
applies:
app.layout.resolver.form.target_type.mapper.my_target:
class: AppBundle\Layout\Resolver\Form\TargetType\Mapper\MyTarget
tags:
- { name: netgen_block_manager.layout.resolver.form.target_type.mapper, target_type: my_target }
netgen_block_manager.layout.resolver.target_handler.doctrine
¶
Purpose: Adds a new target type Doctrine handler
When registering a new target type Doctrine handler, you need to use the
target_type
attribute in the tag to specify to which target type this
handler applies:
app.layout_resolver.target_handler.doctrine.my_target:
class: AppBundle\LayoutResolver\TargetHandler\Doctrine\MyTarget
tags:
- { name: netgen_block_manager.layout.resolver.target_handler.doctrine, target_type: my_target }
netgen_block_manager.layout.resolver.condition_type
¶
Purpose: Adds a new condition type
app.layout.resolver.condition_type.my_condition:
class: AppBundle\Layout\Resolver\ConditionType\MyCondition
tags:
- { name: netgen_block_manager.layout.resolver.condition_type }
netgen_block_manager.layout.resolver.form.condition_type.mapper
¶
Purpose: Adds a new condition type form mapper
When registering a new condition type form mapper, you need to use the
condition_type
attribute in the tag to specify to which condition type this
mapper applies:
app.layout.resolver.form.condition_type.mapper.my_condition:
class: AppBundle\Layout\Resolver\Form\ConditionType\Mapper\MyCondition
tags:
- { name: netgen_block_manager.layout.resolver.form.condition_type.mapper, condition_type: my_condition }
netgen_block_manager.view.template_matcher
¶
Purpose: Adds a new view template matcher
When registering a new view template matcher, you need to use the identifier
attribute in the tag to specify the unique identifier of the matcher:
app.view.matcher.block.my_matcher:
class: AppBundle\View\Matcher\Block\MyMatcher
tags:
- { name: netgen_block_manager.view.template_matcher, identifier: block\my_matcher }
netgen_block_manager.context.provider
¶
Purpose: Adds data to the context which is used to render contextual blocks via AJAX or ESI fragments
app.context.my_context_provider:
class: AppBundle\Context\MyContextProvider
tags:
- { name: netgen_block_manager.context.provider }
Symfony commands¶
Export/import commands¶
The following is a list of Symfony commands available in Netgen Layouts used for exporting/importing Netgen Layouts data.
Command name | Purpose |
---|---|
ngbm:export |
This script can be used to export one or more layouts or mappings to a file in JSON format |
ngbm:import |
This script can be used to import one or more layouts from a JSON format stored in a file |
ngbm:export
¶
This script can be used to export one or more layouts or mappings to a file in JSON format.
To specify the type of the entity you wish to export, you need to provide it to the script as the first argument.
To specify the ID of the entity to export, provide it to the script as the second argument.
You can also provide the name of the file where to store the export as the third argument. This argument is optional and if you do not provide it, JSON will be dumped to the standard output of your terminal.
For example, to export the layout with ID of 1, call the script like this:
$ php bin/console ngbm:export layout 1 layout_1.json
Or to export a mapping with an ID of 1, call the script with:
$ php bin/console ngbm:export rule 1 rule_1.json
You can also specify the list of IDs which will then be exported together:
$ php bin/console ngbm:export layout 1,2,3 layouts.json
ngbm:import
¶
This script can be used to import one or more layouts from a JSON format stored in a file.
To specify the type of the entity you wish to import, you need to provide it to the script as the first argument. Currently, only layouts can be imported.
To specify the file from which the JSON data will be read, you need to provide it to the script as the second argument.
For example, to import all layouts stored in a file called layouts.json
,
call the script like this:
$ php bin/console ngbm:import layout layouts.json
Migration commands¶
These commands are used in upgrade processes between various Netgen Layouts versions.
Warning
These scripts should not be executed in normal operation since they can result in loss of data.
Command name | Purpose |
---|---|
ngbm:migration:query_offset_limit |
Migrates query offset and limit parameters to the collection. Used when upgrading from version 0.9 to 0.10. |
ngbm:migration:query_offset_limit
¶
This script migrates query offset and limit parameters to the collection. It is used when upgrading from version 0.9 to 0.10.
The script does not have any parameters and can simply be called with:
$ php bin/console ngbm:migration:query_offset_limit
The script will ask you for names of offset and limit parameters for each of your custom query types and then migrate the offset and limit from the query to the collection.
Upgrades¶
Upgrades¶
Upgrading from 0.7.0 to 0.8.0¶
Upgrade composer.json
¶
In your composer.json
file, upgrade the version of netgen/block-manager
package to ~0.8.0
and run the composer update
command.
Note
If you have Netgen Layouts installed on eZ Platform, the package name will
be netgen/block-manager-ezpublish
.
Note
Integrations into Netgen Admin UI and eZ Platform UI also have separate
packages whose versions need to be bumped to ~0.8.0
.
Activate required bundles¶
Version 0.8 requires FOS HTTP Cache Bundle to be activated, so if not already
present, activate FOS\HttpCacheBundle\FOSHttpCacheBundle
in your kernel.
Database migration¶
Run the following command from the root of your installation to execute migration to version 0.8 of Netgen Layouts:
$ php app/console doctrine:migrations:migrate --configuration=vendor/netgen/block-manager/migrations/doctrine.yml
Upgrading Netgen Content Browser¶
Netgen Content Browser version 0.8 was also automatically installed. Be sure to read its upgrade instructions too, to make sure you custom code keeps working.
Updates to Varnish VCL¶
To enable caching and later cache clearing of block and layout HTTP caches, you
will need to use Varnish. To make the cache clearing work, you need to modify
your Varnish VCL and add the following rules somewhere in your vcl_recv
function. If you’re using eZ Platform and the VCL supplied by it, the best place
to put this is in ez_purge
function (which is called from vcl_recv
),
right after if (req.http.X-Location-Id) { ... }
block.
For Varnish 3:
if (req.http.X-Layout-Id) {
ban( "obj.http.X-Layout-Id ~ " + req.http.X-Layout-Id);
if (client.ip ~ debuggers) {
set req.http.X-Debug = "Ban done for layout with ID " + req.http.X-Layout-Id;
}
error 200 "Banned";
}
if (req.http.X-Block-Id) {
ban( "obj.http.X-Block-Id ~ " + req.http.X-Block-Id);
if (client.ip ~ debuggers) {
set req.http.X-Debug = "Ban done for block with ID " + req.http.X-Block-Id;
}
error 200 "Banned";
}
For Varnish 4 and later:
if (req.http.X-Layout-Id) {
ban("obj.http.X-Layout-Id ~ " + req.http.X-Layout-Id);
if (client.ip ~ debuggers) {
set req.http.X-Debug = "Ban done for layout with ID " + req.http.X-Layout-Id;
}
return (synth(200, "Banned"));
}
if (req.http.X-Block-Id) {
ban("obj.http.X-Block-Id ~ " + req.http.X-Block-Id);
if (client.ip ~ debuggers) {
set req.http.X-Debug = "Ban done for block with ID " + req.http.X-Block-Id;
}
return (synth(200, "Banned"));
}
Breaking changes¶
The following breaking changes were made in version 0.8 of Netgen Layouts. Follow the instructions to upgrade your code to this newer version.
Some classes and interfaces had their namespaces changed. Update your custom code working with these classes and interfaces. The following table lists the old and the new interface and class names:
Old FQCN New FQCN Netgen\BlockManager\API\Values\Page\Block
Netgen\BlockManager\API\Values\Block\Block
Netgen\BlockManager\API\Values\Page\Placeholder
Netgen\BlockManager\API\Values\Block\Placeholder
Netgen\BlockManager\API\Values\Page\CollectionReference
Netgen\BlockManager\API\Values\Block\CollectionReference
Netgen\BlockManager\API\Values\Page\BlockCreateStruct
Netgen\BlockManager\API\Values\Block\BlockCreateStruct
Netgen\BlockManager\API\Values\Page\BlockUpdateStruct
Netgen\BlockManager\API\Values\Block\BlockUpdateStruct
Netgen\BlockManager\API\Values\Page\Layout
Netgen\BlockManager\API\Values\Layout\Layout
Netgen\BlockManager\API\Values\Page\Zone
Netgen\BlockManager\API\Values\Layout\Zone
Netgen\BlockManager\API\Values\Page\LayoutCreateStruct
Netgen\BlockManager\API\Values\Layout\LayoutCreateStruct
Netgen\BlockManager\API\Values\Page\LayoutUpdateStruct
Netgen\BlockManager\API\Values\Layout\LayoutUpdateStruct
Notable change is the
Block
interface since it’s used inNetgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandlerInterface::getDynamicParameters
. method. You will need to modify your custom block definition handlers to use the new interface.In
Netgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandlerInterface::getDynamicParameters
method, a second, unused, parameter called$parameters
was removed from the interface. Remove it from your custom block definition handlers.A new method called
isContextual
was added toNetgen\BlockManager\Collection\QueryType\QueryTypeHandlerInterface
interface. The purpose of this method is to signal to the system when the query acts as a contextual query, i.e., if it depends on data from current page to run. You need to add this method to your custom query type handlers.The following is the method signature as well as an example implementation:
/** * Returns if the provided query is dependent on a context, i.e. currently displayed page. * * @param \Netgen\BlockManager\API\Values\Collection\Query $query * * @return bool */ public function isContextual(Query $query);
public function isContextual(Query $query) { return $query->getParameter('use_current_location')->getValue() === true; }
BlockDefinitionHandlerInterface::hasCollection
method has been removed. From now on, specifying that the block has a collection is done through configuration. The following shows the old and new way of specifying that the block has a collection:// Old way <?php namespace MyApp\Block\BlockDefinition\Handler; use Netgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandler; class MyBlockHandler extends BlockDefinitionHandler { /** * Returns if this block definition should have a collection. * * @return bool */ public function hasCollection() { return true; } }
# New way netgen_block_manager: block_definitions: my_block: collections: ~
Netgen\BlockManager\Layout\Resolver\TargetTypeInterface::provideValue
method has a changed signature. From now on, SymfonyRequest
object is provided as a parameter to the method, so there’s no need to manually fetch the current request from the request stack. The new interface looks like this:/** * Provides the value for the target to be used in matching process. * * @param \Symfony\Component\HttpFoundation\Request $request * * @return mixed */ public function provideValue(Request $request);
Netgen\BlockManager\Layout\Resolver\ConditionTypeInterface::matches
method has a changed signature. From now on, SymfonyRequest
object is provided as a first parameter to the method, so there’s no need to manually fetch the current request from the request stack. The new interface looks like this:/** * Returns if this request matches the provided value. * * @param \Symfony\Component\HttpFoundation\Request $request * @param mixed $value * * @return bool */ public function matches(Request $request, $value);
Netgen\BlockManager\Traits\RequestStackAwareTrait
trait has been removed. Inject the request stack service directly into the constructor.If using Netgen Layouts with eZ Publish 5, instead of redefining the alias for the content provider service, you now have to redefine the alias for newly introduced content extractor service.
# Before netgen_block_manager.ezpublish.content_provider: alias: netgen_block_manager.ezpublish.content_provider.ez5_request
# After netgen_block_manager.ezpublish.content_extractor: alias: netgen_block_manager.ezpublish.content_extractor.ez5_request
netgen_block_manager.google_maps_api_key
configuration was renamed tonetgen_block_manager.api_keys.google_maps
. The following shows an example of the old and new configs:# Old config netgen_block_manager: google_maps_api_key: MY_API_KEY
# New config netgen_block_manager: api_keys: google_maps: MY_API_KEY
standard
item view type is always added to all view types automatically. However, this was not true for view types that specified custom item view types. You had to specifystandard
item view type manually if you wanted to use it. From now on,standard
item view type will be added in those cases too. If you wish to disable it, you can do so like this:netgen_block_manager: block_definitions: my_block: view_types: my_view_type: item_view_types: standard: enabled: false
User policies are introduced. To be able to manage user policies in legacy administration interface of eZ Platform, you need to activate the provided
nglayouts
legacy extension. If you’re using eZ Platform UI, policy management is available automatically.Custom items can now be added to blocks manually, instead of just being able to return them from query types. Make sure to implement the
Netgen\BlockManager\Item\ValueLoaderInterface
for your custom items, as well as Content Browser backend, and then activate the value type in configuration:netgen_block_manager: items: value_types: my_value_type: name: 'My value type'
Upgrading from 0.8.0 to 0.9.0¶
Upgrade composer.json
¶
In your composer.json
file, upgrade the version of netgen/block-manager
package to ~0.9.0
and run the composer update
command.
Note
If you have Netgen Layouts installed on eZ Platform, the package name will
be netgen/block-manager-ezpublish
.
Note
Integrations into Netgen Admin UI and eZ Platform UI also have separate
packages whose versions need to be bumped to ~0.9.0
.
Database migration¶
Run the following command from the root of your installation to execute migration to version 0.9 of Netgen Layouts:
$ php app/console doctrine:migrations:migrate --configuration=vendor/netgen/block-manager/migrations/doctrine.yml
The database migration will ask you for a default locale for your existing layouts and blocks. Make sure to enter the primary locale of your site.
Warning
If using eZ Platform, you need to input the Symfony locale that directly converts to eZ language code, or loading layouts and blocks will not work.
E.g. if your primary language code in eZ Platform is eng-GB
, you will
need to use en_GB
Symfony locale instead of plain en
.
Upgrading Netgen Content Browser¶
Netgen Content Browser version 0.9 was also automatically installed. Be sure to read its upgrade instructions too, to make sure you custom code keeps working.
Breaking changes¶
The following breaking changes were made in version 0.9 of Netgen Layouts. Follow the instructions to upgrade your code to this newer version.
A bug was fixed in eZ Platform semantic configuration for view layer which wrongly ordered template override rules for blocks, layouts and block items. Fixing this bug means that your custom override rules might stop working if you used the same override identifiers as the ones in Netgen Layouts. To fix this, rename your rule identifiers to a unique value.
Many services that should not be used directly and are not part of public API are now marked as private in service container. Remove usage of those services in your code. Note that some of the services (forms, validators, event subscribers and Twig runtimes) were not marked as private due to incompatibilities with Symfony 2.8, but will be marked as such in a future update.
Most of the internal
protected
dependencies and methods were madeprivate
and classes made final. Rather than extending internal classes, you need to use other patterns when changing built in behaviour.Layout type, block type and block definition icons are introduced in configuration. If you previously defined custom icons through custom CSS, you need to move the path of the icon to configuration:
netgen_block_manager: layout_types: my_layout: icon: /path/to/icon.svg
netgen_block_manager: block_definitions: my_block: icon: /path/to/icon.svg
netgen_block_manager: block_types: my_block: icon: /path/to/icon.svg
A new method called
isContextual
was added toNetgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandlerInterface
interface. The purpose of this method is to signal to the system when the block acts as a contextual block, i.e., if it depends on data from current page to run. You need to add this method to your custom block definition handlers if they depend on data from current page (for example, if they use current eZ Platform location or content).The following is the method signature:
/** * Returns if the provided block is dependent on a context, i.e. currently displayed page. * * @param \Netgen\BlockManager\API\Values\Block\Block $block * * @return bool */ public function isContextual(Block $block);
Block plugins are implemented. This led to changing the signature of
BlockDefinitionHandlerInterface::getDynamicParameters
method. This method now receives a second parameter (located in the first place in the list of arguments) which is an instance ofNetgen\BlockManager\Block\DynamicParameters
and is used to collect the dynamic parameters, instead of returning them from the method. This object implementsArrayAccess
interface, so you can use array notation when adding the parameters. The following code blocks show the example of the method before the change and after:// Before /** * Returns the array of dynamic parameters provided by this block definition. * * @param \Netgen\BlockManager\API\Values\Block\Block $block * * @return array */ public function getDynamicParameters(Block $block) { return array( 'param' => 'value', ); }
// After /** * Adds the dynamic parameters to the $params object for the provided block. * * @param \Netgen\BlockManager\Block\DynamicParameters $params * @param \Netgen\BlockManager\API\Values\Block\Block $block */ public function getDynamicParameters(DynamicParameters $params, Block $block) { $params['param'] = 'value'; }
buildCommonParameters
method in theBlockDefinitionHandler
abstract class is removed and replaced with a block plugin which adds the common parameters to every block. Remove the call from your handlers if it exists.If one of your blocks did not call this method (and thus did not add the common parameters to your block), implement a block plugin which removes any parameter from the block which has a
common
group:/** * Builds the parameters by using provided parameter builder. * * @param \Netgen\BlockManager\Parameters\ParameterBuilderInterface $builder */ public function buildParameters(ParameterBuilderInterface $builder) { foreach ($builder->all('common') as $parameter) { $builder->remove($parameter->getName()); } }
createValueFromInput
method inNetgen\BlockManager\Parameters\ParameterTypeInterface
has been removed. Use the domain format of the value in your code working with parameters instead.toHash
,fromHash
, andisValueEmpty
methods inNetgen\BlockManager\Parameters\ParameterTypeInterface
interface were changed. From now on, they receive an instance ofNetgen\BlockManager\Parameters\ParameterInterface
object as their first parameter. The following shows the difference in signature in one of the methods:// Before /** * Converts the parameter value from a domain format to scalar/hash format. * * @param mixed $value * * @return mixed */ public function toHash($value);
// After /** * Converts the parameter value from a domain format to scalar/hash format. * * @param \Netgen\BlockManager\Parameters\ParameterInterface $parameter * @param mixed $value * * @return mixed */ public function toHash(ParameterInterface $parameter, $value);
mapOptions
method in target type form mapper interface (Netgen\BlockManager\Layout\Resolver\Form\TargetType\MapperInterface
) was replaced withgetFormOptions
method which does not take any parameters. If you needed the target type in this method, inject it into the mapper via constructor. The contents of the method can be migrated verbatim.mapOptions
method in condition type form mapper interface (Netgen\BlockManager\Layout\Resolver\Form\ConditionType\MapperInterface
) was replaced withgetFormOptions
method which does not take any parameters. If you needed the condition type in this method, inject it into the mapper via constructor. The contents of the method can be migrated verbatim.Second parameter of
handleForm
method in target type mapper interface (Netgen\BlockManager\Layout\Resolver\Form\TargetType\MapperInterface
) was removed. If you needed the target type in this method, inject it into the mapper via constructor.Second parameter of
handleForm
method in condition type mapper interface (Netgen\BlockManager\Layout\Resolver\Form\ConditionType\MapperInterface
) was removed. If you needed the condition type in this method, inject it into the mapper via constructor.
Upgrading from 0.9.0 to 0.10.0¶
Add required packages¶
All standard blocks and layouts provided by Netgen Layouts have been moved to a
separate bundle. To get the blocks and layouts back, you will need to add an
additional Composer package to your site’s composer.json
, named
netgen/block-manager-standard
with version ~0.10.0
.
Activate required bundles¶
Version 0.10 requires
Netgen\Bundle\BlockManagerStandardBundle\NetgenBlockManagerStandardBundle
to
be activated in your app kernel. Make sure this new bundle is activated
immediately after NetgenBlockManager
bundle.
Upgrade composer.json
¶
In your composer.json
file, upgrade the version of netgen/block-manager
package to ~0.10.0
and run the composer update
command.
Note
If you have Netgen Layouts installed on eZ Platform, the package name will
be netgen/block-manager-ezpublish
.
Note
Integrations into Netgen Admin UI and eZ Platform UI also have separate
packages whose versions need to be bumped to ~0.10.0
.
Database migration¶
Run the following command from the root of your installation to execute migration to version 0.10 of Netgen Layouts:
$ php app/console doctrine:migrations:migrate --configuration=vendor/netgen/block-manager/migrations/doctrine.yml
Running migration script¶
Version 0.10 brings a new feature called AJAX blocks, which makes it possible to page block collections via AJAX. To achieve that, we needed to implement a proper support for paging block collections via offset and limit. This means that from now on, every collection (dynamic as well as manual) will have an offset and limit parameter and this script can be used to migrate existing offset and limit parameters from your custom query types to collections.
The workflow is to run the script, specify the names of offset and limit
parameters for each of your custom query types and then let script migrate the
values from your queries to their respective collections. Once this is done,
you should refactor your custom query types to remove offset and limit
parameters, and instead, start using $offset
and $limit
arguments
provided to you by getValues
method.
To run the script, execute the following:
$ php app/console ngbm:migration:query_offset_limit
For every custom query type, the script will now ask the name of offset and
limit parameter. If some of your query types do not have an offset and limit
parameter, you can select NO PARAMETER
in the list of provided options,
which will signal to the script that no such parameter is used and default
values for offset and limit will be used (0
and null
respectively).
Note
Collection offset and limit are not translatable, so only offset and limit from main query locale will be used.
Caution
It is possible that you receive a database transaction error about incompatible collations between database tables. This is due to Doctrine Migrations setting a wrong collation on newly created database tables instead of using the collation specified on the database level. To get rid of the error, make sure that all your tables have a same collation before running the script.
Upgrading Netgen Content Browser¶
Netgen Content Browser version 0.10 was also automatically installed. Be sure to read its upgrade instructions too, to make sure you custom code keeps working.
Breaking changes¶
The following breaking changes were made in version 0.10 of Netgen Layouts. Follow the instructions to upgrade your code to this newer version.
Two new container blocks were added: three column and four column containers. If you implemented those containers by yourself and if you used
three_columns
andfour_columns
identifiers, you will need to migrate your existing blocks to different identifiers. This will require changing the identifiers in your configuration and templates as well as updating the identifier in the database with the SQL code similar to the following:UPDATE ngbm_block SET definition_identifier = 'custom_three_columns' WHERE definition_identifier = 'three_columns';
netgen_block_manager.collection.result_loader
Symfony service has been renamed tonetgen_block_manager.collection.result_builder
and corresponding interface has been renamed fromNetgen\BlockManager\Collection\Result\ResultLoaderInterface
toNetgen\BlockManager\Collection\Result\ResultBuilderInterface
.All standard blocks and layouts provided by Netgen Layouts have been moved to a separate bundle. PHP namespaces of the block handlers have been changed to have the prefix
Netgen\BlockManager\Standard
. As for templates, if you referenced built-in block and layout templates with deprecated Symfony syntax (e.g.NetgenBlockManagerBundle:block:block.html.twig
), you will need to renameNetgenBlockManagerBundle
part of the template name toNetgenBlockManagerStandardBundle
. It is however recommended to change your custom code and configuration to use Twig namespaces (@NetgenBlockManager/block/block.html.twig
) as per Symfony best practices. Using Twig namespaces also means that you do not need to worry about the fact that the block and layout templates moved to a different bundle, since the new bundle reuses the@NetgenBlockManager
Twig namespace.If you overrode some frontend block or layout templates from
NetgenBlockManagerBundle
by usingapp/Resources/NetgenBlockManagerBundle/views
folder, you will need to move those templates toapp/Resources/views/ngbm/themes/standard
folder. This is due to all frontend templates for blocks and layouts being referenced by their theme names (by using@ngbm
prefix instead of@NetgenBlockManager
or@NetgenBlockManagerStandard
prefixes). Read about theme support in Netgen Layouts for more details.getInternalLimit
method has been removed fromNetgen\BlockManager\Collection\QueryType\QueryTypeHandlerInterface
interface and is not used by Netgen Layouts any more. You can remove it from your query types.import
andexport
methods have been added toNetgen\BlockManager\Parameters\ParameterTypeInterface
If you extended abstractNetgen\BlockManager\Parameters\ParameterType
class when creating your own parameter types, there’s nothing for you to do. Otherwise, you need implement these methods, which are used for exporting and importing values of your parameter types. Basic implementation ofimport
method should return values in the same format as yourfromHash
method, while basic implementation ofexport
method should return values in the same format as yourtoHash
method.loadByRemoteId
method has been added toNetgen\BlockManager\Item\ValueLoaderInterface
. This method will be used by export/import process to work with remote IDs when exporting items instead of their database IDs. This method in your custom value loaders needs to look just likeload
method, except that it should load your value by its remote ID. If your value does not have the remote ID, simply forward the call toload
method.getRemoteId
method has been added toNetgen\BlockManager\Item\ValueConverterInterface
. This method will be used by export/import process to work with remote IDs when exporting items instead of their database IDs. This method in your custom value converters needs to return the remote ID of your value. If your value does not have the remote ID, simply return the ID, just asgetId
method does.getObject
method has been added toNetgen\BlockManager\Item\ValueConverterInterface
. This method can be used to enrich your custom objects when loading them from your CMS before being rendered. To retain the current behaviour and not enrich the object, just return it.Dependency injection tag for layout resolver target handlers has been renamed from
netgen_block_manager.persistence.doctrine.layout_resolver.query_handler.target_handler
tonetgen_block_manager.layout.resolver.target_handler.doctrine
. You need to rename the tag in service definitions for your target handlers.PHP interface for layout resolver target handlers has been renamed from
Netgen\BlockManager\Persistence\Doctrine\QueryHandler\LayoutResolver\TargetHandler
toNetgen\BlockManager\Persistence\Doctrine\QueryHandler\TargetHandlerInterface
. You need to implement the new interface in your target handlers. Method signatures remain the same.
Upgrading from 0.10.0 to 0.11.0¶
Upgrade composer.json
¶
In your composer.json
file, upgrade the version of netgen/block-manager
package and all other related packages (like netgen/block-manager-standard
,
netgen/block-manager-ezpublish
and others) to ~0.11.0
and run the
composer update
command.
Database migration¶
Run the following command from the root of your installation to execute migration to version 0.11 of Netgen Layouts:
$ php app/console doctrine:migrations:migrate --configuration=vendor/netgen/block-manager/migrations/doctrine.yml
Upgrading Netgen Content Browser¶
Netgen Content Browser version 0.11 was also automatically installed. Be sure to read its upgrade instructions too, to make sure you custom code keeps working.
Breaking changes¶
- Layouts exported in Netgen Layouts 0.10 cannot be imported into Netgen Layouts 0.11, due to updated specification.
Netgen\BlockManager\Parameters\ParameterInterface
has been renamed toNetgen\BlockManager\Parameters\ParameterDefinition
class, and the interface itself has been removed. This mostly has impact onNetgen\BlockManager\Parameters\ParameterTypeInterface
andNetgen\BlockManager\Parameters\Form\MapperInterface
, which receive instances of renamed interfaces in their methods. Update the type hints in your implementations ofParameterTypeInterface
andMapperInterface
toParameterDefinition $parameterDefinition
to migrate.Netgen\BlockManager\Item\ValueUrlBuilderInterface
interface has been renamed toNetgen\BlockManager\Item\ValueUrlGeneratorInterface
and the methodgetUrl
from the interface has been renamed togenerate
. Symfony dependency injection tag for value URL generators has also been renamed fromnetgen_block_manager.item.value_url_builder
tonetgen_block_manager.item.value_url_generator
.ngbm_render_value_object
Twig function has been renamed tongbm_render_value
.
Cookbook¶
Cookbook¶
Netgen Layouts provides around 10 officially supported extension points, ranging from simpler ones like creating custom layout types to advanced and rarely used ones like creating custom conditions and targets for layout matching process. The following chapters will go through each of these extension points and detail the process of creating your own layout types, blocks, query types and so on.
Creating a custom layout type¶
Netgen Layouts ships with some layout types (from simple ones with one zone, to more complicated ones with 8 zones), which are readily available to be used in your own projects without any additional configuration.
If none of those layout types satisfy your needs, you can create your own. Creating your own layout type is split into three parts:
- Basic configuration
- Creating frontend and backend Twig templates for rendering the layout
- Connecting the templates with your layout type
We will demonstrate the process by creating a simple layout type with two zones:
left
and right
.
Basic configuration¶
To register a new layout type in Netgen Layouts, add the following YAML config:
netgen_block_manager:
layout_types:
my_layout:
name: 'My layout'
icon: '/path/to/icon.svg'
zones:
left:
name: 'Left'
right:
name: 'Right'
This specifies that our new layout type has a my_layout
identifier, that its
human readable name is My layout
and that it has two zones, left
and
right
. It also specifies the full path to layout type icon.
Tip
Since layout type icons are used in several places in admin interface and Block Manager app in different sizes, it is recommended to create your own icons in SVG format, rather than PNG to allow the CSS to resize the icons.
Creating frontend and backend Twig templates¶
Netgen Layouts uses two separate templates to render the layout on the frontend and in the backend. By default, all frontend templates and backend templates for built-in layout types are based on Bootstrap grid. Backend templates, used by the Block Manager app, will be rendered correctly as long as you provide the valid Bootstrap markup. On the other hand, to render frontend templates correctly, you will need to include CSS for Bootstrap Grid component in your site.
Note
It is possible to switch all frontend templates to use a different grid like Flexbox, however at this time, only Bootstrap implementation of templates is available.
Creating a backend template¶
Backend templates for layout types usually do not have any logic, apart from
HTML markup that specifies where each of the layout type zones goes within
Bootstrap grid. If needed, backend templates can access the currently rendered
layout with a Twig variable named layout
.
The following template shows an example of how would the backend template look for layout type we configured earlier:
{# @App/layouts/api/my_layout.html.twig #}
<div class="row">
<div class="col-md-8">
<div data-zone="left"></div>
</div>
<div class="col-md-4">
<div data-zone="right"></div>
</div>
</div>
It is important for backend templates to have <div data-zone="my_zone"></div>
element with correct zone identifier (replacing my_zone
) for every zone
configured.
Creating a frontend template¶
Frontend templates are usually more complicated, since they need to provide the code to actually render layout zones by themselves.
All markup in frontend templates for your layout types needs to be inside a Twig
block named layout
and they always need to extend a special
ngbm.pageLayoutTemplate
variable available in the template. This variable
will always hold the name of the main pagelayout of your app, which is either
configured manually through Netgen Layouts configuration, or in some cases
picked up automatically from available configuration of your app (if using
eZ Platform for example).
This template has access to currently rendered layout via Twig variable named
ngbm.layout
and each zone is rendered via ngbm_render_zone
Twig tag.
Since zone does not have a template of its own, this tag simply renders all
blocks one after another. Accessing a zone via ngbm.layout.zone('left')
function will either return the requested zone, or the zone in a shared layout
if one is configured for the specified zone, so no additional code is required
to handle zones connected to shared layouts.
The complete frontend template for your custom layout type with two zones might look something like this:
{# @App/layouts/my_layout.html.twig #}
{% extends ngbm.pageLayoutTemplate %}
{% block layout %}
<div class="container">
<div class="row">
<div class="col-lg-8">
{% if ngbm.layout.zone('left') is not empty %}
{% ngbm_render_zone ngbm.layout.zone('left') %}
{% endif %}
</div>
<div class="col-lg-4">
{% if ngbm.layout.zone('right') is not empty %}
{% ngbm_render_zone ngbm.layout.zone('right') %}
{% endif %}
</div>
</div>
</div>
{% endblock %}
Connecting the templates with your layout type¶
To activate the frontend and backend templates you defined, you will need to configure them through the view layer configuration. Read up on what a view layer is and the corresponding terminology in documentation specific to view layer itself.
Currently, two matchers are implemented in the view layer for layout view:
layout\type
- Matches on layout type of a layoutlayout\shared
- Matches on “shared” flag of a layout
Most of the time, you will use layout\type
matcher for configuring templates
for your custom layout types. The reason for this is that shared layouts are
never rendered directly on the frontend so there is no really need for using
layout\shared
matcher. The reason for its existence is that it is used in
the administration interface of Netgen Layouts.
The following is an example config that enables the two templates we created:
netgen_block_manager:
view:
layout_view:
default:
my_layout:
template: "@App/layouts/my_layout.html.twig"
match:
layout\type: my_layout
api:
my_layout:
template: "@App/layouts/api/my_layout.html.twig"
match:
layout\type: my_layout
api_version: 1
At this point, your new layout type is ready for usage.
Creating a custom block¶
Similar to layout types, when creating a custom block, you need a bit of configuration and some templates, but since blocks almost always need some custom logic, you will also need to create a PHP class that will handle custom functionalities of a block. In the following examples, we will show creating a custom block that can render a Markdown document.
When creating a custom block, you will often run into two entities mentioned in code and configuration: a block definition, and a block type. Before you actually create a custom block, it is important to understand a difference between a block definition and a block type.
Difference between block definition & block type¶
Block definition is the central entity you will be creating when creating a custom block. As the name implies, block definition defines how your custom block behaves. This includes specifying what parameters will the block have and what type are they of and if the block has a collection or not. It also gives you a possibility to write your own custom behaviour for a block, based on block parameters. In case of container blocks, it specifies which placeholders the container block has.
Each block definition can have multiple block types. Block type is nothing more than a starting configuration used when creating a block in a layout. In Block Manager app, block types are what is shown on the left side and what you drag and drop to a zone in a layout. Creating block types for a certain block definition requires only a couple of lines of configuration where you would specify starting values for block label, block view, block item view and block parameters.
Once you create a block in a layout, it doesn’t store the information from which block type it was created, it only stores the block definition. When you think about it, this makes sense. Since block type is a starting configuration for a block you’re adding to a layout, and that configuration can change in the lifecycle of a block, there is no benefit in storing the information which block type was used to create the block. On the other hand, block definition needs to be stored because it defines how block parameters will be validated, what custom behaviour the block has and so on.
Configuring a new block definition¶
To register a new block definition in Netgen Layouts, you will need the following configuration:
netgen_block_manager:
block_definitions:
my_markdown:
name: 'My markdown block'
icon: '/path/to/icon.svg'
view_types:
my_markdown:
name: 'My markdown block'
This configuration example adds a new block definition with my_markdown
identifier, which as a human readable name My markdown block
and has one
view type, also called my_markdown
. It also specifies the full path to the
icon of the block.
View type is nothing more than an identifier of a template which will be used to render the block. Every block definition needs at least one view type.
Note
By convention, in built in blocks, if a block definition has only one view type, like above, that view type will have the same identifier as the block definition itself.
Creating a PHP service for a block definition¶
Every block definition needs a single PHP class that specifies the entire
behaviour of a block. This class needs to implement
Netgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandlerInterface
interface which specifies a number of methods for you to implement. To simplify
implementing new block definitions, an abstract class exists
(Netgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandler
) which has
all of those methods implemented with default and empty implementations,
reducing the need for writing boilerplate code.
Let’s create a basic block definition handler class:
<?php
namespace AppBundle\Block\BlockDefinition\Handler;
use Netgen\BlockManager\API\Values\Block\Block;
use Netgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandler;
use Netgen\BlockManager\Block\DynamicParameters;
use Netgen\BlockManager\Parameters\ParameterBuilderInterface;
class MyMarkdownHandler extends BlockDefinitionHandler
{
/**
* Builds the parameters by using provided parameter builder.
*
* @param \Netgen\BlockManager\Parameters\ParameterBuilderInterface $builder
*/
public function buildParameters(ParameterBuilderInterface $builder)
{
}
/**
* Adds the dynamic parameters to the $params object for the provided block.
*
* @param \Netgen\BlockManager\Block\DynamicParameters $params
* @param \Netgen\BlockManager\API\Values\Block\Block $block
*/
public function getDynamicParameters(DynamicParameters $params, Block $block)
{
}
/**
* Returns if the provided block is dependent on a context, i.e. current request.
*
* @param \Netgen\BlockManager\API\Values\Block\Block $block
*
* @return bool
*/
public function isContextual(Block $block)
{
}
}
Specifying block parameters¶
First method we will look at is buildParameters
method. By using an object
called parameter builder and adding parameter specifications to it, this method
will specify which parameters your custom block will have. Details on how the
parameter builder works, what parameter types exist and how to implement custom
parameter type are explained in dedicated chapter.
Let’s add a custom parameter to our block which will serve as an input for raw Markdown content:
use Netgen\BlockManager\Parameters\ParameterType;
public function buildParameters(ParameterBuilderInterface $builder)
{
$builder->add('content', ParameterType\TextType::class);
}
Notice that we didn’t specify the human readable labels for the parameters.
That’s because they are generated automatically via translation system. To
create the correct labels for your block parameters, you need to add one string
to ngbm
translation catalog for every parameter in your block with the
format block.<block_definition>.<parameter_name>
where block_definition
and parameter_name
are placeholders that need to be replaced with correct
values. So, for our custom Markdown block definition, the translation file would
look something like this:
block.my_markdown.content: 'Content'
Custom block behaviour¶
Second method in our handler example above is called getDynamicParameters
.
This method is used for your own custom logic. Anything goes in this method. You
can inject dependencies into your block definition handler, use them here, do
some processing based on provided instance of a block or some other parameters
you provide when rendering a block manually and so on.
After all processing is done, this method needs to set the parameters which will
be injected into template when block is rendered. The parameters are set to an
instance of Netgen\BlockManager\Block\DynamicParameters
object. This object
implements ArrayAccess
interface, so you can use array notation to add the
parameters. Each of the values can either be a regular scalar, array, object and
so on, or it can be a closure, which will transparently be called to calculate
the value at the moment the parameter is used inside the block template.
In case of our Markdown handler, we will need to inject a Markdown parser into
our handler, and use it in this method to parse the raw Markdown into HTML. We
will be using Michelf\MarkdownInterface
, Markdown parser which is already
pre-installed with Netgen Layouts:
/**
* @var \Michelf\MarkdownInterface
*/
protected $markdownParser;
public function __construct(MarkdownInterface $markdownParser)
{
$this->markdownParser = $markdownParser;
}
public function getDynamicParameters(DynamicParameters $params, Block $block)
{
$rawContent = $block->getParameter('content')->getValue();
$params['html'] = $this->markdownParser->transform($rawContent);
}
Contextual blocks¶
A contextual block is a block which needs the current context (i.e. current request) to function. For example, a block that needs a currently displayed location or content from eZ Platform is a contextual block.
In order for the system to work properly with contextual blocks,
isContextual
method needs to be implemented, which signals to the system if
the block is contextual or not. You can use any property of the provided block
to decide if it contextual or not, but in our case, we will simply return
false
:
public function isContextual(Block $block)
{
return false;
}
Defining the Symfony service for our handler¶
To connect the created handler with block definition configuration, we need to register the handler in Symfony DIC. We also need to specify a service for Markdown parser we used in the handler:
services:
app.markdown:
class: Michelf\MarkdownExtra
app.block.block_definition.handler.markdown:
class: AppBundle\Block\BlockDefinition\Handler\MyMarkdownHandler
arguments:
- "@app.markdown"
tags:
- { name: netgen_block_manager.block.block_definition_handler, identifier: my_markdown }
This configuration is a fairly regular specification of services in Symfony,
however, to correctly recognize our PHP class as a block definition handler, we
need to tag it with netgen_block_manager.block.block_definition_handler
tag
and attach to it an identifier
key with a value which equals to the
identifier of block definition we configured at the beginning (in this case
my_markdown
).
Specifying block view templates¶
Every view type in your block definition needs to have two templates, one for
frontend and one for backend. If you remember, we specified that our
my_markdown
block definition has one view type, also called my_markdown
.
Frontend block template¶
Let’s create a template for displaying the block in the frontend with
my_markdown
view type. Every frontend template for the block needs to extend
from @NetgenBlockManager/block/block.html.twig
and all content of the
template needs to be inside Twig block called content
. The currently
rendered block is accessible via block
variable which you can use to access
block parameters specified in the handler as well as any dynamic parameters in
the block.
Tip
View type templates for built in block definitions are also a great source of inspiration, so make sure to give them a look.
Our frontend template for the Markdown block definition will simply output the parsed Markdown which is provided by the handler:
{# @App/blocks/my_markdown/my_markdown.html.twig #}
{% extends '@NetgenBlockManager/block/block.html.twig' %}
{% block content %}
{{ block.dynamicParameter('html')|raw }}
{% endblock %}
Backend block template¶
As for backend, in this specific case, the template will look almost the same (since all we want is to render the parsed Markdown), save for the different template used to extend from.
In general, all backend templates need to extend from
@NetgenBlockManager/api/block/block.html.twig
(notice that this template is
different from the frontend base template, this one is in an api
folder).
In most cases, backend template will be simpler than the frontend one, without
any design specific markup and so on. Everything you can use in frontend
templates is also available here, meaning that you can use the block
variable to access the block and its parameters.
Going back to our example backend template, it will look like this:
{# @App/blocks/api/my_markdown/my_markdown.html.twig #}
{% extends '@NetgenBlockManager/api/block/block.html.twig' %}
{% block content %}
{{ block.dynamicParameter('html')|raw }}
{% endblock %}
Connecting the templates with your block definition¶
To activate the frontend and backend templates you defined, you will need to configure them through the view layer configuration. Read up on what a view layer is and the corresponding terminology in documentation specific to view layer itself.
Currently, two matchers are implemented in the view layer for block view:
block\definition
- Matches on block definition of a blockblock\view_type
- Matches on view type of a block
If you are creating a block which will only have a single view type, you can
omit the block\view_type
matcher and use only block\definition
matcher,
which will make sure that templates you defined will be applied to any future
view types of your block automatically.
The following is an example config that enables the two templates we created:
netgen_block_manager:
view:
block_view:
default:
my_markdown:
template: "@App/blocks/my_markdown/my_markdown.html.twig"
match:
block\definition: my_markdown
# View type matcher is optional
block\view_type: my_markdown
api:
my_markdown:
template: "@App/blocks/api/my_markdown/my_markdown.html.twig"
match:
block\definition: my_markdown
# View type matcher is optional
block\view_type: my_markdown
api_version: 1
The following configuration shows how you can specify a fallback template that will be applied to all block view types that do not specify their own template rules:
netgen_block_manager:
view:
block_view:
default:
my_markdown:
template: "@App/block/my_markdown.html.twig"
match:
block\definition: my_block
api:
my_markdown:
template: "@App/api/block/my_markdown.html.twig"
match:
block\definition: my_block
Note
Take care to specify the fallback rule at the bottom of all other rules, since the first rule that matches will be used when searching for templates.
After you have defined the configuration for the view layer, your block is ready for usage.
Defining block types for your block definition¶
Remember block types and how we said that block types are a starting configuration for a block definition? Remember how we said that block types are the thing that is shown on the left hand side in the Block Manager app?
When you create a custom block definition, Netgen Layouts internally creates for you a single block type with the same name as block definition with empty default configuration, and adds it to a block type group called “Custom blocks”. This is to enable the block definition to be displayed in the interface so you can actually add it to a layout.
If you want to create another starting configuration for your block definition, you can do so by configuring an additional block type which will also be automatically added to a “Custom blocks” group. For example:
netgen_block_manager:
block_types:
my_markdown_v2:
name: 'My Markdown block with default title'
icon: '/path/to/icon.svg'
definition_identifier: my_markdown
defaults:
parameters:
content: '# Some default title'
This configuration defines a block type with my_markdown_v2
identifier,
which sets a default value for content
parameter.
If you want to define some other group where your block type should live, you
can do so. In that case, the block type will not be shown in the Custom blocks
group, but in the group you specified. You can use the configuration similar to
this:
netgen_block_manager:
block_type_groups:
my_group:
name: 'My group'
block_types: [my_markdown_v2, second_block_type, other_block_type]
Tip
Once you start adding more and more block types for your block definition, you might decide that you no longer need the automatically created block type with empty configuration. In that case, you might want to simply disable it:
netgen_block_manager:
block_types:
my_markdown:
enabled: false
Creating a block plugin¶
Block plugins are a simple way to extend the behavior of existing blocks, without having to touch their original implementations. Block plugins can be used to add new parameters to the block (both normal and dynamic ones) or to remove or redefine the existing parameters. One block plugin can extend one block or all existing blocks.
Implementing the block plugin class¶
Implementing a block plugin class is quite similar to implementing a block
handler class itself. Block plugin needs to implement
Netgen\BlockManager\Block\BlockDefinition\Handler\PluginInterface
, which
provides methods to work with block parameters. You can also extend the provided
abstract class (Netgen\BlockManager\Block\BlockDefinition\Handler\Plugin
) to
cut down on boilerplate code to write.
If you extend the abstract plugin class, the only required method to implement
is getExtendedHandler
, which needs to return fully qualified class name of
the handler you wish to extend.
Tip
You can also return the FQCN of the block handler interface
(Netgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandlerInterface
)
if you wish to extend all existing blocks, or you can return an array of
FQCNs if you wish to extend a curated list of blocks.
Our plugin would then look like this:
<?php
namespace AppBundle\Block\BlockDefinition\Handler;
use Netgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandlerInterface;
class MyPlugin extends Plugin
{
/**
* Returns the fully qualified class name of the handler which this
* plugin extends.
*
* @return string|string[]
*/
public static function getExtendedHandler()
{
return BlockDefinitionHandlerInterface::class;
}
}
Ofcourse, our plugin is not very useful right now, so let’s add some parameters.
Parameters are added by implementing the buildParameters
method, which works
in the exact same way as the buildParameters
method in the block handler:
/**
* Builds the parameters by using provided parameter builder.
*
* @param \Netgen\BlockManager\Parameters\ParameterBuilderInterface $builder
*/
public function buildParameters(ParameterBuilderInterface $builder)
{
$builder->add('my_param', ParameterType\TextLineType::class);
// You can even remove existing params
$builder->remove('existing_param');
// Or you can modify existing ones
$builder->get('test')->setDefaultValue('test');
}
If you wish to add some business logic to the block, you can do that too, by
implementing the getDynamicParameters
method, which, again, works in the
exact same way as the getDynamicParameters
method in the block handler:
/**
* Adds the dynamic parameters to the $params object for the provided block.
*
* @param \Netgen\BlockManager\Block\DynamicParameters $params
* @param \Netgen\BlockManager\API\Values\Block\Block $block
*/
public function getDynamicParameters(DynamicParameters $params, Block $block)
{
$params['some_param'] = 'some_value';
}
Tip
You can ofcourse inject any service into your plugin and use in this method.
Registering the block plugin¶
To register the block plugin in the system, add it as a Symfony service, and tag
it with netgen_block_manager.block.block_definition_handler.plugin
tag.
app.block.block_definition.handler.plugin.my_plugin:
class: AppBundle\Block\BlockDefinition\Handler\MyPlugin
tags:
- { name: netgen_block_manager.block.block_definition_handler.plugin }
You can also add a priority
attribute to the tag, to control the order in
which your plugins will be executed.
Creating a custom container block¶
Containers are blocks like any other, so everything described in chapter on creating a custom block applies here.
The difference between regular blocks and containers is that containers can contain other blocks. This is achieved by using something called a placeholder, which is nothing more than a label which is applied to every child block in a container. When rendering the container, you can use this label to specify where in the template will all blocks with that label be rendered. As with zones, all blocks with a specified label will be rendered one after another.
Think of a placeholder in the container block as a lightweight variant of a zone in a layout. When you drag and drop a new block to a placeholder in a container, placeholder label is automatically assigned to the new block so it can be rendered when requested.
Note
Currently, it is not possible to add containers within containers.
Container definition handler¶
When creating a custom block definition handler for a container block, instead
of extending from Netgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandler
abstract class, you will extend from
Netgen\BlockManager\Block\BlockDefinition\ContainerDefinitionHandler
which
is also an abstract class. What is left for you to do is to define which
placeholders your new container block has by implementing
getPlaceholderIdentifiers
method. For example, Two columns
container
block provided by Netgen Layouts looks like this:
<?php
namespace Netgen\BlockManager\Block\BlockDefinition\Handler\Container;
use Netgen\BlockManager\Block\BlockDefinition\ContainerDefinitionHandler;
class TwoColumnsHandler extends ContainerDefinitionHandler
{
/**
* Returns placeholder identifiers.
*
* @return array
*/
public function getPlaceholderIdentifiers()
{
return array('left', 'right');
}
}
Twig templates¶
Frontend Twig templates for container blocks have all the same features as Twig
templates for regular blocks. The only difference is that in templates for
container blocks, you can use ngbm_render_placeholder
Twig function to
render all blocks which are located in specified placeholder.
For example, frontend Twig template for Two columns
block provided by
Netgen Layouts looks like this:
{% extends '@NetgenBlockManager/block/block.html.twig' %}
{% block content %}
<div class="row">
<div class="col-md-6">
{{ ngbm_render_placeholder(block, 'left') }}
</div>
<div class="col-md-6">
{{ ngbm_render_placeholder(block, 'right') }}
</div>
</div>
{% endblock %}
As for backend Twig templates for container blocks, they are similar to backend Twig templates for layout types. They do not need custom logic to render the blocks, except specific HTML elements used as markers for block placeholders:
{% extends '@NetgenBlockManager/api/block/block.html.twig' %}
{% block content %}
<div class="row">
<div class="col-md-6">
<div data-placeholder="left" data-receiver></div>
</div>
<div class="col-md-6">
<div data-placeholder="right" data-receiver></div>
</div>
</div>
{% endblock %}
Basically, for every placeholder in your container block, you need to have a
<div data-placeholder="my_placeholder" data-receiver></div>
element with a
placeholder identifier in data-placeholder
attribute.
Adding collections to blocks¶
As you are probably aware, blocks can have collections attached to them, which provide block items to the block. Block definition can control if the block can have a collection by specifying it in the block definition configuration. By default, blocks do not use collections, so if you want to allow your custom block definitions to use collections, configure it like this:
netgen_block_manager:
block_definitions:
my_block:
collections: ~
Once you specify that your block definition can use collections, all blocks will automatically be created with a manual collection attached to the block.
Note
Currently, every block can have only one collection with an identifier named
default
.
You can also configure which items and query types are valid for a collection. That way, you can specify, for example, that your collection can only have manual items or only a dynamic collection, or any combination of two.
To specify which item are allowed within the collection, use the config similar to this:
netgen_block_manager:
block_definitions:
my_block:
collections:
default:
# Set to an empty array to disable manual collection
valid_item_types: [my_item_type]
To specify which query types are allowed within the collection, use the config similar to this:
netgen_block_manager:
block_definitions:
my_block:
collections:
default:
# Set to an empty array to disable dynamic collection
valid_query_types: [my_query]
Accessing the collection and items in the template¶
The collection provides the block items to the block in form of a collection
result set object (Netgen\BlockManager\Collection\Result\ResultSet
) which is
a collection of result objects (Netgen\BlockManager\Collection\Result\Result
)
which themselves are a simple wrapper around the single item in a collection.
In the Twig templates for your block views, all collection results are
accessible through collections
variable, which you can use to iterate over
the items in a collection and render them:
{% for result in collections.default %}
{{ ngbm_render_item(result.item, block.itemViewType) }}
{% endfor %}
When rendering an item, you need to specify with which item view type it will be
rendered (block.itemViewType
in the above example). As with block view types,
item view type is nothing more than an identifier of a template which will be
used to render the item. Every block view type can define which item view types
it supports with the configuration like this:
netgen_block_manager:
block_definitions:
my_block:
name: 'My block'
view_types:
first:
name: 'First'
item_view_types:
item_type_1:
name: 'Item type 1'
item_type_2:
name: 'Item type 2'
second:
name: 'Second'
With this, we specified that first
block view type supports item_type_1
and item_type_2
item view types, while second
block view type does not
specify any specific item view types.
For every view type, an item view type called standard
will be added
automatically to configuration. This is to make it easier to create item view
type templates for simpler blocks. If you wish to disable this standard
item
view type, you can do so like this:
netgen_block_manager:
block_definitions:
my_block:
view_types:
my_view_type:
item_view_types:
standard:
enabled: false
Tip
In your Twig templates for block view types, you can ofcourse choose not to use
the item view type stored in a block (block.itemViewType
), but use a
hardcoded one, or mix the hardcoded item view type with the one stored in a
block and so on.
Using themes¶
Themes in Netgen Layouts provide a way to quickly override any frontend layout, block and block item templates provided by Netgen Layouts.
Once configured, the override process works based on convention. That is, you only need to place templates at certain paths, and they will automatically be picked up and used instead of the built in templates.
Warning
Currently, only frontend templates use themes. Overriding backend templates still works in very much the same way as always.
Netgen Layouts theme support defines two concepts: a design, and a theme, design being a collection of themes and theme being a collection of paths where templates are being loaded from.
When searching for a template, the system looks at the currently configured design and starts looking for the template in all themes within the design, one by one. First path from the first theme which exists for the specified template is used. This makes it possible to override any built in theme by creating a design that contains the original theme and your new theme that only has the overriden templates.
The system also comes with one built in theme called standard
, which is
always used as a fallback when no templates are found in your custom
design/themes. All frontend templates for layouts, blocks and block items are
part of this built in theme.
Getting started with themes¶
To specify which design your frontend will use, you need to add it to configuration and specify the currently used design:
netgen_block_manager:
design_list:
my_design: [my_theme, my_other_theme]
my_second_design: [my_theme, my_third_theme]
design: my_design
With above configuration, we defined two designs, called my_design
and
my_second_design
, with their themes, and we specified that currently used
design is my_design
.
Tip
If you’re using eZ Platform, currently used design can be siteaccess aware, meaning, you can use configuration similar to this to specify different designs for different siteaccesses or siteaccess groups:
netgen_block_manager:
system:
frontend_group:
design: my_design
other_group:
design: my_second_design
Tip
If you only ever intend to use one theme and knowing that standard
theme
is always available and ready to be used, you don’t need to configure
anything, no design, no themes, and you can simply use standard
theme for your own templates.
Theme folders¶
For every theme you defined, system reserves some special folders where you need to place the templates for them to be recognized. The folders are, in descending order of priority:
app/Resources/views/ngbm/themes/<THEME NAME>
%twig.default_path%/ngbm/themes/<THEME NAME>
(for Symfony 3.4+, usuallytemplates/ngbm/themes/<THEME NAME>
)<PATH TO BUNDLE>/Resources/views/ngbm/themes/<THEME_NAME>
For folders inside the bundles, the bundles activated later in the kernel class have higher priority.
As an example, if you have a design with two themes, theme1
and theme2
,
and two bundles active, App\FirstBundle
and App\SecondBundle
(this one
being activated later in the kernel), the system will look in the following
folders for templates, in descending order of priority (this includes the
fallback to standard
theme too and Symfony 3.4+ specific path):
app/Resources/views/ngbm/themes/theme1
templates/ngbm/themes/theme1
src/SecondBundle/Resources/views/ngbm/themes/theme1
src/FirstBundle/Resources/views/ngbm/themes/theme1
app/Resources/views/ngbm/themes/theme2
templates/ngbm/themes/theme2
src/SecondBundle/Resources/views/ngbm/themes/theme2
src/FirstBundle/Resources/views/ngbm/themes/theme2
app/Resources/views/ngbm/themes/standard
templates/ngbm/themes/standard
src/SecondBundle/Resources/views/ngbm/themes/standard
src/FirstBundle/Resources/views/ngbm/themes/standard
Using the theme templates¶
There are two usecases for using themes:
- Overriding the templates for existing layouts or blocks
- Creating templates for custom layouts or blocks
In both cases, using the theme templates is exactly the same. Once you define
a design and themes, you can reference the templates with a special Twig
namespace called @ngbm
, followed by the template path, where template path
is anything AFTER the theme name in the template path on filesystem. For
example, @ngbm/block/my_block.html.twig
will look for the template in the
following paths:
app/Resources/views/ngbm/themes/theme1/block/my_block.html.twig
templates/ngbm/themes/theme1/block/my_block.html.twig
src/SecondBundle/Resources/views/ngbm/themes/theme1/block/my_block.html.twig
- …
Overriding the templates for existing layouts or blocks¶
Overriding the templates for existing layouts and blocks is made really simple by using themes, since you don’t need any configuration to override one of the existing templates (apart from configuring the design and themes, obviously).
Lets take an example of a built in layout with the identifier layout_1
.
This template is located on disk at
vendor/netgen/block-manager-standard/bundle/Resources/views/ngbm/themes/standard/layout/layout_1.html.twig
path. As you can see, it’s part of the standard
theme, meaning, it can be
overriden by your themes, just by placing the new template at the correct path.
Any of the following paths would be valid (in no specific order of priority):
app/Resources/views/ngbm/themes/theme1/layout/layout_1.html.twig
src/FirstBundle/Resources/views/ngbm/themes/theme1/layout/layout_1.html.twig
app/Resources/views/ngbm/themes/standard/layout/layout_1.html.twig
src/SecondBundle/Resources/views/ngbm/themes/standard/layout/layout_1.html.twig
- …
Creating templates for custom layouts or blocks¶
Apart from referencing the templates with a new syntax, creating and using
templates for custom blocks and layouts does not differ. You still need to
create block_view
or layout_view
configuration to specify which template
your block will use. For example, to specify the template for a block with
identifier my_block
, you would use the following block_view
configuration. Notice how we’re referencing the template with our special
@ngbm
Twig namespace:
netgen_block_manager:
view:
block_view:
default:
my_block\my_view_type:
template: "@ngbm/block/my_block.html.twig"
match:
block\definition: my_block
block\view_type: my_view_type
The template itself would look like this:
{% extends '@ngbm/block/block.html.twig' %}
{% block content %}
...
{% endblock %}
As you can see, you can even reference the built in templates with @ngbm
Twig namespace in your templates, for extending them, including them and so on.
Warning
Not all built in templates can be referenced with @ngbm
namespace.
Only layout, block (including the base block template) and item templates
can be used with @ngbm
namespace. Referencing all other templates still
works by using @NetgenBlockManager
namespace.
After you place your template in one of the paths discussed earlier, your template will automatically be picked up and used for rendering your block.
Adding custom view types to blocks¶
Just as you can specify that your own custom blocks have certain view types, you can extend existing blocks to add your own view types to them. Configuration to do so is completely the same as with adding a custom block.
When adding a block view type, you need to specify them in block definition settings, as well as configure the template used for them (both for frontend and backend).
The following configuration shows an example how to add a custom view type to
existing list
block definition called list_numbered
and how to specify
the templates that will be used:
netgen_block_manager:
block_definitions:
list:
view_types:
list_numbered:
name: 'List (numbered)'
view:
block_view:
default:
list\numbered:
template: "@App/block/list/list_numbered.html.twig"
match:
block\definition: list
block\view_type: list_numbered
api:
list\numbered:
template: "@NetgenBlockManager/api/block/list/list.html.twig"
match:
block\definition: list
block\view_type: list_numbered
Note that template rule for backend (api
context) reuses the template for
list view type already available in the list
block. This is to make sure
that both list
and list_numbered
view types are displayed in the same
way in the backend. This is of course optional as you can specify your own
template for the backend.
Adding a custom item view type¶
You can also add custom item view types to every existing block and its view types.
The following configuration shows an example how to add a custom item view type
called standard_with_intro
to already existing block view type in list
block definition:
netgen_block_manager:
block_definitions:
list:
view_types:
list:
item_view_types:
standard_with_intro:
name: 'Standard (with intro)'
You can specified the template to be used like this:
netgen_block_manager:
view:
item_view:
default:
my_item\standard_with_intro:
template: "@App/items/my_item/standard_with_intro.html.twig"
match:
item\value_type: my_item
item\view_type: standard_with_intro
api:
my_item\standard_with_intro:
template: "@App/items/api/my_item/standard_with_intro.html.twig"
match:
item\value_type: my_item
item\view_type: standard_with_intro
Tip
If using Netgen Layouts in eZ Platform, every content view type is also a
valid item view type. Because of that, you don’t need to duplicate templates
from eZ Platform in Netgen Layouts to display eZ locations. For example, if
you have a listitem
content view type for your content, you can use it
just by specifying that some of your block view types have a listitem
item view type and selecting in the block configuration in the right sidebar.
Note
In case of eZ Platform, it is always a good idea to specify a fallback content view template that will be applied to all content types, since Netgen Layouts does not limit which eZ content types can be added to blocks.
Disabling existing view types in blocks¶
You can disable any existing block view types or item view types to stop them from showing up in Block Manager app.
The following configuration shows an example how to disable a block view type:
netgen_block_manager:
block_definitions:
list:
view_types:
some_view_type:
enabled: false
The following configuration shows an example how to disable an item view type:
netgen_block_manager:
block_definitions:
list:
view_types:
list:
item_view_types:
some_item_view_type:
enabled: false
Note that when you disable a block view type or an item view type, they will still be used by the rendering engine. However, you will not be able to save the block configuration any more in Block Manager app until you change the (item) view type to some other enabled one.
Creating custom query types¶
When installed on pure Symfony, Netgen Layouts comes with no built in query types which means you can only use manual collections in your blocks.
Tip
If you install Netgen Layouts on eZ Platform, you will get a single query type that will be automatically used when switching a collection from manual to dynamic in blocks.
When you implement your own query types, you will be able to use dynamic collections, and if you implement more than one query type, you will be able to select which query type to use when switching to dynamic collection in a block.
To implement a query type, you need a bit of configuration and a PHP class that will handle custom functionalities of a query type. In the following examples, we will show creating a custom query type that will use eZ search engine to search for items by text.
Configuring a new query type¶
To register a new query type in Netgen Layouts, you will need the following configuration:
netgen_block_manager:
query_types:
my_search:
name: 'My search'
This configuration specifies a new query type with my_search
identifier and
My search
human readable name.
Creating a PHP service for a query type¶
Every query type needs a single PHP class that specifies the entire behaviour of
a query type. This class needs to implement
Netgen\BlockManager\Collection\QueryType\QueryTypeHandlerInterface
interface
which specifies a number of methods for you to implement.
Let’s create a basic query type handler class:
<?php
namespace AppBundle\Collection\QueryType\Handler;
use Netgen\BlockManager\API\Values\Collection\Query;
use Netgen\BlockManager\Collection\QueryType\QueryTypeHandlerInterface;
use Netgen\BlockManager\Parameters\ParameterBuilderInterface;
class MySearchHandler implements QueryTypeHandlerInterface
{
/**
* Builds the parameters by using provided parameter builder.
*
* @param \Netgen\BlockManager\Parameters\ParameterBuilderInterface $builder
*/
public function buildParameters(ParameterBuilderInterface $builder)
{
}
/**
* Returns the values from the query.
*
* @param \Netgen\BlockManager\API\Values\Collection\Query $query
* @param int $offset
* @param int $limit
*
* @return mixed[]
*/
public function getValues(Query $query, $offset = 0, $limit = null)
{
}
/**
* Returns the value count from the query.
*
* @param \Netgen\BlockManager\API\Values\Collection\Query $query
*
* @return int
*/
public function getCount(Query $query)
{
}
/**
* Returns if the provided query is dependent on a context, i.e. currently displayed page.
*
* @param \Netgen\BlockManager\API\Values\Collection\Query $query
*
* @return bool
*/
public function isContextual(Query $query)
{
}
}
Specifying query type parameters¶
First method we will look at is buildParameters
method. By using an object
called parameter builder and adding parameter specifications to it, this method
will specify which parameters your custom query type will have. Details on how
the parameter builder works, what parameter types exist and how to implement
custom parameter type are explained in dedicated chapter.
Let’s add a custom parameter to our query type which will serve as an input for search text:
use Netgen\BlockManager\Parameters\ParameterType;
public function buildParameters(ParameterBuilderInterface $builder)
{
$builder->add('search_text', ParameterType\TextType::class);
}
Notice that we didn’t specify the human readable label for the parameter.
That’s because it is generated automatically via translation system. To
create the correct labels for your query type parameters, you need to add one
string to ngbm
translation catalog for every parameter in your query type
with the format query.<query_type>.<parameter_name>
where query_type
and
parameter_name
are placeholders that need to be replaced with correct values.
So, for our custom search query type, the translation file would look something like this:
query.my_search.search_text: 'Search text'
Fetching the items¶
Second method in our handler example above is called getValues
. This method
is used for fetching the items from a query.
This method needs to return the array of domain objects that will be automatically converted to block items.
Warning
Query types are invisioned to always return only those items that can be safely rendered on the frontend. In other words, items returned from query types will always be presumed by the system to be visible and available. For example, in eZ Platform case, this means that query types need to return only visible items in correct language that the current user has access to.
Tip
In case of eZ Platform, query types can return the list of eZ ContentInfo
or Location
objects.
/**
* @var \eZ\Publish\API\Repository\SearchService
*/
protected $searchService;
public function __construct(SearchService $searchService)
{
$this->searchService = $searchService;
}
public function getValues(Query $query, $offset = 0, $limit = null)
{
$searchResult = $this->searchService->findLocations(
$this->buildQuery($query, false, $offset, $limit)
);
return array_map(
function (SearchHit $searchHit) {
return $searchHit->valueObject;
},
$searchResult->searchHits
);
}
/**
* Builds the query from current parameters.
*
* @param \Netgen\BlockManager\API\Values\Collection\Query $query
* @param bool $buildCountQuery
* @param int $offset
* @param int $limit
*
* @return \eZ\Publish\API\Repository\Values\Content\LocationQuery
*/
protected function buildQuery(Query $query, $buildCountQuery = false, $offset = 0, $limit = null)
{
$locationQuery = new LocationQuery();
$criteria = array(
new Criterion\FullText($query->getParameter('search_text')->getValue()),
new Criterion\Visibility(Criterion\Visibility::VISIBLE),
);
$locationQuery->filter = new Criterion\LogicalAnd($criteria);
$locationQuery->limit = 0;
if (!$buildCountQuery) {
$locationQuery->offset = $offset;
$locationQuery->limit = $limit;
}
return $locationQuery;
}
As you can see, getValues
method simply builds a location query for eZ
search engine and returns the list of found eZ locations. Conversion to block
items is handled automatically by Netgen Layouts.
Fetching the item count¶
To retrieve the item count from the query type, we use the getCount
method:
public function getCount(Query $query)
{
$searchResult = $this->searchService->findLocations(
$this->buildQuery($query, true)
);
return $searchResult->totalCount;
}
Contextual queries¶
A contextual query is a query which needs the current context (i.e. current page) to run. Think of a situation where you have a layout with a block which shows top 5 items from the category it is applied to. Contextual query removes the need to create five different layouts for five different categories just so you can change the parent category from which to fetch the items. Instead, in a contextual query, you will take the currently displayed category and use it as the parent, making it possible to have only one layout for all five different categories.
In order for the system to work properly with contextual queries, one method is
used, isContextual
, which signals to the system if the query is contextual
or not. Most of the time, this method will return a value of a boolean parameter
specified inside of the query which decides if a query is contextual or not, for
example:
public function isContextual(Query $query) { return $query->getParameter('use_current_location')->getValue() === true; }
In our case, we will simply return false
from isContextual
method:
public function isContextual(Query $query)
{
return false;
}
Defining the Symfony service for our handler¶
To connect the created handler with query type configuration, we need to register the handler in Symfony DIC:
services:
app.collection.query_type.handler.my_search:
class: AppBundle\Collection\QueryType\Handler\MySearchHandler
arguments:
- "@ezpublish.api.service.search"
tags:
- { name: netgen_block_manager.collection.query_type_handler, type: my_search }
This configuration is a fairly regular specification of services in Symfony,
however, to correctly recognize our PHP class as a query type handler, we need
to tag it with netgen_block_manager.collection.query_type_handler
tag and
attach to it an type
key with a value which equals to the identifier of
query type we configured at the beginning (in this case my_search
).
After this, our query type is ready for usage.
Creating custom parameter types¶
Netgen Layouts ships with around 15 parameter types which you can use in your custom blocks and queries and which fulfill most of the everyday usecases.
However, if you need custom validation on some of your parameters, or custom display in Symfony forms, you need to create a custom parameter type.
We will show how to create a custom parameter type on an example of a parameter which stores and validates dates in Google Analytics format.
There are two parts to implementing a parameter type in Netgen Layouts:
- Implementing a main parameter type service which deals with parameter value conversion and validation
- Implementing a form mapper which takes care of creating a Symfony form for the parameter type
Implementing the parameter type service¶
Parameter type service needs to implement
Netgen\BlockManager\Parameters\ParameterTypeInterface
. Since this interface
has a handful of methods, there is a handy abstract class from which you can
extend so you don’t have to write boilerplate code in your parameter types.
This cuts down the number of required methods to implement to 2. Let’s create an empty class extending the abstract class:
<?php
namespace AppBundle\Parameters\ParameterType;
use Netgen\BlockManager\Parameters\ParameterDefinition;
use Netgen\BlockManager\Parameters\ParameterType;
class GoogleAnalyticsDateType extends ParameterType
{
/**
* Returns the parameter type identifier.
*
* @return string
*/
public function getIdentifier()
{
}
/**
* Returns constraints that will be used to validate the parameter value.
*
* @param \Netgen\BlockManager\Parameters\ParameterDefinition $parameterDefinition
* @param mixed $value
*
* @return \Symfony\Component\Validator\Constraint[]
*/
protected function getValueConstraints(ParameterDefinition $parameterDefinition, $value)
{
}
}
As you can see, only two methods need to be implemented for basic parameter type
to work: getIdentifier
, which should return a unique identifier of a
parameter type, and getValueConstraints
, which should return an array of
Symfony validator constraints which validate the value.
Note
Every parameter type needs to allow null
as its value, since parameters
are by default optional in blocks and queries. Because of that, take care
not to include constraints which validate that the value is not null
,
like NotNull
or NotBlank
.
To specify constraints when the parameter is required, you can use the
getRequiredConstraints
method. It already has a default implementation
which you can override to suit your needs.
Let’s implement getIdentifier
and getValueConstraints
methods:
/**
* Returns the parameter type identifier.
*
* @return string
*/
public function getIdentifier()
{
return 'ga_date';
}
/**
* Returns constraints that will be used to validate the parameter value.
*
* @param \Netgen\BlockManager\Parameters\ParameterDefinition $parameterDefinition
* @param mixed $value
*
* @return \Symfony\Component\Validator\Constraint[]
*/
protected function getValueConstraints(ParameterDefinition $parameterDefinition, $value)
{
return array(
new Constraints\Type(array('type' => 'string'))
);
}
With the above implementation, we specified that the unique identifier of our
parameter type is ga_date
and that the value of the parameter should be a
string.
This is a good time to add any custom validations you want, for example, you can implement a validator and a constraint that validates the date as a Google Analytics date.
The purpose of other methods in ParameterTypeInterface
is detailed below:
configureOptions
This method uses the Symfony OptionsResolver component to specify any custom options your parameter type might have. Here, you can use the full power of the component to define required and optional options, custom validation and so on. For example, you might specify the minimum year your parameter accepts and then use the option in
getValueConstraints
method to modify the value constraints accordingly. An example implementation might look like this:public function configureOptions(OptionsResolver $optionsResolver) { $optionsResolver->setDefault('min_year', null); $optionsResolver->setRequired(array('min_year')); $optionsResolver->setAllowedTypes('min_year', array('int', 'null')); }
getConstraints
This method by default takes the constraints fromgetValueConstraints
andgetRequiredConstraints
method, and merges them together. Notice that this method has public visibility, whilegetValueConstraints
andgetRequiredConstraints
are protected. This means that this method is the one used by Netgen Layouts when validating the parameter value and if you override it, you will effectively override any constraints implemented in the two protected methods.
toHash
This method is responsible for converting the parameter value to a hash format (scalar or an array of scalars). Since every parameter value is stored in the database encoded into JSON, this method must not return any data that cannot be safely encoded into JSON. Default implementation does not convert the value and simply returns it as is.
fromHash
This method does the opposite oftoHash
method. That is, it converts the JSON decoded data stored in the database to a value that will be used by the rest of Netgen Layouts code as well as your custom code. This can be anything really: a scalar, an array, on object or a whole object graph. Default implementation does not convert the value and simply returns it as is.
export
This method has the exact same purpose astoHash
method, but with one important difference. It returns the parameter value ready for exporting with Netgen Layouts export/import feature. Usually, this means exporting various IDs (for example location ID in eZ Publish), not as IDs, but as remote IDs of the same domain object.
import
This method has the exact same purpose asfromHash
method, but with one important difference. It returns the parameter value ready for importing with Netgen Layouts export/import feature. Usually, this means that import procedure will provide to this method various IDs (for example location ID in eZ Publish), not as IDs, but as remote IDs of the same domain object, which then will be converted to IDs suitable for storing in the database.
isValueEmpty
This method is used to signal to the system when the value of the parameter is considered empty. For example, a date can be empty if the value of the parameter isnull
or an empty string. By default, this method usesempty
PHP language construct to check emptiness of the value.
Implementing the form mapper¶
Form mapper object is responsible for specifying how the parameter will look
like on a Symfony form. The interface
Netgen\BlockManager\Parameters\Form\MapperInterface
provides three methods
for you to implement. There is also an abstract class which you can extend to
ease the implementation, so you need to implement only one method.
Basic form mapper needs to only specify which Symfony form type to use:
<?php
namespace AppBundle\Parameters\FormMapper;
use Netgen\BlockManager\Parameters\Form\Mapper;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class GoogleAnalyticsDateMapper extends Mapper
{
/**
* Returns the form type for the parameter.
*
* @return string
*/
public function getFormType()
{
return TextType::class;
}
}
The purpose of other methods in MapperInterface
is detailed below:
mapOptions
If your parameter type has custom options which need to be forwarded to Symfony form type, you can use this method to do so. For example, if you implemented a custom Symfony form type for your Google Analytics date, you could transfer yourmin_year
option to the Symfony form, so it does not allow specifying any year lower than what is defined in your option.
handleForm
This method is a generic method which receives the form built from the information in
getFormType
andmapOptions
methods and makes it possible to do anything you wish with the form, like attaching custom data mappers or data transformers, adding event listeners to the form and so on.Basically, anything you can do in Symfony form type class with a form field, you can do here too.
Registering the Symfony services¶
To activate both the parameter type and the form mapper, you need to specify them as Symfony services.
Parameter type service needs to have a
netgen_block_manager.parameters.parameter_type
tag in its service
definition, while the form mapper needs to have a
netgen_block_manager.parameters.form.mapper
tag, together with the type
attribute whose value is equal to the parameter type identifier.
Our parameter type and form mapper service definitions should look like this:
services:
app.parameters.parameter_type.ga_date:
class: AppBundle\Parameters\ParameterType\GoogleAnalyticsDateType
tags:
- { name: netgen_block_manager.parameters.parameter_type }
app.parameters.form.mapper.ga_date:
class: AppBundle\Parameters\FormMapper\GoogleAnalyticsDateMapper
tags:
- { name: netgen_block_manager.parameters.form.mapper, type: ga_date }
Creating custom value types¶
In Netgen Layouts, (block) item is a generic concept in a way that blocks do not (and should not) care what kind of items are put inside the blocks. To achieve this, a block item is a wrapper around a value which comes from your CMS. For example, in eZ Platform integration, Netgen Layouts supports two types of values: eZ location and eZ content.
To be able to create block items from your own domain objects, you need to create and register your own custom value type. Value type has three purposes:
- Loading of your domain object from the CMS by its ID by using a value loader
- Handling the domain objects provided by your custom query types by using a value converter
- Generating the URL to the domain object by using a value URL generator
Registering a new value type¶
To be able to use your domain objects inside Netgen Layouts as block items, you need to register a new value type in the configuration. To do so, you need to provide a unique identifier for your value type and a human readable name:
netgen_block_manager:
items:
value_types:
my_value_type:
name: 'My value type'
This configuration registers a new value type in the system with
my_value_type
identifier.
Implementing a value loader¶
A value loader is an object responsible for loading your domain object by its
ID or its remote ID. It is an implementation of
Netgen\BlockManager\Item\ValueLoaderInterface
which provides two methods,
load
and loadByRemoteId
.
load
method takes the ID of the domain object and should simply return the
object once loaded or throw an exception if the object could not be loaded.
loadByRemoteId
method takes the remote ID of the domain object and again,
should simply return the object once loaded or throw an exception if the object
could not be loaded.
Note
Remote ID of the object is usually an ID which identifies a same domain object in different databases (dev, staging, production). For example, since regular autoincremented primary keys can be different for the same domain object in development and production databases, remote ID would be used to uniquely and consistently identify the same object in both databases.
The following is an example implementation of a value loader:
<?php
namespace AppBundle\Item\ValueLoader;
use Netgen\BlockManager\Item\ValueLoaderInterface;
class MyValueTypeLoader implements ValueLoaderInterface
{
/**
* Loads the value from provided ID.
*
* @param int|string $id
*
* @throws \Netgen\BlockManager\Exception\Item\ItemException If value cannot be loaded
*
* @return mixed
*/
public function load($id)
{
try {
return $this->myBackend->loadMyObject($id);
} catch (Exception $e) {
throw new ItemException(
sprintf('Object with ID "%s" could not be loaded.', $id),
0,
$e
);
}
}
/**
* Loads the value from provided remote ID.
*
* @param int|string $remoteId
*
* @throws \Netgen\BlockManager\Exception\Item\ItemException If value cannot be loaded
*
* @return mixed
*/
public function loadByRemoteId($remoteId)
{
try {
return $this->myBackend->loadMyObjectByRemoteId($remoteId);
} catch (Exception $e) {
throw new ItemException(
sprintf('Object with remote ID "%s" could not be loaded.', $remoteId),
0,
$e
);
}
}
}
Once implemented, you need to register the loader in Symfony DI container:
app.block_manager.value_loader.my_value_type:
class: AppBundle\Item\ValueLoader\MyValueTypeLoader
tags:
- { name: netgen_block_manager.item.value_loader, value_type: my_value_type }
Notice that the service is tagged with netgen_block_manager.item.value_loader
DI tag which has a value_type
attribute. This attribute needs to have a
value equal to your value type identifier.
Implementing Content Browser support¶
To be able to actually select the items from the CMS and add them to your blocks, you also need to implement a Netgen Content Browser backend.
To automatically recognize which backend is responsible for which value types, you need to make sure that the identifier of the item in the Netgen Content Browser backend you implemented is the same as the identifier of the value type you configured above.
Implementing a value converter¶
As you’re probably aware, query types need not worry themselves about returning PHP objects specific to Netgen Layouts to work. Instead, they simply return domain objects which are then converted by Netgen Layouts into block items.
Converting the domain objects to Netgen Layouts items is done through so called
value converters and every value type needs to have a value converter
implemented. Value converter should implement
Netgen\BlockManager\Item\ValueConverterInterface
, which provides methods
that return the data used by Netgen Layouts to work with block items, like the
ID of the object, name and if the object is considered visible in your CMS.
Method supports
should return if the value converter supports the given
object. Usually, you will check if the provided object is of correct interface.
This makes it possible to handle different types of objects in the same value
converter. For example, in eZ Platform, Content
and ContentInfo
are two
different objects that represent the same piece of content in the CMS, but with
different usecases in mind.
Method getValueType
should simply return the identifier of the value type
you choose when activating the value type in the configuration.
An example implementation of a value converter might look something like this:
<?php
namespace AppBundle\Item\ValueConverter;
use App\MyValue;
use Netgen\BlockManager\Item\ValueConverterInterface;
class MyValueTypeConverter implements ValueConverterInterface
{
/**
* Returns if the converter supports the object.
*
* @param mixed $object
*
* @return bool
*/
public function supports($object)
{
return $object instanceof MyValue;
}
/**
* Returns the value type for this object.
*
* @param mixed $object
*
* @return string
*/
public function getValueType($object)
{
return 'my_value_type';
}
/**
* Returns the object ID.
*
* @param \App\MyValue $object
*
* @return int|string
*/
public function getId($object)
{
return $object->id;
}
/**
* Returns the object remote ID.
*
* @param \App\MyValue $object
*
* @return int|string
*/
public function getRemoteId($object)
{
return $object->remoteId;
}
/**
* Returns the object name.
*
* @param \App\MyValue $object
*
* @return string
*/
public function getName($object)
{
return $object->name;
}
/**
* Returns if the object is visible.
*
* @param \App\MyValue $object
*
* @return bool
*/
public function getIsVisible($object)
{
return $object->isVisible();
}
/**
* Returns the object itself.
*
* This method can be used to enrich the object before it being rendered.
*
* @param \App\MyValue $object
*
* @return \App\MyValue
*/
public function getObject($object)
{
$object->param = 'value';
return $object;
}
}
Once implemented, you need to register the converter in Symfony DI container and
tag it with netgen_block_manager.item.value_converter
tag:
app.block_manager.value_converter.my_value_type_content:
class: AppBundle\Item\ValueConverter\MyValueTypeConverter
tags:
- { name: netgen_block_manager.item.value_converter }
Implementing a value URL generator¶
To generate the links to your domain objects in your blocks, you can use
ngbm_item_path
Twig function in your Twig templates. This function
internally forwards the URL generation to the correct value URL generator based
on the value type of the item. To generate the URL for your value type, simply
implement the Netgen\BlockManager\Item\ValueUrlGeneratorInterface
, which
provides a single method called generate
responsible for generating the
URL.
Note
generate
method should return the full path to the item, including the
starting slash, not just a slug.
An example implementation might use the Symfony router and generate the URL based on the object ID:
<?php
namespace AppBundle\Item\ValueUrlGenerator;
use Netgen\BlockManager\Item\ValueUrlGeneratorInterface;
class MyValueTypeUrlGenerator implements ValueUrlGeneratorInterface
{
/**
* Returns the object URL. Take note that this is not a slug,
* but a full path, i.e. starting with /.
*
* @param mixed $object
*
* @return string
*/
public function generate($object)
{
return $this->router->generate(
'my_custom_route',
array(
'id' => $object->id,
)
);
}
}
Once implemented, you need to register the URL generator in Symfony DI container:
app.block_manager.value_url_generator.my_value_type:
class: AppBundle\Item\ValueUrlGenerator\MyValueTypeUrlGenerator
tags:
- { name: netgen_block_manager.item.value_url_generator, value_type: my_value_type }
Notice that the service is tagged with
netgen_block_manager.item.value_url_generator
DI tag which has a
value_type
attribute. This attribute needs to have a value equal to your
value type identifier.
Implementing item templates¶
Once a custom value type is implemented, it’s time to implement Twig templates that will be used to render the item that holds the value.
Just like with block templates, for rendering an item, you need to implement two templates, one for backend (Block Manager app) and one for frontend.
Implementing a backend template¶
A backend template, or rather, template for Block Manager app is simple. It
receives the item in question in item
variable and can be used to render
the item name and item image. The basic structure of the template looks like
this:
<div class="image">
<img src="/path/to/image.jpg" />
</div>
<div class="name">
<p><a href="{{ ngbm_item_path(item) }}" target="_blank" rel="noopener noreferrer">{{ item.name }}</a></p>
</div>
Rendering an item name and URL works for all items, as long as you implemented proper value URL generators and converters. Rendering an image is left for you, as often it requires additional steps in contrast to just outputting the image path.
Registering the backend template is done via the view config:
netgen_block_manager:
view:
item_view:
api:
my_value:
template: "@App/api/item/view/my_value.html.twig"
match:
item\value_type: my_value
Implementing a frontend template¶
Just as with the backend template, frontend template receives the item in
question via item
variable. Frontend templates depend on your design, so
there’s little sense in providing an example implementation, but once you
implement your frontend template, you can register it with:
netgen_block_manager:
view:
item_view:
default:
my_value:
template: "@App/item/view/my_value.html.twig"
match:
item\value_type: my_value
Creating custom target types¶
Netgen Layouts is shipped with a number of target types to which you can map your layouts to be used in a layout resolving process. These target types are generic, allowing you to attach a layout to a request URI, a Symfony route or their prefixes. In most cases, when working with pure Symfony apps, this is enough.
However, if you wish that your layouts can be mapped to domain objects from your CMS directly, you can create custom target types.
Note
Custom target type can be whatever comes to mind, not only a domain object from your CMS.
Warning
Custom target types are one of the most complicated extension points in Netgen Layouts and creating a custom target type involves creating configuration, templates, translations and quite a bit of code.
Implementing the target type classes¶
Implementing a target type in PHP requires creating at least three Symfony services:
- Target type itself
- Symfony form mapper
- A target handler for every database engine supported in Netgen Layouts
Creating a target type¶
A target type is a PHP class implementing
Netgen\BlockManager\Layout\Resolver\TargetTypeInterface
. The purpose of this
class is twofold:
- Provide Symfony constraints that validate the value of the target when adding it to a mapping
- Extract the value of the target from the request to be used in layout resolving process
The first point is achieved by implementing getConstraints
method, which
should return the array of Symfony validator constraints which should validate
the value. For example, in eZ location target type, these constraints validate
that the ID of the location is a number larger than 0 and that the location with
the provided ID actually exists:
public function getConstraints()
{
return array(
new Constraints\NotBlank(),
new Constraints\Type(array('type' => 'numeric')),
new Constraints\GreaterThan(array('value' => 0)),
new EzConstraints\Location(),
);
}
The second point is achieved by implementing the provideValue
method. This
method takes a request object and should return a value of your target type if
it exists in the request or null
if it doesn’t. For example, eZ location
target type extracts the location from provided request and returns its ID:
public function provideValue(Request $request)
{
$location = $this->contentExtractor->extractLocation($request);
return $location instanceof APILocation ? $location->id : null;
}
The one method that remains to be implemented is the getType
method, which
should return a unique identifier of the target type.
Once this is done, we need to register the target type in the Symfony DIC with
the netgen_block_manager.layout.resolver.target_type
tag:
app.target_type.my_target:
class: AppBundle\Layout\Resolver\TargetType\MyTarget
tags:
- { name: netgen_block_manager.layout.resolver.target_type }
Tip
You can add a priority
attribute to the tag, which allows you to make
your target type considered before others when deciding if the current
request matches one of the targets.
Creating the form mapper¶
To be able to add the target to a mapping or edit the value of an existing
target, you need to provide a form mapper which provides data for generating
Symfony form for your target type. The mapper needs to implement
Netgen\BlockManager\Layout\Resolver\Form\TargetType\MapperInterface
and
there’s also a handy abstract class which you can extend to cut down the number
of methods to define to one: getFormType
, which returns which Symfony form
type should be used to edit the target:
<?php
namespace AppBundle\Layout\Resolver\Form\TargetType\Mapper;
use Netgen\BlockManager\Layout\Resolver\Form\TargetType\Mapper;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class MyTarget extends Mapper
{
/**
* Returns the form type that will be used to edit the value of this condition type.
*
* @return string
*/
public function getFormType()
{
return TextType::class;
}
}
There are two other methods in the interface:
getFormOptions
which makes it possible to provide custom options to the form typehandleForm
which allows you to customize the form in any way you see fit
Finally, you need to register the mapper in the Symfony container with the correct tag and the identifier of the target type:
app.layout.resolver.form.target_type.mapper.my_target:
class: AppBundle\Layout\Resolver\Form\TargetType\Mapper\MyTarget
tags:
- { name: netgen_block_manager.layout.resolver.form.target_type.mapper, target_type: my_target }
Creating target handlers for the database engine¶
Matching the target value from the request to the value stored in the database is done in the database itself. This means that you need to provide a so called target handler for every database engine supported in Netgen Layouts.
The only supported database engine is called “doctrine”, since it uses Doctrine library to communicate with the database.
This target handler needs to implement
Netgen\BlockManager\Persistence\Doctrine\QueryHandler\TargetHandlerInterface
interface which provides a single method called handleQuery
which takes the
Doctrine query object and the target value and should modify the query in way to
match the provided value.
Stored target value can be accessed in the query with rt.value
so to match a
simple integer, you would implement it like this:
/**
* Handles the query by adding the clause that matches the provided target values.
*
* @param \Doctrine\DBAL\Query\QueryBuilder $query
* @param mixed $value
*/
public function handleQuery(QueryBuilder $query, $value)
{
$query->andWhere(
$query->expr()->in('rt.value', array(':target_value'))
)
->setParameter('target_value', $value, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
}
Finally, the target handler needs to registered in the Symfony container with the correct tag and target type identifier:
app.layout_resolver.target_handler.doctrine.my_target:
class: AppBundle\LayoutResolver\TargetHandler\Doctrine\MyTarget
tags:
- { name: netgen_block_manager.layout.resolver.target_handler.doctrine, target_type: my_target }
Implementing the target type template¶
Target type uses a single template in the value
view context of the
Netgen Layouts view layer to display the value of the target in the admin
interface. Since the target itself usually provides only the scalar identifier
as its value, this template usually needs some logic to display the name of the
target (from your CMS for example). In case of eZ Platform, these templates for
example use Twig functions to load the content and location objects and return
their names and paths:
{% set content_name = ngbm_ezcontent_name(target.value) %}
{{ content_name != null ? content_name : '(INVALID CONTENT)' }}
To register the template in the system, the following configuration is needed
(make sure to use the value
view context):
netgen_block_manager:
view:
rule_target_view:
value:
my_target:
template: "@App/layout_resolver/target/value/my_target.html.twig"
match:
rule_target\type: my_target
Target type translations¶
Each target type uses two translation strings, one in ngbm
and one in
ngbm_admin
catalog. The first one is a generic string which should provide
a human readable name of the target type and should be in the
layout_resolver.target.<target_type_identifier>
format:
The second one is used as a label in administration of interface which states
for which target types is the mapping used and should be in
layout_resolver.rule.target_header.<target_type_identifier>
format:
Creating custom condition types¶
Netgen Layouts is shipped with a couple of condition types which you can use to limit your layout mappings to certain conditions. One example condition type which is built into Netgen Layouts is the query parameter condition type which enables the mapping if some query parameter from the request matches the value stored in the condition. In case of eZ Platform integration, an example condition type which is built in is the siteaccess condition type that activates the mapping only if the siteaccess of the current request matches the condition.
If you wish to map your layouts to targets in some other conditions, like time of day, location of the user, IP address, you name it…, you can create your own condition types.
Warning
Custom condition types are one of the most complicated extension points in Netgen Layouts and creating a custom condition type involves creating configuration, templates, translations and quite a bit of code.
Implementing the condition type classes¶
Implementing a condition type in PHP requires creating two Symfony services:
- Condition type itself
- Symfony form mapper
Creating a condition type¶
A condition type is a PHP class implementing
Netgen\BlockManager\Layout\Resolver\ConditionTypeInterface
. The purpose of
this class is twofold:
- Provide Symfony constraints that validate the value of the condition when adding it to a mapping
- Deciding if the current request matches the provided value of the condition
The first point is achieved by implementing getConstraints
method, which
should return the array of Symfony validator constraints which should validate
the value. For example, in eZ siteaccess condition type, these constraints
validate that all selected siteaccesses are non empty strings and that they
actually exist:
public function getConstraints()
{
return array(
new Constraints\NotBlank(),
new Constraints\Type(array('type' => 'array')),
new Constraints\All(
array(
'constraints' => array(
new Constraints\Type(array('type' => 'string')),
new EzConstraints\SiteAccess(),
),
)
),
);
}
The second point is achieved by implementing the matches
method. This method
takes a request object and based on the data from the request decides if it
matches the provided value. For example, the matches
method of the
eZ siteaccess condition type returns true only if the siteaccess is provided in
the request and is equal to one of the stored values of the condition:
public function matches(Request $request, $value)
{
$siteAccess = $request->attributes->get('siteaccess');
if (!$siteAccess instanceof SiteAccess) {
return false;
}
if (!is_array($value) || empty($value)) {
return false;
}
return in_array($siteAccess->name, $value, true);
}
The one method that remains to be implemented is the getType
method, which
should return a unique identifier of the condition type.
Once this is done, we need to register the condition type in the Symfony DIC
with the netgen_block_manager.layout.resolver.condition_type
tag:
app.condition_type.my_condition:
class: AppBundle\Layout\Resolver\ConditionType\MyCondition
tags:
- { name: netgen_block_manager.layout.resolver.condition_type }
Creating the form mapper¶
To be able to add the condition to a mapping or edit the value of an existing
condition, you need to provide a form mapper which provides data for generating
Symfony form for your condition type. The mapper needs to implement
Netgen\BlockManager\Layout\Resolver\Form\ConditionType\MapperInterface
and
there’s also a handy abstract class which you can extend to cut down the number
of methods to define to one: getFormType
, which returns which Symfony form
type should be used to edit the condition:
<?php
namespace AppBundle\Layout\Resolver\Form\ConditionType\Mapper;
use Netgen\BlockManager\Layout\Resolver\Form\ConditionType\Mapper;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class MyCondition extends Mapper
{
/**
* Returns the form type that will be used to edit the value of this condition type.
*
* @return string
*/
public function getFormType()
{
return TextType::class;
}
}
There are two other methods in the interface:
getFormOptions
which makes it possible to provide custom options to the form typehandleForm
which allows you to customize the form in any way you see fit
Finally, you need to register the mapper in the Symfony container with the correct tag and the identifier of the condition type:
app.layout.resolver.form.condition_type.mapper.my_condition:
class: AppBundle\Layout\Resolver\Form\ConditionType\Mapper\MyCondition
tags:
- { name: netgen_block_manager.layout.resolver.form.condition_type.mapper, condition_type: my_condition }
Implementing the condition type template¶
Condition type uses a single template in the value
view context of the
Netgen Layouts view layer to display the value of the condition in the admin
interface. Since the condition itself usually provides only the scalar
identifier as its value, this template usually needs some logic to display the
human readable value of the condition. For example, content type condition from
eZ Platform uses custom Twig functions to display content type names instead of
the identifiers:
{% set content_type_names = [] %}
{% for value in condition.value %}
{% set content_type_names = content_type_names|merge([ngbm_ez_content_type_name(value)]) %}
{% endfor %}
{{ content_type_names|join(', ') }}
To register the template in the system, the following configuration is needed
(make sure to use the value
view context):
netgen_block_manager:
view:
rule_condition_view:
value:
my_condition:
template: "@App/layout_resolver/condition/value/my_condition.html.twig"
match:
rule_condition\type: my_condition
Condition type translations¶
Each condition type uses one translation string in the ngbm
catalog. This is
a generic string which should provide a human readable name of the condition
type and should be in the
layout_resolver.condition.<condition_type_identifier>
format:
- Creating a custom layout type
- Creating a custom block
- Creating a block plugin
- Creating a custom container block
- Adding collections to blocks
- Using themes
- Adding custom view types to blocks
- Creating custom query types
- Creating custom parameter types
- Creating custom value types
- Creating custom target types
- Creating custom condition types
- Creating a custom layout type
- Creating a custom block
- Creating a block plugin
- Creating a custom container block
- Adding collections to blocks
- Using themes
- Adding custom view types to blocks
- Creating custom query types
- Creating custom parameter types
- Creating custom value types
- Creating custom target types
- Creating custom condition types
Tips & tricks¶
Tips & tricks¶
How to override existing templates¶
By using the view layer configuration in Netgen Layouts, it is possible to override any template for built in layout types, block view types and block item view types.
Warning
View layer works in a way that first configuration which matches the rules is used for rendering the entity, so take care to properly use Symfony configuration prepending to make sure your rules are matched before the built in ones.
Overriding layout type templates¶
You can override a template for any layout type (including built in ones) with the following example configuration:
netgen_block_manager:
view:
layout_view:
default:
layout_4_override:
template: "@App/layouts/layout_4.html.twig"
match:
layout\type: layout_4
This overrides the layout_4
layout type to use
@App/layouts/layout_4.html.twig
template.
Overriding block view type templates¶
You can override a template for any block view type (including built in ones) with the following example configuration:
netgen_block_manager:
view:
block_view:
default:
simple_title_override:
template: "@App/blocks/title/simple_title.html.twig"
match:
block\definition: title
block\view_type: simple_title
This overrides the simple_title
view type of the title
block definition
to use @App/blocks/title/simple_title.html.twig
template.
Overriding block item view type templates¶
You can override a template for any block item view type (including built in ones) with the following example configuration:
netgen_block_manager:
view:
item_view:
default:
my_item_standard_override:
template: "@App/items/my_item/standard.html.twig"
match:
item\value_type: my_item
item\view_type: standard
This overrides the standard
item view type of the my_item
value type to
use @App/items/my_item/standard.html.twig
template.
Tip
To override item view types for ezcontent
and ezlocation
items,
use the regular eZ Platform content view configuration instead of overriding
the templates in Netgen Layouts.
How to quickly render a layout on a single URL¶
Usually, if you wish to render a page with a layout in your CMS, you would need
to create a controller which renders a template which then extends from
ngbm.layoutTemplate
variable for layout to be resolved.
Even worse, you would need to create a page (article, blog post, landing page or something else) in the CMS just to make the URL available in the system.
Creating a Symfony controller and a page in your CMS just to render an URL with a layout can be an overkill, and in those cases, you can use a controller built into Symfony to quickly render a layout on a single URL.
To render the page, you need to create a Symfony route which uses a built in Symfony controller to render the template available in Netgen Layouts:
my_cool_page:
path: /my/cool/page
defaults:
_controller: 'FrameworkBundle:Template:template'
template: '@NetgenBlockManager/empty_page.html.twig'
Finally, you need to add a mapping in Netgen Layouts administration to link one of the layouts to the route you created. Once this is done, you can access the URL you provided in your route config and see the layout rendered in all its glory.
How to inject current eZ location and content in blocks and query types¶
Note
This tutorial is eZ Platform specific.
Often, your custom block definitions and query types need the current
eZ Platform location or content to work. While you can extract the information
about the current location and content from the Request
object, the
differences between different versions of eZ kernel make it impossible to create
generic block definitions and query types that work on any eZ kernel
available.
That’s why there is a handy Symfony service called Content Provider in Netgen Layouts that can be used to retrieve the current location or content in a generic way. In background, this service uses different implementations of a service that extracts content and locations from the request for every eZ kernel version available.
Note
If using eZ Publish 5, you need to specify a Symfony service alias somewhere in your configuration which makes sure that an eZ 5 version of the extractor is used:
netgen_block_manager.ezpublish.content_extractor:
alias: netgen_block_manager.ezpublish.content_extractor.ez5_request
Service identifier of the Content Provider is
netgen_block_manager.ezpublish.content_provider
and you can inject it into
your block definitions and query types like any other service.
Content Provider exposes two methods: provideLocation
and provideContent
which return the location and content from the current request and null
if
no location or content exist.
As an example, you can use the Content Provider to inject the location and content objects into Twig templates for your blocks:
<?php
namespace AppBundle\Block\BlockDefinition\Handler;
use Netgen\BlockManager\API\Values\Block\Block;
use Netgen\BlockManager\Block\BlockDefinition\BlockDefinitionHandler;
use Netgen\BlockManager\Ez\ContentProvider\ContentProviderInterface;
class MyBlockHandler extends BlockDefinitionHandler
{
/**
* @var \Netgen\BlockManager\Ez\ContentProvider\ContentProviderInterface
*/
protected $contentProvider;
/**
* Constructor.
*
* @param \Netgen\BlockManager\Ez\ContentProvider\ContentProviderInterface $contentProvider
*/
public function __construct(ContentProviderInterface $contentProvider)
{
$this->contentProvider = $contentProvider;
}
/**
* Adds the dynamic parameters to the $params object for the provided block.
*
* @param \Netgen\BlockManager\Block\DynamicParameters $params
* @param \Netgen\BlockManager\API\Values\Block\Block $block
*/
public function getDynamicParameters(DynamicParameters $params, Block $block)
{
$params['content'] = $this->contentProvider->provideContent();
$params['location'] = $this->contentProvider->provideLocation();
}
}
How to override the templates for Grid block columns¶
Grid block type uses a nifty little trick to specify the templates for its 2, 3, 4 or 6 columns variants which makes it possible to override the template for only one of those variants without the need for overriding the entire grid template.
Basically, it uses a feature from the view layer which makes it possible to inject custom parameters to Twig templates straight from the match configuration rule. By default, if no parameter is provided that specifies the template to use, Grid block uses built in templates for each of the column variants.
As an example, the following configuration would override the template for 4 column variant of a Grid block:
netgen_block_manager:
view:
block_view:
default:
list\grid\override:
template: "@NetgenBlockManager/block/list/grid.html.twig"
parameters:
column_templates:
4: "@App/block/grid/4_columns.html.twig"
match:
block\definition: list
block\view_type: grid
Basically, this rule specifies that we want to use the original grid template
available in Netgen Layouts (@NetgenBlockManager/block/list/grid.html.twig
)
and to also provide a parameter called column_templates
which the original
grid template uses to extract the template names for column variants from.
We only specified that 4 columns template should be overriden by specifying the
key with a value of 4
, but we can easily add more overrides by specifying
more array keys in the column_templates
parameter.
How to specify default value for block parameters¶
As you probably know, you can create a new block in a layout by drag and dropping it from the left sidebar to the layout. This means that there is no way to specify the starting values for the parameters in the block. Instead, the default values provided in the block definition are used.
This is not a problem per se, but it does mean that in cases when you do need different starting values than those provided by the block definition, you need to add a block and immediately edit it in the right sidebar to change the parameter values to more suitable ones. This only slows down layout creation process.
To overcome this, you can specify default values for any block parameter in the configuration. For example, if you want to change the default number of columns of a Grid block, you would use a configuration like this one:
block_types:
grid:
defaults:
parameters:
number_of_columns: 6
From now on, every time you add a Grid block to your layout, it will be created with 6 columns.
How to inject items to blocks manually¶
Usually, block items are provided to blocks with a collection query. But,
sometimes it is useful to provide some specific block items to the block by hand
(meaning in block definition handler). This way, you could reuse block item
templates by calling the ngbm_render_item
function on those items, instead
of duplicating the block item template logic inside the block itself.
To achieve this, you can use a Symfony service from Netgen Layouts called item
builder which is an instance of
Netgen\BlockManager\Item\ItemBuilderInterface
. After that, you can just use
it in your getDynamicParameters
method of the block definition handlers to
build the items and provide them as dynamic parameters to the block.
Note
This service is used by the collection query result building process too, so you will be basically using the same principles Netgen Layouts uses when building items.
The ID of the item builder Symfony service is
netgen_block_manager.item.item_builder
and you can just inject it to your
block definition handlers as usual.
The service provides a single method called build
which receives a single
parameter, your domain object, which will then build the block item. For this to
work, you need to have value converters (instances of
Netgen\BlockManager\Item\ValueConverterInterface
) for any domain object you
wish to build items from.
For example, to build the item from your domain object, you would write
something like this in your getDynamicParameters
method:
$myObject = $this->myBackend->loadMyObject(42);
$item = $this->itemBuilder->build($myObject);