Синтаксис
Синтаксис Latte вырос из практических запросов веб-дизайнеров. Мы искали максимально дружелюбный синтаксис, на котором можно изящно записать конструкции, обычно вызывающие настоящие трудности. При этом все выражения пишутся точно так же, как в PHP, поэтому вам не нужно учить новый язык. Вы просто пользуетесь тем, что уже знаете.
Ниже приведён минимальный шаблон, показывающий несколько базовых элементов: теги, n:атрибуты, комментарии и фильтры.
{* это комментарий *}
<ul n:if=$items> {* n:if - это n:атрибут *}
{foreach $items as $item} {* тег, представляющий цикл foreach *}
<li>{$item|capitalize}</li> {* тег, который выводит переменную с фильтром *}
{/foreach} {* конец цикла *}
</ul>
Рассмотрим эти важные элементы подробнее и посмотрим, как они помогут вам создать замечательный шаблон.
Теги
Шаблон содержит теги, которые управляют логикой шаблона (например,
циклы foreach) или выводят выражения. Для того и другого используется
один разделитель { ... }, поэтому, в отличие от других систем, вам
не нужно думать, какой разделитель в какой ситуации применить. Если
сразу за символом { следует пробельный символ, кавычка или ещё
одна { либо }, Latte не считает это началом тега, поэтому вы
без проблем можете использовать в шаблонах конструкции JavaScript, JSON или
правила CSS.
См. обзор всех тегов. Кроме того, вы можете
создавать собственные теги. Разделители
{ } можно также поменять или полностью отключить (через
{syntax double}, {syntax off} или атрибут n:syntax), см. изменение синтаксиса.
Latte понимает PHP
Внутри тегов можно использовать привычные вам выражения PHP:
- переменные
- строки (включая HEREDOC и NOWDOC), массивы, числа и так далее
- операторы
- вызовы функций и методов (их можно ограничить песочницей)
- match
- стрелочные функции
- синтаксис first class callable
- многострочные комментарии
/* ... */ - и так далее…
Кроме того, Latte дополняет синтаксис PHP несколькими приятными расширениями.
n:атрибуты
Каждый парный тег, например {if} … {/if}, действующий на один
HTML-элемент, можно переписать в виде n:атрибута. Например, {foreach} из
вводного примера можно было записать и так:
<ul n:if=$items>
<li n:foreach="$items as $item">{$item|capitalize}</li>
</ul>
Функциональность тогда применяется к тому HTML-элементу, в котором она размещена:
{var $items = ['I', '♥', 'Latte']}
<p n:foreach="$items as $item">{$item}</p>
выводит:
<p>I</p>
<p>♥</p>
<p>Latte</p>
С помощью префикса inner- мы можем изменить поведение так, чтобы
оно относилось только к внутренней части элемента:
<div n:inner-foreach="$items as $item">
<p>{$item}</p>
<hr>
</div>
Выводит:
<div>
<p>I</p>
<hr>
<p>♥</p>
<hr>
<p>Latte</p>
<hr>
</div>
А с помощью префикса tag- мы применяем функциональность только
к самим HTML-тегам:
<p><a href={$url} n:tag-if="$url">Title</a></p>
Это выводит, в зависимости от переменной $url:
{* когда $url пуста *}
<p>Title</p>
{* когда $url содержит 'https://nette.org' *}
<p><a href="https://nette.org">Title</a></p>
Однако n:атрибуты – это не только сокращение для парных тегов, есть и чистые n:атрибуты, например лучший друг верстальщика n:class или очень удобный n:href.
Помимо синтаксиса с кавычками <div n:if="$foo"> можно
использовать альтернативный синтаксис с фигурными скобками
<div n:if={$foo}>. Главное преимущество в том, что внутри {...}
вы свободно используете и одинарные, и двойные кавычки:
<div n:if={str_contains($val, "foo")}> ... </div>
Умные HTML-атрибуты
Latte делает работу с обычными HTML-атрибутами невероятно простой. Он сам
заботится о логических атрибутах вроде checked, убирает атрибуты
со значением null и позволяет собирать значения class и
style из массивов. Он даже автоматически сериализует данные для
атрибутов data- в JSON.
{* null убирает атрибут *}
<div title={$title}>
{* логическое значение управляет наличием логических атрибутов *}
<input type="checkbox" checked={$isChecked}>
{* массивы работают в class *}
<div class={['btn', 'btn-primary', active => $isActive]}>
{* массивы кодируются в JSON в атрибутах data- *}
<div data-config={[theme: dark, version: 2]}>
Подробнее в отдельной главе Умные HTML-атрибуты.
Фильтры
См. обзор стандартных фильтров.
Фильтры пишутся после символа вертикальной черты (пробел перед ней допустим):
<h1>{$heading|upper}</h1>
Фильтры можно объединять в цепочку, они применяются по порядку слева направо:
<h1>{$heading|lower|capitalize}</h1>
Аргументы указываются после имени фильтра через двоеточие, а последующие отделяются запятыми; работает и вызов со скобками:
<h1>{$heading|truncate:20,''}</h1>
<h1>{$heading|truncate(20, '')}</h1>
Фильтры можно применять и к выражению:
{var $name = ($title|upper) . ($subtitle|lower)}
К блоку:
<h1>{block |lower}{$heading}{/block}</h1>
Или прямо к значению (в сочетании с тегом {=expr}):
<h1>{=' Hello world '|trim}</h1>
Если значение может быть null и вы хотите в этом случае не
применять фильтр, используйте nullsafe-фильтр ?|:
<h1>{$heading?|upper}</h1>
Динамические HTML-теги
Latte поддерживает динамические HTML-теги, полезные тогда, когда вам нужна гибкость в именах тегов:
<h{$level}>Heading</h{$level}>
Например, приведённый выше код может породить <h1>Heading</h1>
или <h2>Heading</h2> в зависимости от значения переменной
$level. Динамические HTML-теги в Latte всегда должны быть парными. Их
альтернатива – n:tag.
Поскольку Latte – безопасная система шаблонов, он проверяет, что получившееся имя тега корректно и не содержит нежелательных или вредоносных значений. Он также следит за тем, чтобы имя закрывающего тега всегда совпадало с именем открывающего.
Комментарии
Комментарии пишутся вот так и в вывод не попадают:
{* это комментарий в Latte *}
Внутри тегов работают комментарии PHP:
{include 'file.info', /* value: 123 */}
Управление пробелами
Latte разумно обходится с пробельными символами. Вы можете свободно
делать отступы ради читаемости, а вывод останется чистым. Когда
управляющий тег стоит на строке один, вся строка (отступ и перевод
строки) убирается из вывода (это не относится к тегам, которые что-то
выводят, таким как {$var}, {=...} или {_...}: они сохраняют
свой отступ и завершающий перевод строки):
<ul>
{foreach $items as $item}
<li>{$item}</li>
{/foreach}
</ul>
Выводит:
<ul>
<li>foo</li>
<li>bar</li>
</ul>
А что, если тег стоит на строке не один, а рядом с другим содержимым? Тогда пробельные символы перед тегом принадлежат внутренней части тега:
<div>
{if $foo}hello{/if}
</div>
Отступ фактически находится внутри {if}: когда $foo ложно,
не выводится ничего, ни отступа, ни пустой строки. Когда $foo
истинно, вывод естественным образом включает отступ. Вы просто пишете
хорошо структурированные шаблоны, а вывод всегда получается чистым.
Для ещё более чистого вывода можно включить возможность Dedent, которая убирает и отступы,
возникающие из-за вложенности в парные теги вроде {if} или
{foreach}.
Синтаксический сахар
Строки без кавычек
У простых строк кавычки можно опустить:
как в PHP: {var $arr = ['hello', 'btn--default', '€']}
сокращённо: {var $arr = [hello, btn--default, €]}
Простые строки – это строки, состоящие только из букв, цифр,
подчёркиваний, дефисов и точек. Они не должны начинаться с цифры и не
должны начинаться или заканчиваться дефисом. Они не должны состоять
только из заглавных букв и подчёркиваний, потому что тогда считаются
константами (например, PHP_VERSION). И они не должны совпадать с
ключевыми словами: and, array, clone, default,
false, in, instanceof, new, null, or,
return, true, xor.
Константы
Чтобы отличить глобальные константы от простых строк, используйте разделитель глобального пространства имён:
{if \PROJECT_ID === 1} ... {/if}
Такая запись полностью корректна и в самом PHP, где обратный слеш указывает, что константа находится в глобальном пространстве имён.
Краткий тернарный оператор
Если третье значение тернарного оператора пустое, его можно опустить:
как в PHP: {$stock ? 'In stock' : ''}
сокращённо: {$stock ? 'In stock'}
Современная запись ключей в массивах
Ключи массива можно записывать так же, как именованные параметры при вызове функций:
как в PHP: {var $arr = ['one' => 'item 1', 'two' => 'item 2']}
современно: {var $arr = [one: 'item 1', two: 'item 2']}
Фильтры
Фильтры можно применять к любому выражению, достаточно заключить всё выражение в скобки:
{var $content = ($text|truncate: 30|upper)}
Оператор in
Оператор in может заменить функцию in_array(). Сравнение
всегда строгое:
{* как in_array($item, $items, true) *}
{if $item in $items}
...
{/if}
Окно в историю
За свою историю Latte ввёл несколько приёмов синтаксического сахара,
которые несколько лет спустя появились и в самом PHP. Например, в Latte
можно было писать массивы как [1, 2, 3] вместо array(1, 2, 3) или
использовать nullsafe-оператор $obj?->foo задолго до того, как это
стало возможным в самом PHP. Latte также ввёл оператор развёртывания
массива (expand) $arr, равнозначный сегодняшнему оператору
...$arr из PHP.
Ограничения PHP в Latte
В Latte можно писать только выражения PHP. То есть инструкции,
заканчивающиеся точкой с запятой, использовать нельзя. Нельзя
объявлять классы или использовать управляющие конструкции, такие
как if, foreach, switch, return, try, throw и
другие, для которых Latte предлагает свои теги.
Также нельзя использовать атрибуты, обратные кавычки и некоторые магические константы. Нельзя
использовать и unset, echo, include, require, exit,
eval, потому что это не функции, а специальные конструкции языка PHP
и, следовательно, не выражения. Поддерживаются только многострочные
комментарии /* ... */.
Впрочем, эти ограничения можно обойти, включив расширение RawPhpExtension, которое позволяет
использовать внутри тега {php ...} любой PHP-код под ответственность
автора шаблона.