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 is0
. There are also some special values:first
corresponds to0
andlast
corresponds to16777215
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
, andzone
$event->addMutation('XLite\View\SomeWidget', [
'some_list.name',
['some_other_list.name', 100, 'web', 'customer']
]);
- Array with the key
to_remove
orto_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