2. Руководство разработчика › 2.4 Шаблонизатор › Группы шаблонов

Вся вёрстка проекта живёт в каталоге templates/, разложенная по именованным группам. Группа — это полный набор .htm-файлов витрины: одна группа даёт один внешний вид. Дополнительные группы заводят под мобильную версию, альтернативный дизайн, отдельное оформление партнёрского раздела.

Этот раздел — про то, как устроены файлы шаблонов, как группы наследуют друг друга и как переключить группу из кода. Как модуль работает с шаблонами изнутри — в разделе «Методы шаблонизатора».

Структура файлов шаблонов

Шаблоны хранятся в каталоге templates/ в корне проекта. Внутри находятся именованные группы шаблонов:

templates/
    default/
        units/
            melbis_base_page/
                main.htm
                page_index.htm
                page_goods.htm
                page_404.htm
            melbis_store_card/
                main.htm
            melbis_cataloge/
                main.htm

Каждый модуль имеет собственный подкаталог внутри units/, в котором хранятся все его .htm-шаблоны. Внутри одного модуля может быть произвольное количество шаблонов — они загружаются методами Tpl* по имени файла без расширения.

Активная группа

По умолчанию используется группа default. После создания новой группы она автоматически появится в дереве каждого модуля в IDE.

Активная группа задаётся в config.json (параметр MELBIS_TEMPLATE) или через диалог «Проектирование → Инсталляция» — об этом подробно рассказано в разделе «Конфигурация». Это значение действует, пока проект не переключит группу из кода.

Общий код между группами

Дополнительная группа редко отличается от default целиком — обычно это те же шаблоны с небольшими правками. Полностью дублировать их не нужно, для этого есть три механизма.

Пустой файл наследует группу по умолчанию. Если .htm-файл в группе пуст (или его нет), движок берёт одноимённый файл из группы MELBIS_TEMPLATE. Пустой templates/mobi/units/melbis_cataloge/main.htm отдаст содержимое templates/default/units/melbis_cataloge/main.htm. Такой пустой файл читается как явная пометка «здесь всё как в default» — в отличие от полной копии, про которую потом не скажешь, есть в ней отличия или нет. Наследование одноуровневое — только в default, не по цепочке; если файла нет ни в группе, ни в default, сборка запишет ошибку в лог.

Мелкие различия — условием по группе. Расхождения удобно держать в одном общем файле, помечая куски условием по текущей группе:

{*TEMPLATE==default} <div class="page-wide"> {TEMPLATE*}
{*TEMPLATE==mobi}    <div class="page-narrow"> {TEMPLATE*}

Файл лежит в default, а mobi подтягивает его пустым файлом-наследником; под каждой группой активна своя ветка, потому что {TEMPLATE} разный. Так же можно ветвить по языку — {*LANG==ru} … {LANG*}. Синтаксис условий — в разделе «Синтаксис шаблонов».

Шаблон другой группы — по имени. Тег {^CARD:mobi} подключает card.htm модуля из группы mobi, на какой бы группе ни собиралась страница; файл, которого в mobi нет, придёт из default. Подробно — в разделе «Синтаксис шаблонов».

Наследование касается только .htm: статика (.js/.css) собирается по своей группе, а общий файл одной группы входит в бандл другой через её имя в строке бандлов — mobi/melbis.js (см. «Сборка статики»). Общий скрипт обычно держат один и ветвят внутри по версии, отдав её из шаблона — <script>var TEMPLATE = "{TEMPLATE}";</script>.

Переключение группы и языка из кода

TemplateSet($mTemplate) и TemplateGet() переключают и возвращают активную группу шаблонов, LanguageSet($mLang) и LanguageGet() — язык страницы. Умолчания для обоих берутся из config.json (MELBIS_TEMPLATE и MELBIS_LANG).

В корневом скрипте, до вызова Run, выбор действует на все модули страницы:

MELBIS()->TemplateSet('mobile');
MELBIS()->LanguageSet('en');

MELBIS()->Run($entry_point, $entry_param);

Группу можно переключить и внутри модуля. С этого места шаблоны и кэш берутся из новой группы — у самого модуля и у модулей, которые выполнятся после него. Шаблон, прочитанный контекстом до переключения, контекст второй раз не читает, поэтому шаблоны новой группы разбирают в новом контексте:

$was = MELBIS()->TemplateGet();
MELBIS()->TemplateSet('mail');

$tpl = MELBIS()->TplCreate();
MELBIS()->TplParse($tpl, 'LETTER', 'letter');
$letter = MELBIS()->TplFree($tpl, 'LETTER');

MELBIS()->TemplateSet($was);

Системные теги — {PATH}, {TEMPLATE} и остальные — подставляются в вывод модуля после его возврата, по группе, которая стоит в этот момент. Модуль из примера вернул прежнюю группу, поэтому {PATH} в его выводе ведёт в неё. Если вывод модуля должен ссылаться на новую группу, её не возвращают до конца модуля.

Типичный случай — выбор мобильной группы по устройству посетителя или языка по сегменту URL. Устройство и предпочитаемый язык отдают методы AgentDevice и AgentLanguage — см. «Посетитель».

Читающая пара нужна в коде модуля, когда логика зависит от версии витрины или языка:

$is_mobile = ( MELBIS()->TemplateGet() == 'mobile' );
$lang      = MELBIS()->LanguageGet();

От текущего языка зависят и мультиязычные модификаторы inum, inums, idate (см. «Модификаторы»). В самих шаблонах оба значения доступны без PHP — системными тегами {TEMPLATE} и {LANG}.

Кеш разложен по группам физически: у каждой группы свои каталоги базового и Trick-кеша. Поэтому один и тот же адрес, отданный в разных группах, в кеше не пересекается — две версии витрины могут жить на одном домене.