Skip to main content
page last edited on 10 October 2022

Rendering

Version: 5.5.1

As a tool for working with templates, we use twig from symfony. However, the way we use it is different from the standard one.

Widgets

The interface is entirely built as a tree of widgets which are classes that are inherited from \\XLite\\View\\AView .

Under normal conditions, rendering starts with the widget \\XLite\\View\\Controller. It is also possible to render upon request a separate widget that is used to partially update the page via ajax.

Each widget can render content as a result of template rendering, or simply as text. In order to get the content of another widget from a template, you need to use special syntax:

# Widget \Widget\Class\Name with the passed parameters
{{ widget('[Widget\\Class\\Name]',[paramName=paramValue,...]) }}

# Clone of the current widget with passed parameters
{{ widget([paramName=paramValue,...]) }}

Note that if {% include 'some/template/name' %} is used in the template, the child template will be rendered within the current widget.

ViewLists

If it is required to display several elements (blocks) in the template at once, whereas the list of such elements (blocks) is not known in advance and is formed depending on the settings, the list of modules, the content of the database or the request context, then a special kind of statement is used:

# Rendering all the templates and widgets added to `list_name`
# The parameters are passed as an array
{{ widget_list('list_name',[params],[type='{type}']) }}
# The parameters are passed separately as function arguments
{{ widget_list('list_name',type='{type}',[paramName=paramValue,...] }}

Note that if a widget is added to the list, it will be processed in the same way as in a call

{{ widget('[Widget\\Class\\Name]',[paramName=paramValue,...]) }}

Rendering a template in a list corresponds to a call

{{ widget(template='some/template/name',[paramName=paramValue,...]) }}

That is, a clone of the current widget will be used as the widget.

The type parameter affects the way the list name is formed.

Inherited view lists

If type=inherited, then the result of the getListName() method of the current widget is used as the list name prefix.

This may be necessary if the template is used for different widgets or a different list content needs to be used in the widget depending on the state.

For example:

# Use widget in the template
{{ widget_list('list_name',type='inherited' }}
# Current widget
protected function getListName()
{
return 'some_list.prefix';
}
# final result
{{ widget_list('some_list.prefix.list_name',type='inherited' }}

Nested view lists

If type=nested, then the name of the current list is used as the template prefix.

For example:

# Call in the template
{{ widget_list('fisrt_parent_list.name' }}

{{ widget_list('second_parent_list.name' }}
{##
# @ListChild (list="first_parent_list.name")
# @ListChild (list="second_parent_list.name")
#}

{{ widget_list('list_name',type='nested' }}

As a result, the child widget will be different depending on which list it is rendered within.

# within first_parent_list.name
{{ widget_list('first_parent_list.name.list_name' }}

# within second_parent_list.name
{{ widget_list('second_parent_list.name.list_name' }}

Adding a template or a widget to a view list

To add a template to a view list, annotations are used in PHP classes as well as a similar syntax of comments in the templates:

<?php

namespace XLite\View;

use XCart\Extender\Mapping\ListChild;

/**
* @ListChild (list="some_list_name", interface="web" zone="customer", weight="100")
*/
class SomeWidget extends \XLite\View\AView
{
}
{##
# @ListChild (list="customer.account.details.after", weight="100")
#}

<h1>Some Header</h1>

{{ widget_list('some_list.content') }}
  • list - required parameter, list name.
  • interface - possible values: web (default for widgets), mail, pdf. For templates, the value is calculated from the file path.
  • zone - possible values: customer (default for widgets), admin, common. For templates, the value is calculated from the file path.
  • weight - the numerical value of the template position on the list (the lesser the value, the higher on the list). The default is 0. There are also some special values: first corresponds to 0 and last corresponds to 16777215

Changing the contents of lists

For some modules, especially for skins, it may be necessary to change the contents of lists. For that the module needs to be marked as a symfony bundle. Next, you need to create a handler for one of the events:

  • xcart.service.view-list.collect-mutation.before
  • xcart.service.view-list.collect-mutation
  • xcart.service.view-list.collect-mutation.after
  • xcart.service.view-list.apply-mutation.before
# <XCart>/modules/{AuthorId}/{ModuleId}/config/services.yaml

{AuthorId}\{ModuleId}\CrispWhiteSkin\Core\EventListener:
arguments:
$moduleManagerDomain: '@XCart\Domain\ModuleManagerDomain'
tags:
- { name: kernel.event_listener, event: xcart.service.view-list.collect-mutation, method: onCollectViewListMutations }
public function onCollectViewListMutations(ViewListMutationEvent $event): void
{
$event->addMutation($subject, $mutations);

$event->addMutations([
'{subject}' => {mutations},
...
]);
}

**subject** - FQCN of the widget (without the leading slash) or a relative path to the template from {interface}/{zone} .

For example:

File path: /var/www/shop/templates/web/customer/layout/slidebar.twig

Relative path: layout/slidebar.twig

File path: /var/www/shop/modules/XC/CrispWhiteSkin/templates/web/customer/layout/content/breadcrumbs.twig

Relative path: layout/content/breadcrumbs.twig

**mutations** - change specification

  • Array with a single element - remove subject from the list.
# Remove XLite\View\SomeWidget from the list some_list.name regardless of the
# interface and the zone
$event->addMutation('XLite\View\SomeWidget', ['some_list.name']);
$event->addMutation('XLite\View\SomeWidget', [['some_list.name']]);

# Remove XLite\View\SomeWidget from the list some_list.name for the web interface
# and all the zones
$event->addMutation('XLite\View\SomeWidget', [['some_list.name', 'web']]);

# Remove XLite\View\SomeWidget from the list some_list.name for the web interface
# and the customer zone
$event->addMutation('XLite\View\SomeWidget', [['some_list.name', 'web', 'customer']]);
  • Array with two elements - remove from the lists for the specified FQCN the first element and insert into the lists for the specified FQCN the second element. Note that the array element for insertion must have four values: list name, weight, interface, and zone
$event->addMutation('XLite\View\SomeWidget', [
'some_list.name',
['some_other_list.name', 100, 'web', 'customer']
]);
  • Array with the key to_remove or to_insert or both. The elements for these keys must represent lists of specifications to remove or to insert, respectively.
$event->addMutation('XLite\View\SomeWidget', [
'to_remove' => [
'some_list.name',
['some_other_list.name', 'web', 'customer']
]
]);

$event->addMutation('XLite\View\SomeWidget', [
'to_insert' => [
['some_list.name', 10, 'web', 'customer']
['some_other_list.name', 20, 'web', 'customer']
]
]);

$event->addMutation('XLite\View\SomeWidget', [
'to_remove' => [
'some_list.name',
['some_other_list.name', 'web', 'customer']
],
'to_insert' => [
['one_more_list.name', 10, 'web', 'customer']
['some_list.name', 20, 'web', 'customer']
]
]);

Choosing an appropriate template

Since in lists, in the widget function parameter and in the twig include statement a short name of the template is used, we need to determine which file to use.

For a specific interface and zone, the template file is first searched for in skin modules, then in all the other modules, then in the core. If no template file has been found, the search is repeated in the same order and in the same interface but in the common zone. In addition to that, for the interfaces mail and pdf, the search is performed in the web interface and the common zone.

Choosing resources (js, css, images)

For resources, the logic is the same as for templates, but it applies when copying to public/assest is done.

The copying is performed automatically during a cache rebuild process (That may be launched by enabling/disabling and installation/removal of modules, running a software update, or may be initiated manually).

In addition, copying may be done using the following command: # ./bin/console xcart:assest:install

If node (14+), yarn and gulp-cli are installed on the system, it is possible to run a system that will automatically track changes in resources: # gulp watch