Платформа Melbis использует архитектуру MVC: логика работы с данными сосредоточена в PHP-коде модуля, а формирование HTML-кода — в шаблонах. Хотя PHP позволяет собрать весь HTML прямо в модуле с помощью простых операций подстановки строк, мы настоятельно рекомендуем этого не делать. Шаблонизатор Melbis оснащён мощным инструментарием: циклы, условия, модификаторы, колбэки, вложенность — всё это избавляет модуль от логики отображения и делает код чище и поддерживаемее.
Где лежат .htm-файлы, что такое группа шаблонов и как
выбрать её для конкретного посетителя — в разделе «Группы шаблонов».
Все взаимодействия модуля с шаблонизатором происходят через методы
MELBIS()->Tpl*:
TplCreate() — создаёт новый контекст
шаблонизатора и возвращает его указатель. Вызывается в начале каждого
модуля:
$tpl = MELBIS()->TplCreate();TplAssign($tpl, $vars, $value = '') —
передаёт данные в контекст, полностью затирая то, что
лежало под этим именем раньше: и скаляр, и массив, независимо от того,
что записывается сейчас. Это простое присваивание, никаких слияний.
Вызывается в двух формах — пара «имя + значение» или один массив пар:
// Имя + значение
MELBIS()->TplAssign($tpl, 'TITLE', 'Каталог товаров');
// Вложенный массив — в шаблоне доступен как {PAGE:TITLE}, {PAGE:DIR} и т.д.
MELBIS()->TplAssign($tpl, 'PAGE', $page);
// Массивом пар: каждый ключ становится отдельной переменной
MELBIS()->TplAssign($tpl, $product);
MELBIS()->TplAssign($tpl, ['TITLE' => 'Каталог', 'GOODS' => $goods]);При передаче массивом пар третий аргумент не используется.
Ключи приводятся к верхнему регистру — и само имя
переменной, и все строковые ключи внутри переданного массива, на любую
глубину. В PHP можно писать как удобно:
TplAssign($tpl, 'page', $page) и
TplAssign($tpl, 'PAGE', $page) — одно и то же, а в шаблоне
ключ всегда пишется в UPPERCASE. Числовые ключи списков остаются как
есть.
TplAppend($tpl, $var, $value = '', $replace = false)
— дописывает значение к уже существующей переменной, не затирая её
целиком. Поведение жёстко зависит от типа $value, и это два
принципиально разных режима:
.
(то же самое, что PHP-шный $var .= $value). Это касается и
чисел: если в переменной лежит 5, а вы вызовете
TplAppend($tpl, 'COUNT', 3), получится строка
"53", а не число 8 — оператор .
не умеет складывать, только склеивать текст. Для числового накопления
считайте сумму в PHP и записывайте через TplAssign.$replace = false) — глубокое слияние на любую вложенность:
совпавшие ассоциативные подключи сохраняются на каждом уровне, а
совпавшие числовые списки (например, галереи) не портятся позиционно, а
дописываются в конец. С $replace = true —
слияние одноуровневое: совпавший ключ заменяется новым значением
целиком, вместе со всем, что было внутри него (списки в этом режиме не
дописываются, а подменяются). Строковой склейки внутри массивов не
бывает никогда ни в одном из режимов — это только про скаляры.Если тип не совпал, старое значение теряется. Дописать массив туда, где лежит скаляр, — скаляр отбрасывается, слияние начинается с пустого массива. Дописать скаляр туда, где лежит массив, — массив отбрасывается, и в переменной остаётся только новая строка. Ошибки при этом не будет, поэтому следите, чтобы
Appendполучал тот же тип, что уже лежит в переменной.
Формы вызова те же, что у TplAssign, но с одной
особенностью: при передаче массивом пар роль
$replace играет второй аргумент, а не
четвёртый.
// Имя + значение
MELBIS()->TplAppend($tpl, 'TAGS', $extra_tags);
// Массивом пар: второй аргумент — $replace
MELBIS()->TplAppend($tpl, ['TAGS' => $extra_tags, 'FILTERS' => $extra_filters]);
MELBIS()->TplAppend($tpl, ['SETTINGS' => $extra_settings], true); // одноуровневая замена вместо слиянияTplParse($tpl, $var, $file) — загружает
.htm-шаблон по имени файла, парсит его с текущими данными
контекста и помещает результат в переменную. Имя переменной может быть
путём: TplParse($tpl, 'PAGE:CONTENT', 'page_index') положит
разобранный шаблон внутрь PAGE, создав недостающие уровни.
Именно этим методом модуль собирает различные части своего HTML:
// Спарсить шаблон page_index.htm и записать в переменную CONTENT
MELBIS()->TplParse($tpl, 'CONTENT', 'page_index');
// Дополнительные шаблоны
MELBIS()->TplParse($tpl, 'WINDOWS', 'windows');
MELBIS()->TplParse($tpl, 'SCRIPTS', 'scripts');Накопление результата. Обычно TplParse
записывает результат в переменную, затирая прежнее значение. Точка в
имени файла меняет это поведение на дозапись:
// Обычно: результат заменяет содержимое CONTENT
MELBIS()->TplParse($tpl, 'CONTENT', 'page_index');
// '.имя' — результат дописывается в КОНЕЦ того, что уже лежит в CONTENT
MELBIS()->TplParse($tpl, 'CONTENT', '.page_extra');
// 'имя.' — результат дописывается в НАЧАЛО
MELBIS()->TplParse($tpl, 'CONTENT', 'page_notice.');Приём достался платформе от старого стиля модулей, где список
собирался циклом в PHP: на каждой итерации данные строки передавались
через TplAssign, а
TplParse($tpl, 'ITEM', '.item') дописывал очередную
карточку к предыдущим. Сейчас так писать не нужно — список целиком
передаётся в шаблонизатор одним TplAssign, а перебор делает
цикл {#...} в шаблоне (см. «Синтаксис шаблонов»). Дозапись
остаётся полезной в других случаях: собрать переменную из нескольких
разных шаблонов, добавить блок по условию, приклеить предупреждение
перед основным содержимым.
TplFinal($tpl, $file, $postProdName = false)
— финальный шаг: парсит указанный шаблон (как правило main)
с текущим состоянием контекста (включая уже заполненные переменные из
TplParse) и возвращает готовую HTML-строку. Результат
возвращается из главной функции модуля:
return MELBIS()->TplFinal($tpl, 'main');Третий аргумент — имя функции постобработки, через которую пропускается готовый HTML модуля перед возвратом. Сама функция регистрируется заранее, обычно в библиотечном модуле:
// Регистрация: имя → функция
MELBIS()->DefinePostProd('minify', 'MELBIS_INC_BASE_html');// Применение в любом модуле
return MELBIS()->TplFinal($tpl, 'main', 'minify');Функция получает готовую HTML-строку единственным аргументом и должна
вернуть строку. Это место для сквозных преобразований разметки: сжатие
HTML, подстановка версий у статических файлов, простановка
loading="lazy" у картинок. Если функция с указанным именем
не зарегистрирована, разбор останавливается с ошибкой.
Важно, что постобработка выполняется до кеширования результата модуля — то есть один раз на компиляцию, а не на каждый запрос. Персональные для посетителя данные так подставлять нельзя, для них есть глобальный массив (см. «Глобальный массив»).
TplFree($tpl, $var) — альтернативный
финал: возвращает значение уже готовой переменной контекста и
уничтожает сам контекст. Это TplFetch и
освобождение памяти одним вызовом:
// Модуль собрал всё в CONTENT, и main-шаблон ему не нужен
MELBIS()->TplParse($tpl, 'CONTENT', 'page_index');
return MELBIS()->TplFree($tpl, 'CONTENT');Разница с TplFinal в том, что TplFinal
разбирает указанный .htm-файл с текущими данными, а
TplFree ничего не парсит — просто отдаёт то, что уже
накоплено. После вызова указатель $tpl недействителен:
обращаться к этому контексту больше нельзя. Имя переменной обязано
существовать — как и TplFetch без значения по умолчанию, на
неизвестном имени метод останавливает разбор с ошибкой.
TplParseStr($tpl, $var, $str, $vars = [])
— то же, что TplParse, но шаблон берётся не из файла, а из
переданной строки. Нужен, когда разметка приходит из базы: письма,
SMS-шаблоны, тексты соглашений с подстановками, которые редактирует
менеджер.
$template = $letter['body']; // '<p>Здравствуйте, {NAME}! Заказ {ORDER_ID} принят.</p>'
$vars = [
'NAME' => $client['name'],
'ORDER_ID' => $order_id
];
MELBIS()->TplParseStr($tpl, 'LETTER', $template, $vars);Четвёртый аргумент — необязательный набор данных, он просто
передаётся в контекст перед разбором, как если бы вы вызвали
TplAssign. Строке доступны все возможности шаблонизатора:
циклы, условия, модификаторы.
TplParseVar($tpl, $var, $varTemplate) —
разбирает как шаблон значение другой переменной
контекста, а результат кладёт в $var. Применяется,
когда текст с тегами уже попал в контекст раньше и его нужно разобрать
вторым проходом. Точка в имени работает так же, как у
TplParse. Путём может быть и приёмник, и источник, но
правила у них разные: приёмнику недостающие уровни создаются, источник
же только читается — если такого пути нет, в приёмник попадёт пустая
строка.
TplFetchAll($tpl) — возвращает все
переменные контекста одним массивом. Инструмент отладки: посмотреть, что
реально накопилось в шаблонизаторе к моменту вызова. В рабочем коде
вместо него берите конкретное значение через TplFetch.
TplFetch($tpl, $var, $default = null) —
читает значение переменной обратно уже на стороне PHP. Принимает и путь:
TplFetch($tpl, 'PAGE:DIR') достанет вложенный элемент,
ничего при этом не создавая. Если переменной с таким именем или путём
нет: без третьего аргумента — ошибка парсинга (защита от опечаток в
имени); если третий аргумент передан (даже null) — вернётся
он, без ошибки. Это разные вызовы, а не один и тот же с «более мягким»
дефолтом:
MELBIS()->TplFetch($tpl, 'DEBUG_INFO'); // нет переменной — упадёт с ошибкой
MELBIS()->TplFetch($tpl, 'DEBUG_INFO', null); // нет переменной — вернёт null, без ошибки
MELBIS()->TplFetch($tpl, 'DEBUG_INFO', []); // нет переменной — вернёт []TplClear($tpl, $var) — удаляет
переменную (или несколько) из контекста, как будто её никогда не
передавали через TplAssign. Принимает как одно имя, так и
массив имён, и в любом из них — путь:
TplClear($tpl, 'PAGE:DIR') удалит один вложенный ключ,
оставив остальной PAGE нетронутым. Несуществующий путь
просто игнорируется.
// Удалить одну переменную
MELBIS()->TplClear($tpl, 'DEBUG_INFO');
// Удалить сразу несколько
MELBIS()->TplClear($tpl, ['DEBUG_INFO', 'RAW_VARS']);Везде, где метод принимает имя переменной, вместо простого
имени можно передать путь через : — в той же
нотации, что используется на чтение в шаблонах
({PAGE:DIR}). Тогда метод адресует не всю переменную
целиком, а один конкретный вложенный элемент, не трогая соседей.
Различаются методы только тем, создают ли они недостающие уровни пути:
| Метод | Создаёт недостающие уровни |
|---|---|
TplAssign, TplAppend |
да |
TplParse, TplParseStr |
да |
TplParseVar |
приёмник — да, источник — нет |
TplFetch, TplClear |
нет |
Правило простое: пишущие методы путь создают, читающие —
нет. Поэтому TplFetch по несуществующему пути даст
ошибку разбора (или вернёт значение по умолчанию), а
TplClear просто ничего не сделает — ни тот, ни другой
ничего не создадут и не испортят.
// Вместо «прочитать весь PAGE, поправить DIR в PHP, записать PAGE обратно целиком»
MELBIS()->TplAssign($tpl, 'PAGE:DIR', '/catalog/');
// затронут только PAGE:DIR — остальные ключи PAGE остаются как былиПуть работает во всех формах вызова, в том числе ключом внутри массива пар — это удобно, когда нужно разложить несколько значений по разным веткам одним вызовом:
MELBIS()->TplAssign($tpl, [
'PAGE:DIR' => '/catalog/',
'PAGE:TITLE' => 'Каталог',
'USER:NAME' => $client_name
]);Регистр не важен. Путь целиком приводится к верхнему
регистру, поэтому 'page:dir' и 'PAGE:DIR' —
одно и то же.
Числовые сегменты адресуют элемент списка:
TplAssign($tpl, 'GALLERY:0:TITLE', 'Обложка') меняет
заголовок первой картинки галереи, не перезаписывая остальные.
Промежуточные уровни создаются сами. Если
PAGE ещё нет, TplAssign($tpl, 'PAGE:DIR', '/')
создаст и PAGE, и ключ внутри. Это касается только
Assign и Append; Fetch и
Clear ничего не создают — при отсутствующем пути
Fetch завершится ошибкой разбора (или вернёт значение по
умолчанию, если оно передано), а Clear просто ничего не
сделает.
Промежуточный скаляр по пути будет уничтожен. Если в
PAGEлежала строка, тоTplAssign($tpl, 'PAGE:DIR', '/')превратитPAGEв массив, а прежняя строка пропадёт: путь требует, чтобы все уровни выше листа были массивами. Ошибки не будет.
Разница ровно та же, что и без пути, но по пути она видна нагляднее — сравните на одних и тех же данных:
MELBIS()->TplAssign($tpl, 'PAGE', ['DIR' => '/catalog/', 'TITLE' => 'Каталог']);
// Assign по пути — чистая замена листа
MELBIS()->TplAssign($tpl, 'PAGE:TITLE', 'Новинки');
// PAGE = ['DIR' => '/catalog/', 'TITLE' => 'Новинки']
// Append по пути — конкатенация текста в том же листе
MELBIS()->TplAppend($tpl, 'PAGE:TITLE', ' — страница 2');
// PAGE = ['DIR' => '/catalog/', 'TITLE' => 'Новинки — страница 2']Правило простое: Assign по пути — заменить лист,
Append по пути — дописать к листу. Соседние ключи
не страдают ни в том, ни в другом случае.
Ради этого путь и появился. Раньше, чтобы поменять один вложенный
лист, приходилось передавать в Append целый вложенный
массив — и рисковать соседними ключами, если слияние оказывалось
одноуровневым, — либо читать переменную целиком, править в PHP и
записывать обратно. С путём адресуется ровно один лист, и выбор между
заменой и дозаписью делается явно.
Таким образом, типичный сценарий работы модуля с шаблонизатором выглядит так:
function MELBIS_BASE_PAGE($mVars)
{
$tpl = MELBIS()->TplCreate();
// ... получить данные из БД ...
// Передать данные
MELBIS()->TplAssign($tpl, 'PAGE', $page);
MELBIS()->TplAssign($tpl, 'GOODS', $goods);
// Собрать нужный вариант контента
MELBIS()->TplParse($tpl, 'CONTENT', 'page_goods');
// Собрать дополнительные части
MELBIS()->TplParse($tpl, 'SCRIPTS', 'scripts');
// Вернуть итоговый HTML
return MELBIS()->TplFinal($tpl, 'main');
}