Главная » Статьи » Документация » Дизайн и шаблоны
Категории

Синтаксис шаблоного интерпретатора

В шаблонах можно использовать синтаксис схожий с языком программирования. Это позволяет использовать такие плюшки как условные операторы, циклы, присваивание, фильтры. Далее я постараюсь раскрыть все возможности шаблонизатора(так называют интерпретаторы шаблонов).

Прежде всего, важно помнить, что неверно составленное условие или конструкция, может привести к ошибке и шаблон вообще не будет обработан, а вместо этого ты увидишь белый экран(если дебаг выключен) или ошибку(если дебаг включен). Так что старайся хорошо тестировать свои шаблоны, проверять все возможные пути развития событий. Например, если у тебя в шаблоне есть условие, необходимо проверить как этот код отработает в том случае когда условие верно и когда не верно. Такой подход поможет сэкономить тебе туеву хучу времени и нервов в будущем.

Но хватит подготовки - пора переходить к делу.

Переменные

Вся прелесть шаблонизатора заключается в том, что он может работать с контекстом, переданным ему из другой области(в нашем случае из PHP). Другими словами - мы можем использовать в шаблонах переменные, пришедшие к нам из PHP, не зная ничего о самом PHP вообще. Не правда ли это круто? Дело в том, что каждый шаблон имеет свой, заранее определенный контекст, например, шаблон list.html принимает массив новостей, хранящийся в переменной entities. Но кроме этого, он так же принимает и некий набор глобальных переменных(доступных в любом шаблоне), например, title, meta_description и т.д. Но как же нам вывести значение этих переменных в шаблон, чтобы они были видны пользователям? Очень просто:
1
2
3
4
5
6
<!-- Выводим заголовок -->
<title>{{ title }}</title>
<!-- Выводим описание -->
<meta name="description" content="{{ meta_description }}" />
<!-- просто какая-то переменная -->
{{ entity.some_var }}
Если попытаться вывести несуществующую переменную, то вместо нее выведется просто пустая строка, тоесть "ничего". Как это ни странно)

Выражения

Внутри метки "{{ some_value }}" так же доступны выражения(expressions). Это могут быть арифметические операции, группировка или конкатенация.
Например:
1
2
3
4
5
{# Будет выведен результат выражения #}
{{ 20 / (2 * var) }}
{# Так же есть поддержка JSON формата(>= 2.6 rc2). Фильтр show здесь исключительно для того, чтобы мы могли увидеть конечный массив #}
{{ {'key1': 'value1', 'key2': 'value2'}|reverse|show }}
{# array('key2' => 'value2', 'key1' => 'value1') #}
Выражения поддерживаются повсеместно в шаблонизаторе. Например внутри конструкций IF, FOR, SET.

Фильтры

Теперь мы знаем как выводить переменные, но переменные бывают разные и выводиться они тоже могут в разных местах. Зачастую необходимо эти переменные экранировать, точнее экранировать HTML сущности в них, чтобы пользователи увидели текст, как текст, а не как HTML код. Это кстати спасает от такой плохой штуки как XSS. И вот тут нам на помощь приходят фильтры. Использовать фильтры очень просто:
1
2
3
4
<!-- Переводим HTML в простой текст в заголовке(используем фильтр escape) -->
<title>{{ title|escape }}</title>
<!-- Пример фильтра с параметром -->
<title>{{ title|match('#regexp#') }}</title>
Список фильтров


Оператор if

Этот оператор позволяет проверить на истинность некое условие или несколько условий, а затем выполнить тот или иной участок кода. Тут все так же, как в любом языке программирования. Давай рассмотрим небольшой пример:
1
2
3
4
5
{% if entity.name == 'Petya' %}
    <p><span>{{ entity.name }}</span></p>
{% else %}
    <p>{{ entity.name }}</p>
{% endif %}
Тут мы выводим ник пользователя, но, если этот ник Petya, мы дополнительно заключаем его в тег span. Но бывают и такие ситуации когда нам не нужен блок else, например как в следующем примере.
1
2
3
{% if entity.views >= 100 and entity.id != 1 %}
    <div class="congratulation">{{ entity.title }}</div>
{% endif %}
Заметил что изменилось, кроме убранного блока else? Правильно - изменилось и само условие. Я сделал это для того, чтобы сразу продемонстрировать тебе еще одну возможность - множественные параметры. Если в первом примере было одно условие, то тут их сразу два(больше 100 просмотров и ID не должен быть 1). На самом деле условий может быть сколько угодно, но надо понимать, что накатай ты 100 условий в одном блоке, ты потом и сам не поймешь откуда ноги растут, так что тут следует быть осторожным или, правильнее сказать, эстетичным. Код должен легко читаться, запомни это и повторяй как мантру. А вот пример самого простого использования if(когда просто надо проверить, что переменная не пустая, то есть больше чем 0 и не false, и не пустая строка):
1
2
3
{% if entity.title %}
    <div class="congratulation">{{ entity.title }}</div>
{% endif %}
Начиная с версии 2.6 rc3 появилась поддержка конструкции elseif.

Оператор for

С помощью этого оператора мы сможем проходить итеративно по каждому элементу некоего массива. Чтобы стало понятнее что это такое, можно вспомнить пример с шаблоном list.html и его контекстом - масиивом записей(entities). Так как это массив, содержащий в себе множество записей, нам надо каким-то образом пройтись по каждой из них. и вот тут тебе должно стать понятно нафига этот for. А использовать его очень просто, возьмем пример из предыдущего раздела и применим к каждой записи в нашем массиве:
1
2
3
4
5
{% for entity in entities %}
    {% if entity.title %}
        <div class="congratulation">{{ entity.title }}</div>
    {% endif %}
{% endfor %}
Как ты, наверное, заметил, for принимает два параметра(левый и правый) и разделитель in. Так вот правый параметр - это исходные данные(наш массив), а левый - это новая переменная, которая образуется из каждого элемента массива. Это похоже на for в любом другом языке программирования. Проще говоря, мы выполняем код внутри блока for столько раз, сколько элементов у нас в массиве, но каждый раз в левой переменной(в данном примере entity) будет новая запись(при первом проходе это будет первая запись, при втором - вторая и т.д.). Так же есть возможность получать индекс текущего элемента:
1
2
{% for key, entity in entities %}
{% endfor %}

Оператор set

Или присваивание. Благодаря этому оператору у тебя появляется возможность объявлять внутри шаблона свои переменные с каким хочешь значением. Это самый простой оператор, так что тут и объяснять нечего, можно сразу перейти к примерам:
1
2
3
4
5
6
7
8
9
10
11
12
<!-- Объявляем переменную var -->
{% set var = 1 %}
<!-- Выводим переменную var -->
{{ var }}
<!-- Переопределяем переменную var -->
{% set var = var * 2 + 1 %}
<!-- Выводим переменную var -->
{{ var }}
<!-- Объявляем массив -->
{% set array = [] %}
<!-- Добавляем элемент в массив -->
{% set array[] = 'test' %}
Как видишь, все предельно просто. Но я должен сказать несколько слов об арифметических операциях, которые можно заметить в примере. Подобных сложений, умножений, делений или вычитаний может быть сколь угодно много, но важно помнить приоритетность этих операций. Например умножение и деление сделаются раньше вычитаний и прибавлений, не зависимо от их расположения.

Функции

В шаблонизаторе можно вызывать любые пользовательские функции, находящиеся в глобальной области видимости. В функции так же как в if можно передавать множественные параметры. Конечно работа с этим инструментом уже потребует некоторых знаний, но, если тебе не надо писать новые функции, а просто использовать то, что уже есть, то вот пара примеров:
1
2
3
4
5
6
<!-- Преобразуем дату в красивый формат -->
{{ AtmGetDate(entity.date) }}
<!-- Преобразуем дату в свой формат -->
{{ AtmGetDate(entity.date, 'Y-m-d H:i:s') }}
<!-- Получаем из БД пользователя и сохраняем в переменную (fps_user_id - ID текущего пользователя) -->
{% set var = fetch('users', fps_user_id) %}

Авто-преобразование ссылок на страницы(pages)

Ну тут все вообще просто. Так как можно задавать страницам в модуле Pages свои ссылки и они могут меняться, то чтобы потом не искать по всему сайту старую ссылку и менять ее на новую, мы можем сделать так:
1
<a href="[~ 1 ~]">Link</a>
В данном примере мы выводим ссылку на страницу с ID = 1. Так же стоит помнить, что если мы выводим ссылку на вложенную страницу, то конечная ссылка будет иметь вид /firs_page_url/second_page_url/last_page_url.
Если у страницы нет кастомной ссылки, будет выведен ее ID вместо ссылки(/firs_page_url/second_page_url/last_page_ID).

Сниппеты

Сниппеты - это произвольные куски PHP кода, которые можно выводить в шаблоне, точнее выводится не сам код, а результат его выполнения. Сниппеты бывают кэшируемые и не кэшируемые. Кэшируемые сниппеты можно использовать когда мы выводим данные которые долго устаревают, например топ юзеров. Не думаю что такая информация может сильно измениться в течении одного часа(именно на столько кэшируется сниппет). Но когда нам надо вывести, например последние посты с форума, лучше использовать не кэширующий сниппет, так как такая информация может полностью измениться в течении часа. В сниппеты так же можно передавать параметры. Сейчас все покажу на примерах:
1
2
3
4
5
6
<!-- Кэширующий -->
{[snippet_title]}
<!-- Не кэширующий -->
{[!snippet_title]}
<!-- Не кэширующий с параметрами -->
{[!snippet_title?foo=bar&foo2={{ entity.title }}]}
Как видишь, можно передавать как обычные строковые параметры, так и переменные.
Имена сниппетов должы состоять из латинских букв нижнего регистра, цифр и нижнего подчеркивания. Другие символы использовать не желательно.

Include

Думаю тут все понятно из названия. Мы можем подключить один шаблон внутри другого. При этом в подключаемом шаблоне будет доступен весь тот же контекст, что и в шаблоне-родителе. Пример:
1
{% include 'test.html' %}
Помни, друг мой, пути в этой конструкции используются относительные. Корнем считается папка html текущего шаблона. В примере выше будет подключен файл /template/your_template/html/test.html.

Конкатенация (начиная с версии 2.5 RC2)

Конкатенация - это объединение строк в одну. Конкатенировать можно либо строки, либо переменные, либо их между собой. Конечно может возникнуть вопрос - нафига нам конкатенация, если мы можем делать так:
1
2
<!-- foo = bar -->
some_string{{ foo }}
В итоге, после парсинга, мы увидим
1
some_stringbar
Все ок, без всякой конкатенации. Так за чем она нужна? А что делать в таком случае?
1
2
3
4
<!-- Не правильно! -->
{{ function('some_string'{{ foo }}) }}
<!-- Правильно! -->
{{ function('some_string' ~ foo) }}
Вот мы и разобрались, для чего была придумана конкатенация. Но это не единственное ее возможное использование. Вот еще пример:
1
{% set var = 'string' ~ foo %}

Группировка (начиная с версии 2.5 RC2)

Группировка позволяет группировать выражения при помощи скобок. Тут, для лучшего понимания, нужны сразу примеры:
1
2
3
4
5
6
<!-- Результат = 3 -->
{% set var = 1 + 1 * 1 + 1 %}
<!-- Результат = 4 -->
{% set var = (1 + 1) * (1 + 1) %}
<!-- Пример группировки в IF -->
{% if (1 == 1 or 1 == 2) and var == 'test' %}
Результаты в арифметических операциях отличаются из-за приоритета операторов(умножение первое, потом деление и так делее. Я жил далеко от школы, но еще помню). Скобки позволяют задать нужный нам порядок выполнения.

Комментирование (начиная с версии 2.6 RC2)

Тут все предельно просто - все что находится между тегами "{#" и "#}" никак не обрабатывается и не будет видно в конечном HTML коде.
1
2
{# {{ 'test1' }} #}
{{ 'test2' }}
Если запустить данный пример, мы увидим только "test2".

Примеры того что можно делать

Тут просто примеры конструкций которые понимает шаблонизатор, для более полного представления того, что можно делать.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- Версия >= 2.6 rc1 -->
<!-- Функция как массив для перебора(конечно должна возвращать массив) -->
{% for var in func() %}
{% endfor %}
<!-- Функция как аргумент другой функции -->
{{ func(func2()) }}
<!-- А можно и так -->
{% for var in func(func2()) %}
{% endfor %}
<!-- Вызов функции со сложным параметром -->
{{ func('string' ~ func2() ~ var) }}
<!-- То же самое работает и в остальных метсах, например в присвоении -->
{% set var2 = func('string' ~ func2() ~ var) %}
<!-- А мож и так -->
{% set var2 = func(('string' ~ func2() ~ var) ~ (1 + 2)) %}
<!-- IN в IF является эквивалентом in_array(проверка существования элемента в массиве) -->
{% if 'test' in array %}
{% endif %}
<!-- обращение к массиву по ключу с одновременным использоанием свойства -->
{{ array[i].title }}
{{ array[2].title }}
Дизайн и шаблоны Просмотров: 3557 Комментариев: 4

Комментарии

User avatar
14 Июл 2014
Как вывести информацию из дополнительного поля в материале?..
User avatar
11 Апр 2014
дока проапдейчена
User avatar
28 Мар 2014
Конечно расскажу).
User avatar
28 Мар 2014
Еще нужно про include рассказать