Синтаксис

Синтаксис 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:

Кроме того, 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-код под ответственность автора шаблона.

версия: 3.x