Wiki
Clone wikiCMS / Синтаксис_шаблонного_интерпретатора
Начиная с версии Atom-M 2.3.4 можно подключать специальный шаблонный интерпретатор, который, по умолчанию, подключен в шаблонах. Как подключить его в другое место написано тут: Подключение шаблонизатора
Итак начнем.
Прежде всего, важно помнить, что неверно составленное условие или конструкция, может привести к ошибке и шаблон вообще не будет обработан, а вместо этого ты увидишь белый экран(если дебаг выключен) или ошибку(если дебаг включен). Так что старайся хорошо тестировать свои шаблоны, проверять все возможные пути развития событий. Например, если у тебя в шаблоне есть условие, необходимо проверить как этот код отработает в том случае когда условие верно и когда не верно. Такой подход поможет сэкономить тебе много времени и нервов в будущем.
Арифметические операции
На данный момент поддерживается:
-
"+" - сложение (или "~" если нужно сложить строки)
-
"-" - вычитание
-
"*" - умножение
-
"/" - деление
-
"%" - нахождение остатка
Переменные
Вся прелесть шаблонизатора заключается в том, что он может работать с контекстом, переданным ему из другой области (в нашем случае из PHP). Другими словами - мы можем использовать в шаблонах переменные, пришедшие к нам из PHP, не зная ничего о самом PHP вообще. Не правда ли это круто? Дело в том, что каждый шаблон имеет свой, заранее определенный контекст, например, шаблон list.html принимает массив новостей, хранящийся в переменной entities. Но кроме этого, он так же принимает и некий набор глобальных переменных (доступных в любом шаблоне), например, title, meta_description и т.д. Но как же нам вывести значение этих переменных в шаблон, чтобы они были видны пользователям? Очень просто:
#!html <!-- Выводим заголовок --> <title>{{ title }}</title> <!-- Выводим описание --> <meta name="description" content="{{ meta_description }}" /> <!-- просто какая-то переменная --> {{ entity.some_var }}
Если попытаться вывести несуществующую переменную, то вместо нее выведется просто пустая строка, тоесть "ничего". Как это ни странно). Но при работе с циклами и уловными выражениями все может быть не так гладко, будьте осторожны.
Фильтры
Теперь мы знаем как выводить переменные, но переменные бывают разные и выводиться они тоже могут в разных местах. Зачастую необходимо эти переменные экранировать, точнее экранировать HTML сущности в них, чтобы пользователи увидели текст, как текст, а не как HTML код. Это кстати спасает от такой плохой штуки как XSS. И вот тут нам на помощь приходят фильтры. Использовать фильтры очень просто:
#!html <!-- Переводим HTML в простой текст в заголовке --> <title>{{ title|escape }}</title> <!-- Пример фильтра с параметрами(разобьет текущий URL страницы на составляющие в виде элементов массива) --> <title>{{ fps_request_url|split('/') }}</title>
Как видите, все предельно просто. Стоит заметить, что существует очень много разнообразных фильтров. И в отличие от функций они редактируют обьекты(переменные) или создают новые из других обьектов. Функции же в нашем шаблонизаторе предназначены для создания обьекта "с нуля", хотя и редактировать обьекты они тоже могут. Спрашивается, зачем же нужны фильтры если есть функции? Скажем так, просто для красоты и совместимости с twig-подобными шаблонизаторами.
Условные выражения(Оператор if)
Условные выражения позволяют делать проверку на содержимое метки и в зависимости от результата выводить тот или иной html.Тут все так же, как в любом языке программирования. Их синтаксис прост:
#!php {% if <сравнительное значение> <знак сравнения> <сравнительное значение> %} Условное выражение истина(правильно) {% else if <сравнительное значение> <знак сравнения> <сравнительное значение> %} Второе условное выражение истина(правильно), а первое ложь(не правильно) {% else %} Оба условных выражения ложь(не правильно) {% endif %}
- <знак сравнения> - знак сравнения, может быть одним из:
-
- == - нестрогое равенство.
-
- != - нестрогое не равно.
-
- >= - то что с лева больше или равно того что с права.
-
- <= - то что с лева меньше или равно того что с права.
-
- > - то что с лева больше того что с права.
-
- < - то что с лева меньше того что с права.
-
- in - проверка на вхождение, того что с лева в последовательность, того что с права.
-
- not in - обратная процедура in проверка на не вхождение.
-
- === - строгое равенство(Новое в Atom-M 5).
-
- !== - строгое не равно(Новое в Atom-M 5).
- <сравнительное значение> - значение, метка(Внутри конструкций {% %} записывается без {{ }}) или выражение для получения значения.
Стоит упомянуть, что шаблонизатор поддерживает даже несколько условий в одном выражении if. Для этого специально существует операторы объединения нескольких условий, состоящих из <сравнительное значение> <знак сравнения> <сравнительное значение> или только <сравнительное значение>(см.ниже): * and - оператор вернет истину, если оба выражения, которые он соединяет, истинны. * or - оператор вернет истину если хотя бы одно из выражений которые он соединяет истинно.
истина - в понятии логики программирования означет, что условие выполнилось. (например, 5 > 3 - истина, а 5 < 3 - ложь)
Также знайте, {% else %} и {% else if ... %} являются не обязательными атрибутами конструкции, Вы можете и не делать никаких действий, если первое условие оказалось ложным. И если вам всего лишь нужно проверить метку на существование(или выражение на истинность), то существует сокращенная запись:
{% if <название метки> %} Метка существует {% endif %}.
метка не существует, если она равна нулю(0), равна лжи(false) или пустой строке ('')
Такая запись эквивалентна: {% if <название метки> == 1 %} Метка существует {% endif %} т.к. оператор == является оператором нестрогого сравнения и приводит сравнительные значения к одному типу, поэтому при сравнении, например '',false,0,[], между собой они окажутся равными.
###Пару примеров:
#!html {% if entity.name == 'Petya' %} <p><span>{{ entity.name }}</span></p> {% else %} <p>{{ entity.name }}</p> {% endif %}
Тут мы выводим ник пользователя, но, если этот ник Petya, мы дополнительно заключаем его в тег span. Но бывают и такие ситуации когда нам не нужен блок else, например как в следующем примере.
#!html {% if entity.views >= 100 and entity.id != 1 %} <div class="congratulation">{{ entity.title }}</div> {% endif %}
Заметил что изменилось, кроме убранного блока else? Правильно - изменилось и само условие. Я сделал это для того, чтобы сразу продемонстрировать тебе еще одну возможность - множественные параметры. Если в первом примере было одно условие, то тут их сразу два(больше 100 просмотров и ID не должен быть 1). На самом деле условий может быть сколько угодно, но надо понимать, что накатай ты 100 условий в одном блоке, ты потом и сам не поймешь откуда ноги растут, так что тут следует быть осторожным или, правильнее сказать, эстетичным. Код должен легко читаться, запомни это и повторяй как мантру. А вот пример самого простого использования if(когда просто надо проверить, что переменная не пустая, тоесть не 0 и не false, и не пустая строка):
#!html {% if entity.title %} <div class="congratulation">{{ entity.title }}</div> {% endif %}
Циклы (Оператор for)
С помощью этого оператора мы сможем "проходить" по каждому элементу некоего массива. Чтобы стало понятнее что это такое, можно вспомнить пример с шаблоном list.html и его контекстом - масиивом записей (entities).Так как это массив, содержажий в себе множество записей, нам надо каким-то образом пройтись по каждой из них. и вот тут тебе должно стать понятно нафига этот for. А использовать его очень просто, возмем пример из предыдущего раздела и применим к каждой записи в нашем массиве:
#!html {% for entity in entities %} <div>{{ entity.name1 }}</div> <div>{{ entity.name2 }}</div> {% endfor %}
Как ты, наверное, заметил, for принимает два параметра (левый и правый) и разделилтель in. Так вот правый параметр - это исходные данные (наш массив), а левый - это новая переменная, которая образуется из каждого элемента массива. Это похоже на for в любом другом языке программирования. Проще говоря, мы выполняем код внутри блока for столько раз, сколько элементов у нас в массиве, но каждый раз в левой переменной (в данном примере entity) будет новая запись (при первом проходе это будет первая запись, при втором - вторая и т.д.).
Пример:
#!php {% for mark in names %} {{ mark.name }} - имя {{ mark.subname }} - фамилия {{ mark.age }} - возраст {% endfor %}
Где mark произвольная комбинация латинских букв и цифр, а names название метки с массивом.
Результатом данного примера будет:
#!php Дарья - имя Петрова - фамилия 18 – возраст Мария - имя Родионова - фамилия 48 – возраст Павел - имя Романов - фамилия 98 - возраст
Присваивание (Оператор set)
Благодаря этому оператору у тебя появляется возможность объявлять внутри щаблона свои переменные с каким хочешь значением. Это самый простой оператор, так что тут и объяснять нечего, можно сразу перейти к примерам:
#!html <!-- Объявляем переменную var --> {% set var = 1 %} <!-- Выводим переменную var --> {{ var }} <!-- Переопределяем переменную var --> {% set var = var * 2 + 1 %} <!-- Выводим переменную var --> {{ var }}
Как видишь, все предельно просто. Но я должен сказать несколько слов об арифметических операциях, которые можно заметить в примере. Подобных сложений, умножений, делений или вычетаний может быть сколь угодно много, но важно помнить приоритетность этих операций. Например умножение и деление сделаются раньше вычетаний и прибавлений, не зависимо от их расположения.
Функции
В шаблонизаторе можно вызывать любые пользовательские функции, находящиеся в глобальной области видимости. В функции так же как в if можно передавать множественные параметры. Конечно работа с этим иструментом уже потребует некоторых знаний, но, если тебе не надо писать новые функции, а просто использовать то, что уже есть.
Например:
Выводим фразу, по ключу (в д.с. 'Up') в выбранном языке, если она есть в файле локализации (data/languages/namelang.php).
#!html {{ __('Up', module) }}
Проверяем, может ли видеть пользователь новости. Подробнее о checkAccess() читайте тут: Метки контроля прав доступа
#!html {{ checkAccess(['news','view_list']) }}
Получаем из БД данные о пользователе и сохраняем из в переменную (fps_user_id - название метки с ID текущего пользователя)
#!html {% set var = fetch('users', fps_user_id) %}
Кастомный вывод материалов из любого места в шаблонизаторе
Для получения данных модулей из БД в любом месте используют функцию fetch().
Список аргументов:
#!html {% set data = fetch(model_name, entity_id=false, get_params={}, binded_fields=[]) %}
Необязательные аргументы:
- entity_id - Указывает ID материала или материалов(массив из ID) которые будут возвращены функцией.
- get_params - Ассоциативный массив(ключ-значение) из параметров для получения данных. Список параметров:
#!javascript { "cache": true, // Время в секундах, на которое кешировать результат запроса.(true = 3600сек) "type": "DB_ALL", // Тип запроса: первый совпавший("DB_FIRST"), все совпавшие("DB_ALL"), количество совпавших("DB_COUNT") материалов. "sort": "name_field_for_sort", // При указании только строки выбирается режим DESC(по возрастанию), но можно указать и массив: ["name_field_for_sort", "ASC"] "limit": 25, // Сколько максимум найденных материалов следует возвращать. "page": 2, // При использовании параметра limit результат запроса делится на "куски" размером в limit материалов. Начиная с первого "куска" можно задавать какой именно "кусок" выводить. По умолчанию выводится первый "кусок". "fields": ["id","title"] // Позволяет выводить данные только из определенных столбцов таблицы, а не из всех сразу. }
Обработка результата функции:
Функция возвращает результат выполнения запроса, либо массив вида {"error":"Bad request"}. Во всех случаях будет возвращен массив, так что на ошибку можно смело проверять наличием ключа "error".(Кроме типа DB_COUNT, тут результатом запроса будет число, а не массив.)
Пример вывода заголовков последних 10 материалов из модуля news c кешированием на один час:
#!html {% set data = fetch("news", false, {"cache":true,"limit":10,"sort":"date"}) %} {% for entity in data %} <h4>{{ entity.title }}</h4> {% endfor %}
Подключение других файлов шаблона
Шаблонизатор позволяет вынести повторяющийся код в отдельный файл и подключать его так же, как include в php подключает другие файлы. В шаблонную функцию include необходимо передать полное название импортируемого файла. Предполагается, что этот файл распологается в той же папке, от куда и вызывается. Чтобы вызвать файл из папки уровнем выше, неодходимо перед адресом указать ../, то есть поддерживается всем привычная работа с адресами файловой системы. Пример импортирует содержимое файла scripts.html из папки(на примере шаблона) template/шаблон/html/default/:
#!html {% include '../default/scripts.html' %}
внутри подключаемого файла будут работать все возможности шаблонизатора и метки, доступные в файле, где был установлен include
Updated