Volt: Шаблонный движок
Volt — это сверхбыстрый и удобный для дизайнеров шаблонный язык, написанный на C для PHP. Он предоставляет набор помощников для написания представлений простым способом. Volt тесно интегрирован с другими компонентами Phalcon, а также может использоваться как самостоятельный компонент в ваших приложениях.
Volt вдохновлен Jinja, первоначально созданным Armin Ronacher. Поэтому многие разработчики будут чувствовать себя знакомо, используя тот же синтаксис, что и в аналогичных движках шаблонов. Синтаксис и возможности Volt были расширены новыми элементами и, конечно же, с производительностью, к которой разработчики привыкли при работе с Phalcon.
Введение
Представления Volt компилируются в чистый код PHP, поэтому они экономят усилия на ручном написании кода PHP:
{# app/views/products/show.volt #}
{% block last_products %}
{% for product in products %}
* Name: {{ product.name|e }}
{% if product.status === "Active" %}
Price: {{ product.price + product.taxes/100 }}
{% endif %}
{% endfor %}
{% endblock %}
Активация Volt
Как и другие движки шаблонов, вы можете зарегистрировать Volt в компоненте представления, используя новый расширение или повторно используя стандартный ".phtml":
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Volt;
// Register Volt as a service
$di->set(
"voltService",
function ($view, $di) {
$volt = new Volt($view, $di);
$volt->setOptions(
[
"compiledPath" => "../app/compiled-templates/",
"compiledExtension" => ".compiled",
]
);
return $volt;
}
);
// Register Volt as template engine
$di->set(
"view",
function () {
$view = new View();
$view->setViewsDir("../app/views/");
$view->registerEngines(
[
".volt" => "voltService",
]
);
return $view;
}
);
Используйте стандартное расширение ".phtml":
$view->registerEngines(
[
".phtml" => "voltService",
]
);
Вам не нужно указывать службу Volt в DI; вы также можете использовать движок Volt с настройками по умолчанию:
$view->registerEngines(
[
".volt" => "Phalcon\\Mvc\\View\\Engine\\Volt",
]
);
Если вы не хотите повторно использовать Volt в качестве службы, вы можете передать анонимную функцию для регистрации движка вместо имени службы:
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Volt;
// Register Volt as template engine with an anonymous function
$di->set(
"view",
function () {
$view = new \Phalcon\Mvc\View();
$view->setViewsDir("../app/views/");
$view->registerEngines(
[
".volt" => function ($view, $di) {
$volt = new Volt($view, $di);
// Set some options here
return $volt;
}
]
);
return $view;
}
);
Доступны следующие параметры в Volt:
| Параметр | Описание | Значение по умолчанию |
|---|---|---|
compiledPath | Путь для записи, куда будут помещены скомпилированные PHP-шаблоны | ./ |
compiledExtension | Дополнительное расширение, добавляемое к скомпилированному PHP-файлу | .php |
compiledSeparator | Volt заменяет разделители каталогов / и \ на этот разделитель для создания одного файла в каталоге скомпилированных файлов | %% |
stat | Нужно ли Phalcon проверять, есть ли различия между файлом шаблона и его скомпилированным путём | true |
compileAlways | Указать Volt, нужно ли компилировать шаблоны в каждом запросе или только при их изменении | false |
prefix | Позволяет добавить префикс к шаблонам в пути компиляции | null |
autoescape | Включает глобальную автоматическую обработку HTML | false |
Путь компиляции генерируется в соответствии с вышеуказанными параметрами. Если разработчик хочет полную свободу определения пути компиляции, можно использовать анонимную функцию, которая получает относительный путь к шаблону в каталоге представлений. Следующие примеры показывают, как динамически изменить путь компиляции:
// Just append the .php extension to the template path
// leaving the compiled templates in the same directory
$volt->setOptions(
[
"compiledPath" => function ($templatePath) {
return $templatePath . ".php";
}
]
);
// Recursively create the same structure in another directory
$volt->setOptions(
[
"compiledPath" => function ($templatePath) {
$dirName = dirname($templatePath);
if (!is_dir("cache/" . $dirName)) {
mkdir("cache/" . $dirName);
}
return "cache/" . $dirName . "/". $templatePath . ".php";
}
]
);
Базовое использование
Представление состоит из кода Volt, PHP и HTML. Доступен набор специальных разделителей для входа в режим Volt. {% ... %} используется для выполнения инструкций, таких как циклы for или присвоение значений, а {{ ... }}, выводит результат выражения в шаблон.
Ниже приведен минимальный шаблон, который иллюстрирует несколько основ:
{# app/views/posts/show.phtml #}
<!DOCTYPE html>
<html>
<head>
<title>{{ title }} - An example blog</title>
</head>
<body>
{% if show_navigation %}
<ul id="navigation">
{% for item in menu %}
<li>
<a href="{{ item.href }}">
{{ item.caption }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}
<h1>{{ post.title }}</h1>
<div class="content">
{{ post.content }}
</div>
</body>
</html>
Используя Phalcon\Mvc\View, вы можете передавать переменные из контроллера в представления. В приведенном выше примере в представление были переданы четыре переменные: show_navigation, menu, title и post.
use Phalcon\Mvc\Controller;
class PostsController extends Controller
{
public function showAction()
{
$post = Post::findFirst();
$menu = Menu::findFirst();
$this->view->show_navigation = true;
$this->view->menu = $menu;
$this->view->title = $post->title;
$this->view->post = $post;
// Or...
$this->view->setVar("show_navigation", true);
$this->view->setVar("menu", $menu);
$this->view->setVar("title", $post->title);
$this->view->setVar("post", $post);
}
}
Переменные
Переменные-объекты могут иметь атрибуты, к которым можно получить доступ, используя синтаксис: foo.bar. Если вы передаёте массивы, необходимо использовать квадратный синтаксис: foo['bar'].
{{ post.title }} {# for $post->title #}
{{ post['title'] }} {# for $post['title'] #}
Фильтры
Переменные могут быть отформатированы или изменены с помощью фильтров. Оператор «|» | используется для применения фильтров к переменным:
{{ post.title|e }}
{{ post.content|striptags }}
{{ name|capitalize|trim }}
Ниже приведён список доступных встроенных фильтров в Volt:
| Фильтр | Описание |
|---|---|
e | Применяет Phalcon\Escaper->escapeHtml() к значению |
escape | Применяет Phalcon\Escaper->escapeHtml() к значению |
escape_css | Применяет Phalcon\Escaper->escapeCss() к значению |
escape_js | Применяет Phalcon\Escaper->escapeJs() к значению |
escape_attr | Применяет Phalcon\Escaper->escapeHtmlAttr() к значению |
trim | Применяет функцию PHP trim к значению. Удаляет лишние пробелы |
left_trim | Применяет функцию PHP ltrim к значению. Удаляет лишние пробелы |
right_trim | Применяет функцию PHP rtrim к значению. Удаляет лишние пробелы |
striptags | Применяет функцию PHP striptags к значению. Удаляет теги HTML |
slashes | Применяет функцию PHP slashes к значению. Экранирует значения |
stripslashes | Применяет функцию PHP stripslashes к значению. Удаляет экранированные кавычки |
capitalize | Приводит строку к верхнему регистру, применяя функцию PHP ucwords к значению |
lower | Преобразует строку к нижнему регистру |
upper | Преобразует строку к верхнему регистру |
length | Подсчитывает длину строки или количество элементов в массиве или объекте |
nl2br | Заменяет символы новой строки \n на разрывы строк (<br />). Использует функцию PHP nl2br |
sort | Сортирует массив, используя функцию PHP asort |
keys | Возвращает ключи массива с помощью array_keys |
join | Объединяет части массива с помощью разделителя join |
format | Форматирует строку с помощью sprintf |
json_encode | Преобразует значение в его представление JSON |
json_decode | Преобразует значение из его представления JSON в представление PHP |
abs | Применяет функцию PHP abs к значению |
url_encode | Применяет функцию PHP urlencode к значению |
default | Устанавливает значение по умолчанию в случае, если вычисленное выражение пустое (не задано или вычисляется до ложного значения) |
convert_encoding | Преобразует строку из одного набора символов в другой |
Примеры:
{# e or escape filter #}
{{ "<h1>Hello<h1>"|e }}
{{ "<h1>Hello<h1>"|escape }}
{# trim filter #}
{{ " hello "|trim }}
{# striptags filter #}
{{ "<h1>Hello<h1>"|striptags }}
{# slashes filter #}
{{ "'this is a string'"|slashes }}
{# stripslashes filter #}
{{ "\'this is a string\'"|stripslashes }}
{# capitalize filter #}
{{ "hello"|capitalize }}
{# lower filter #}
{{ "HELLO"|lower }}
{# upper filter #}
{{ "hello"|upper }}
{# length filter #}
{{ "robots"|length }}
{{ [1, 2, 3]|length }}
{# nl2br filter #}
{{ "some\ntext"|nl2br }}
{# sort filter #}
{% set sorted = [3, 1, 2]|sort %}
{# keys filter #}
{% set keys = ['first': 1, 'second': 2, 'third': 3]|keys %}
{# join filter #}
{% set joined = "a".."z"|join(",") %}
{# format filter #}
{{ "My real name is %s"|format(name) }}
{# json_encode filter #}
{% set encoded = robots|json_encode %}
{# json_decode filter #}
{% set decoded = '{"one":1,"two":2,"three":3}'|json_decode %}
{# url_encode filter #}
{{ post.permanent_link|url_encode }}
{# convert_encoding filter #}
{{ "désolé"|convert_encoding('utf8', 'latin1') }}
Комментарии
Комментарии также можно добавлять в шаблон, используя разделители {# ... #}. Весь текст внутри них просто игнорируется в конечном выводе:
{# note: this is a comment
{% set price = 100; %}
#}
Список управляющих структур
Volt предоставляет набор основных, но мощных управляющих структур для использования в шаблонах:
For
Перебирает каждый элемент в последовательности. Следующий пример демонстрирует, как пройти по набору «роботов» и напечатать его имя:
<h1>Robots</h1>
<ul>
{% for robot in robots %}
<li>
{{ robot.name|e }}
</li>
{% endfor %}
</ul>
Циклы for также могут быть вложенными:
<h1>Robots</h1>
{% for robot in robots %}
{% for part in robot.parts %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }} <br />
{% endfor %}
{% endfor %}
Вы можете получить элементы «ключи», как в PHP, используя следующий синтаксис:
{% set numbers = ['one': 1, 'two': 2, 'three': 3] %}
{% for name, value in numbers %}
Name: {{ name }} Value: {{ value }}
{% endfor %}
Оценку «if» можно необязательно установить:
{% set numbers = ['one': 1, 'two': 2, 'three': 3] %}
{% for value in numbers if value < 2 %}
Value: {{ value }}
{% endfor %}
{% for name, value in numbers if name !== 'two' %}
Name: {{ name }} Value: {{ value }}
{% endfor %}
Если в ‘for’ определён ‘else’, он будет выполнен, если выражение в результате итератора даёт ноль итераций:
<h1>Robots</h1>
{% for robot in robots %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }} <br />
{% else %}
There are no robots to show
{% endfor %}
Альтернативный синтаксис:
<h1>Robots</h1>
{% for robot in robots %}
Robot: {{ robot.name|e }} Part: {{ part.name|e }} <br />
{% elsefor %}
There are no robots to show
{% endfor %}
Управление циклом
Инструкции ‘break’ и ‘continue’ могут использоваться для выхода из цикла или принудительной итерации в текущем блоке:
{# skip the even robots #}
{% for index, robot in robots %}
{% if index is even %}
{% continue %}
{% endif %}
...
{% endfor %}
{# exit the foreach on the first even robot #}
{% for index, robot in robots %}
{% if index is even %}
{% break %}
{% endif %}
...
{% endfor %}
If
Как и в PHP, оператор «if» проверяет, оценивается ли выражение как истинное или ложное:
<h1>Cyborg Robots</h1>
<ul>
{% for robot in robots %}
{% if robot.type === "cyborg" %}
<li>{{ robot.name|e }}</li>
{% endif %}
{% endfor %}
</ul>
Поддерживается и блок else:
<h1>Robots</h1>
<ul>
{% for robot in robots %}
{% if robot.type === "cyborg" %}
<li>{{ robot.name|e }}</li>
{% else %}
<li>{{ robot.name|e }} (not a cyborg)</li>
{% endif %}
{% endfor %}
</ul>
Управляющая структура ‘elseif’ может использоваться вместе с ‘if’ для эмуляции блока ‘switch’:
{% if robot.type === "cyborg" %}
Robot is a cyborg
{% elseif robot.type === "virtual" %}
Robot is virtual
{% elseif robot.type === "mechanical" %}
Robot is mechanical
{% endif %}
Контекст цикла
Внутри циклов ‘for’ доступна специальная переменная, предоставляющая информацию о
| Переменная | Описание |
|---|---|
loop.index | Текущая итерация цикла. (Индексирование с 1) |
loop.index0 | Текущая итерация цикла. (Индексирование с 0) |
loop.revindex | Количество итераций с конца цикла. (Индексирование с 1) |
loop.revindex0 | Количество итераций с конца цикла. (Индексирование с 0) |
loop.first | Истина, если это первая итерация. |
loop.last | Истина, если это последняя итерация. |
loop.length | Количество элементов для итерации |
{% for robot in robots %}
{% if loop.first %}
<table>
<tr>
<th>#</th>
<th>Id</th>
<th>Name</th>
</tr>
{% endif %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ robot.id }}</td>
<td>{{ robot.name }}</td>
</tr>
{% if loop.last %}
</table>
{% endif %}
{% endfor %}
Присваивания
Переменные могут быть изменены в шаблоне с помощью инструкции «set»:
{% set fruits = ['Apple', 'Banana', 'Orange'] %}
{% set name = robot.name %}
Несколько присваиваний разрешены в одной инструкции:
{% set fruits = ['Apple', 'Banana', 'Orange'], name = robot.name, active = true %}
Кроме того, вы можете использовать составные операторы присваивания:
{% set price += 100.00 %}
{% set age *= 5 %}
Доступны следующие операторы:
| Оператор | Описание |
|---|---|
| = | Стандартное присваивание |
| += | Присваивание с добавлением |
| -= | Присваивание с вычитанием |
| *= | Присваивание с умножением |
| /= | Присваивание с делением |
Выражения
Volt предоставляет базовый набор поддержки выражений, включая литералы и стандартные операторы.
Выражение может быть вычислено и выведено с помощью разделителей '{{‘ и ‘}}’:
{{ (1 + 1) * 2 }}
Если выражение нужно вычислить без вывода, можно использовать инструкцию ‘do’:
{% do (1 + 1) * 2 %}
Литералы
Поддерживаются следующие литералы:
| Фильтр | Описание |
|---|---|
| “это строка” | Текст в двойных или одинарных кавычках обрабатывается как строка |
| 100.25 | Числа с десятичной частью обрабатываются как числа с плавающей точкой (double/float) |
| 100 | Числа без десятичной части обрабатываются как целые числа |
| false | Константа “false” — значение булевого типа false |
| true | Константа “true” — значение булевого типа true |
| null | Константа “null” — значение Null |
Массивы
Используя PHP 5.3 или >= 5.4, вы можете создавать массивы, заключив список значений в квадратные скобки:
{# Simple array #}
{{ ['Apple', 'Banana', 'Orange'] }}
{# Other simple array #}
{{ ['Apple', 1, 2.5, false, null] }}
{# Multi-Dimensional array #}
{{ [[1, 2], [3, 4], [5, 6]] }}
{# Hash-style array #}
{{ ['first': 1, 'second': 4/2, 'third': '3'] }}
Для определения массивов или ассоциативных массивов также можно использовать фигурные скобки:
{% set myArray = {'Apple', 'Banana', 'Orange'} %}
{% set myHash = {'first': 1, 'second': 4/2, 'third': '3'} %}
Математика
Вы можете выполнять вычисления в шаблонах, используя следующие операторы:
| Оператор | Описание |
|---|---|
+ | Выполняет операцию сложения. {{ 2 + 3 }} возвращает 5 |
- | Выполняет операцию вычитания {{ 2 - 3 }} возвращает -1 |
* | Выполняет операцию умножения {{ 2 * 3 }} возвращает 6 |
/ | Выполняет операцию деления {{ 10 / 2 }} возвращает 5 |
% | Вычисляет остаток от целочисленного деления {{ 10 % 3 }} возвращает 1 |
Сравнения
Доступны следующие операторы сравнения:
| Оператор | Описание |
|---|---|
== | Проверяет, равны ли оба операнда |
!= | Проверяет, не равны ли оба операнда |
<> | Проверяет, не равны ли оба операнда |
> | Проверяет, больше ли левый операнд правого |
< | Проверяет, меньше ли левый операнд правого |
<= | Проверяет, меньше или равно ли левый операнд правому |
>= | Проверяет, больше или равно ли левый операнд правому |
=== | Проверяет, идентичны ли оба операнда |
!== | Проверяет, не идентичны ли оба операнда |
Логика
Логические операторы полезны в выражениях «if», чтобы комбинировать несколько проверок:
| Оператор | Описание |
|---|---|
or | Возвращает true, если левый или правый операнд имеет значение true |
and | Возвращает true, если оба левого и правого операнда имеют значение true |
not | Инвертирует выражение |
( expr ) | Группирует выражения в скобки |
Другие операторы
Доступны дополнительные операторы:
| Оператор | Описание |
|---|---|
~ | Конкатенирует оба операнда {{ "hello " ~ "world" }}
|
| | Применяет фильтр к правому операнду, используя левый {{ "hello"|uppercase }}
|
.. | Создаёт диапазон {{ 'a'..'z' }} {{ 1..10 }}
|
is | То же, что и == (равно), также выполняет проверки |
in | Проверяет, содержится ли выражение в других выражениях if "a" in "abc"
|
is not | То же, что и != (не равно) |
'a' ? 'b' : 'c' | Тернарный оператор. Аналогичен тернарному оператору PHP |
++ | Инкрементирует значение |
-- | Декрементирует значение |
Следующий пример демонстрирует использование операторов:
{% set robots = ['Voltron', 'Astro Boy', 'Terminator', 'C3PO'] %}
{% for index in 0..robots|length %}
{% if robots[index] is defined %}
{{ "Name: " ~ robots[index] }}
{% endif %}
{% endfor %}
Проверки
Проверки используются для проверки, имеет ли переменная ожидаемое значение. Оператор «is» используется для выполнения проверок:
{% set robots = ['1': 'Voltron', '2': 'Astro Boy', '3': 'Terminator', '4': 'C3PO'] %}
{% for position, name in robots %}
{% if position is odd %}
{{ name }}
{% endif %}
{% endfor %}
Доступны следующие встроенные проверки в Volt:
| Проверка | Описание |
|---|---|
defined | Проверяет, определена ли переменная (isset()) |
empty | Проверяет, пуста ли переменная |
even | Проверяет, является ли число чётным |
odd | Проверяет, является ли число нечётным |
numeric | Проверяет, является ли значение числовым |
scalar | Проверяет, является ли значение скалярным (не массивом или объектом) |
iterable | Проверяет, является ли значение итерируемым. Может быть пройдено циклом «for» |
divisibleby | Проверяет, делится ли значение на другое значение |
sameas | Проверяет, идентично ли значение другому значению |
type | Проверяет, является ли значение указанного типа |
Дополнительные примеры:
{% if robot is defined %}
The robot variable is defined
{% endif %}
{% if robot is empty %}
The robot is null or isn't defined
{% endif %}
{% for key, name in [1: 'Voltron', 2: 'Astroy Boy', 3: 'Bender'] %}
{% if key is even %}
{{ name }}
{% endif %}
{% endfor %}
{% for key, name in [1: 'Voltron', 2: 'Astroy Boy', 3: 'Bender'] %}
{% if key is odd %}
{{ name }}
{% endif %}
{% endfor %}
{% for key, name in [1: 'Voltron', 2: 'Astroy Boy', 'third': 'Bender'] %}
{% if key is numeric %}
{{ name }}
{% endif %}
{% endfor %}
{% set robots = [1: 'Voltron', 2: 'Astroy Boy'] %}
{% if robots is iterable %}
{% for robot in robots %}
...
{% endfor %}
{% endif %}
{% set world = "hello" %}
{% if world is sameas("hello") %}
{{ "it's hello" }}
{% endif %}
{% set external = false %}
{% if external is type('boolean') %}
{{ "external is false or true" }}
{% endif %}
Макросы
Макросы могут использоваться для повторного использования логики в шаблоне, они работают как PHP функции, могут принимать параметры и возвращать значения:
{# Macro "display a list of links to related topics" #}
{%- macro related_bar(related_links) %}
<ul>
{%- for link in related_links %}
<li>
<a href="{{ url(link.url) }}" title="{{ link.title|striptags }}">
{{ link.text }}
</a>
</li>
{%- endfor %}
</ul>
{%- endmacro %}
{# Print related links #}
{{ related_bar(links) }}
<div>This is the content</div>
{# Print related links again #}
{{ related_bar(links) }}
При вызове макросов параметры могут передаваться по имени:
{%- macro error_messages(message, field, type) %}
<div>
<span class="error-type">{{ type }}</span>
<span class="error-field">{{ field }}</span>
<span class="error-message">{{ message }}</span>
</div>
{%- endmacro %}
{# Call the macro #}
{{ error_messages('type': 'Invalid', 'message': 'The name is invalid', 'field': 'name') }}
Макросы могут возвращать значения:
{%- macro my_input(name, class) %}
{% return text_field(name, 'class': class) %}
{%- endmacro %}
{# Call the macro #}
{{ '<p>' ~ my_input('name', 'input-text') ~ '</p>' }}
И принимать необязательные параметры:
{%- macro my_input(name, class="input-text") %}
{% return text_field(name, 'class': class) %}
{%- endmacro %}
{# Call the macro #}
{{ '<p>' ~ my_input('name') ~ '</p>' }}
{{ '<p>' ~ my_input('name', 'input-text') ~ '</p>' }}
Использование помощников тегов
Volt тесно интегрирован с Phalcon\Tag, поэтому использование помощников этого компонента в шаблонах Volt очень просто:
{{ javascript_include("js/jquery.js") }}
{{ form('products/save', 'method': 'post') }}
<label for="name">Name</label>
{{ text_field("name", "size": 32) }}
<label for="type">Type</label>
{{ select("type", productTypes, 'using': ['id', 'name']) }}
{{ submit_button('Send') }}
{{ end_form() }}
Генерируется следующий PHP:
<?php echo Phalcon\Tag::javascriptInclude("js/jquery.js") ?>
<?php echo Phalcon\Tag::form(array('products/save', 'method' => 'post')); ?>
<label for="name">Name</label>
<?php echo Phalcon\Tag::textField(array('name', 'size' => 32)); ?>
<label for="type">Type</label>
<?php echo Phalcon\Tag::select(array('type', $productTypes, 'using' => array('id', 'name'))); ?>
<?php echo Phalcon\Tag::submitButton('Send'); ?>
{{ end_form() }}
Для вызова помощника Phalcon\Tag достаточно вызвать его имя в нижнем регистре:
| Метод | Функция Volt |
|---|---|
Phalcon\Tag::linkTo | link_to |
Phalcon\Tag::textField | text_field |
Phalcon\Tag::passwordField | password_field |
Phalcon\Tag::hiddenField | hidden_field |
Phalcon\Tag::fileField | file_field |
Phalcon\Tag::checkField | check_field |
Phalcon\Tag::radioField | radio_field |
Phalcon\Tag::dateField | date_field |
Phalcon\Tag::emailField | email_field |
Phalcon\Tag::numericField | numeric_field |
Phalcon\Tag::submitButton | submit_button |
Phalcon\Tag::selectStatic | select_static |
Phalcon\Tag::select | select |
Phalcon\Tag::textArea | text_area |
Phalcon\Tag::form | form |
Phalcon\Tag::endForm | end_form |
Phalcon\Tag::getTitle | get_title |
Phalcon\Tag::stylesheetLink | stylesheet_link |
Phalcon\Tag::javascriptInclude | javascript_include |
Phalcon\Tag::image | image |
Phalcon\Tag::friendlyTitle | friendly_title |
Функции
Ниже приведены встроенные функции, доступные в Volt:
| Имя | Описание |
|---|---|
content | Включает содержимое, сгенерированное на предыдущей стадии рендеринга |
get_content | Аналогично content
|
partial | Динамически загружает частичный вид в текущем шаблоне |
super | Отображает содержимое родительского блока |
time | Вызывает функцию PHP с тем же именем |
date | Вызывает функцию PHP с тем же именем |
dump | Вызывает функцию PHP var_dump()
|
version | Возвращает текущую версию фреймворка |
constant | Читает константу PHP |
url | Генерирует URL с использованием сервиса ‘url’ |
Интеграция с представлениями
Также Volt интегрирован с Phalcon\Mvc\View, вы можете работать с иерархией представлений и включать частичные представления:
{{ content() }}
<!-- Simple include of a partial -->
<div id="footer">{{ partial("partials/footer") }}</div>
<!-- Passing extra variables -->
<div id="footer">{{ partial("partials/footer", ['links': links]) }}</div>
Частичное представление включается во время выполнения, Volt также предоставляет «include», это компилирует содержимое представления и возвращает его содержимое как часть включённого представления:
{# Simple include of a partial #}
<div id="footer">
{% include "partials/footer" %}
</div>
{# Passing extra variables #}
<div id="footer">
{% include "partials/footer" with ['links': links] %}
</div>
Включение
«include» имеет специальное поведение, которое поможет немного улучшить производительность при использовании Volt. Если вы указываете расширение при включении файла, и оно существует во время компиляции шаблона, Volt может встраивать содержимое шаблона в родительский шаблон, где оно включено. Шаблоны не встраиваются, если с включением переданы переменные с помощью «with»:
{# The contents of 'partials/footer.volt' is compiled and inlined #}
<div id="footer">
{% include "partials/footer.volt" %}
</div>
Частичное представление против включения
Учитывайте следующие моменты при выборе функции «partial» или «include»:
- «Partial» позволяет включать шаблоны, созданные в Volt и в других движках шаблонов
- «Partial» позволяет передавать выражение, например, переменную, что позволяет динамически включать содержимое других представлений
- «Partial» лучше, если содержимое, которое необходимо включить, часто изменяется
- «Include» копирует скомпилированное содержимое в представление, что улучшает производительность
- «Include» позволяет включать только шаблоны, созданные с помощью Volt
- «Include» требует наличия шаблона во время компиляции
Наследование шаблонов
С помощью наследования шаблонов вы можете создавать базовые шаблоны, которые могут быть расширены другими шаблонами, что позволяет повторно использовать код. Базовый шаблон определяет блоки, которые могут быть переопределены дочерним шаблоном. Предположим, у нас есть следующий базовый шаблон:
{# templates/base.volt #}
<!DOCTYPE html>
<html>
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
{% endblock %}
<title>{% block title %}{% endblock %} - My Webpage</title>
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}© Copyright 2015, All rights reserved.{% endblock %}
</div>
</body>
</html>
Из другого шаблона мы можем расширить базовый шаблон, заменяя блоки:
{% extends "templates/base.volt" %}
{% block title %}Index{% endblock %}
{% block head %}<style type="text/css">.important { color: #336699; }</style>{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important">Welcome on my awesome homepage.</p>
{% endblock %}
Не все блоки должны быть заменены в дочернем шаблоне, только необходимые. Конечный вывод будет следующим:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">.important { color: #336699; }</style>
<title>Index - My Webpage</title>
</head>
<body>
<div id="content">
<h1>Index</h1>
<p class="important">Welcome on my awesome homepage.</p>
</div>
<div id="footer">
© Copyright 2015, All rights reserved.
</div>
</body>
</html>
Многократное наследование
Расширенные шаблоны могут расширять другие шаблоны. Следующий пример иллюстрирует это:
{# main.volt #}
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
Шаблон «layout.volt» расширяет «main.volt»
{# layout.volt #}
{% extends "main.volt" %}
{% block content %}
<h1>Table of contents</h1>
{% endblock %}
Наконец, представление, которое расширяет «layout.volt»:
{# index.volt #}
{% extends "layout.volt" %}
{% block content %}
{{ super() }}
<ul>
<li>Some option</li>
<li>Some other option</li>
</ul>
{% endblock %}
Рендеринг «index.volt» даёт:
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Table of contents</h1>
<ul>
<li>Some option</li>
<li>Some other option</li>
</ul>
</body>
</html>
Обратите внимание на вызов функции super(). С помощью этой функции можно отобразить содержимое родительского блока.
Как и в частичных представлениях, путь, установленный для «extends», — это относительный путь внутри текущей директории представлений (т.е. app/views/).
По умолчанию и по причинам производительности, Volt проверяет только изменения в дочерних шаблонах, чтобы знать, когда необходимо перекомпилировать в обычный PHP код, поэтому рекомендуется инициализировать Volt с опцией'compileAlways' => true. Таким образом, шаблоны всегда компилируются с учётом изменений в родительских шаблонах.
Режим автозамены
Вы можете включить автоматическую замену всех переменных, выводимых в блоке, используя режим autoescape:
Manually escaped: {{ robot.name|e }}
{% autoescape true %}
Autoescaped: {{ robot.name }}
{% autoescape false %}
No Autoescaped: {{ robot.name }}
{% endautoescape %}
{% endautoescape %}
Расширение Volt
В отличие от других движков шаблонов, сам Volt не требуется для выполнения скомпилированных шаблонов. После компиляции шаблонов нет зависимости от Volt. С учётом независимости от производительности, Volt выступает только как компилятор для PHP-шаблонов.
Компилятор Volt позволяет расширять его, добавляя новые функции, проверки или фильтры к существующим.
Функции
Функции действуют как обычные PHP функции, требуется допустимое имя строки в качестве имени функции. Функции можно добавлять с помощью двух стратегий: возвращая простую строку или используя анонимную функцию. Всегда необходимо, чтобы выбранная стратегия возвращала допустимое PHP выражение:
use Phalcon\Mvc\View\Engine\Volt;
$volt = new Volt($view, $di);
$compiler = $volt->getCompiler();
// This binds the function name 'shuffle' in Volt to the PHP function 'str_shuffle'
$compiler->addFunction("shuffle", "str_shuffle");
Зарегистрируйте функцию с помощью анонимной функции. В этом случае используется $resolvedArgs для передачи аргументов точно так же, как они были переданы в аргументах:
$compiler->addFunction(
"widget",
function ($resolvedArgs, $exprArgs) {
return "MyLibrary\\Widgets::get(" . $resolvedArgs . ")";
}
);
Обращайтесь с аргументами независимо и неразобранными:
$compiler->addFunction(
"repeat",
function ($resolvedArgs, $exprArgs) use ($compiler) {
// Resolve the first argument
$firstArgument = $compiler->expression($exprArgs[0]['expr']);
// Checks if the second argument was passed
if (isset($exprArgs[1])) {
$secondArgument = $compiler->expression($exprArgs[1]['expr']);
} else {
// Use '10' as default
$secondArgument = '10';
}
return "str_repeat(" . $firstArgument . ", " . $secondArgument . ")";
}
);
Генерируйте код на основе доступности некоторых функций:
$compiler->addFunction(
"contains_text",
function ($resolvedArgs, $exprArgs) {
if (function_exists("mb_stripos")) {
return "mb_stripos(" . $resolvedArgs . ")";
} else {
return "stripos(" . $resolvedArgs . ")";
}
}
);
Встроенные функции можно переопределить, добавив функцию с её именем:
// Replace built-in function dump
$compiler->addFunction("dump", "print_r");
Фильтры
Фильтр имеет следующий вид в шаблоне: leftExpr|name(optional-args). Добавление новых фильтров аналогично тому, как это делается с функциями:
// This creates a filter 'hash' that uses the PHP function 'md5'
$compiler->addFilter("hash", "md5");
$compiler->addFilter(
"int",
function ($resolvedArgs, $exprArgs) {
return "intval(" . $resolvedArgs . ")";
}
);
Встроенные фильтры можно переопределить, добавив функцию с её именем:
// Replace built-in filter 'capitalize'
$compiler->addFilter("capitalize", "lcfirst");
Расширения
С расширениями разработчик имеет больше гибкости для расширения движка шаблонов и переопределения компиляции определённой инструкции, изменения поведения выражения или оператора, добавления функций/фильтров и многое другое.
Расширение — это класс, который реализует события, срабатывающие в Volt, как метод самого класса.
Например, класс ниже позволяет использовать любые PHP функции в Volt:
class PhpFunctionExtension
{
/**
* This method is called on any attempt to compile a function call
*/
public function compileFunction($name, $arguments)
{
if (function_exists($name)) {
return $name . "(". $arguments . ")";
}
}
}
Вышеприведённый класс реализует метод «compileFunction», который вызывается перед любой попыткой скомпилировать вызов функции в любом шаблоне. Цель расширения — проверить, является ли функция, подлежащая компиляции, PHP-функцией, позволяя вызывать её из шаблона. События в расширениях должны возвращать допустимый PHP код, который будет использоваться в качестве результата компиляции вместо сгенерированного Volt. Если событие не возвращает строку, компиляция выполняется с помощью поведения по умолчанию, предоставляемого движком.
Доступны следующие события компиляции для реализации в расширениях:
| Событие/Метод | Описание |
|---|---|
compileFunction | Срабатывает перед попыткой скомпилировать любой вызов функции в шаблоне |
compileFilter | Срабатывает перед попыткой скомпилировать любой вызов фильтра в шаблоне |
resolveExpression | Срабатывает перед попыткой скомпилировать любое выражение. Это позволяет разработчику переопределить операторы |
compileStatement | Срабатывает перед попыткой скомпилировать любое выражение. Это позволяет разработчику переопределить любое утверждение |
Расширения Volt должны быть зарегистрированы в компиляторе, что делает их доступными во время компиляции:
// Register the extension in the compiler
$compiler->addExtension(
new PhpFunctionExtension()
);
Кэширование фрагментов представлений
С Volt легко кэшировать фрагменты представлений. Этот кэширование улучшает производительность, предотвращая выполнение содержимого блока PHP каждый раз при отображении представления:
{% cache "sidebar" %}
<!-- generate this content is slow so we are going to cache it -->
{% endcache %}
Установление определённого количества секунд:
{# cache the sidebar by 1 hour #}
{% cache "sidebar" 3600 %}
<!-- generate this content is slow so we are going to cache it -->
{% endcache %}
В качестве ключа кэша может быть использовано любое допустимое выражение:
{% cache ("article-" ~ post.id) 3600 %}
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
{% endcache %}
Кэширование выполняется компонентом Phalcon\Cache через компонент представления. Подробнее об этой интеграции можно узнать в разделе «Кэширование фрагментов представлений».
Ввод сервисов в шаблон
Если для Volt доступен контейнер сервисов (DI), вы можете использовать сервисы, обращаясь только к имени сервиса в шаблоне:
{# Inject the 'flash' service #}
<div id="messages">{{ flash.output() }}</div>
{# Inject the 'security' service #}
<input type="hidden" name="token" value="{{ security.getToken() }}">
Компонент автономного использования
Использование Volt в автономном режиме можно продемонстрировать ниже:
use Phalcon\Mvc\View\Engine\Volt\Compiler as VoltCompiler;
// Create a compiler
$compiler = new VoltCompiler();
// Optionally add some options
$compiler->setOptions(
[
// ...
]
);
// Compile a template string returning PHP code
echo $compiler->compileString(
"{{ 'hello' }}"
);
// Compile a template in a file specifying the destination file
$compiler->compileFile(
"layouts/main.volt",
"cache/layouts/main.volt.php"
);
// Compile a template in a file based on the options passed to the compiler
$compiler->compile(
"layouts/main.volt"
);
// Require the compiled templated (optional)
require $compiler->getCompiledTemplatePath();
Внешние ресурсы
- Пакет для Sublime/Textmate доступен здесь
- Album-O-Rama — это демонстрационное приложение, использующее Volt в качестве шаблонизатора, [Album-O-Rama на Github]
- Наш сайт использует Volt в качестве шаблонизатора, [Наш сайт на Github]
- Форум Phalcon также использует Volt, [Форум на Github]
- Vökuró — еще одно демонстрационное приложение, использующее Volt, [Vökuró на Github]
© 2011–2017 Phalcon Framework Team
Licensed under the Creative Commons Attribution License 3.0.
https://docs.phalconphp.com/en/latest/reference/volt.html