Spec-Zone.ru › Phalcon 3

Volt: Шаблонный движок

Volt — это сверхбыстрый и удобный для дизайнеров шаблонный язык, написанный на C для PHP. Он предоставляет набор помощников для написания представлений простым способом. Volt тесно интегрирован с другими компонентами Phalcon, а также может использоваться как самостоятельный компонент в ваших приложениях.

../_images/volt.jpg

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 %}&copy; 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">
            &copy; 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API