Документация

Шаблонизатор Separate
Версия 1.6 (03.03.2018, PHP7)

Что такое Separate?

Separate - это объектно-ориентированный шаблонизатор для PHP7. С помощью Separate можно отделить бизнес-логику (например, загрузку информации из базы данных) от уровня представления (HTML кода) и тем самым создать чистый и хорошо структурированный исходный код.
 

Архитектура шаблонизатора Separate

Основные свойства архитектуры

В процессе разработки большое значение уделялось динамическому расширению функции, как, например, форматированию значений с использованием Value Formatter. В целом, в архитектуру были интегрированы следующие свойства:
  • Минимальные функциональные ограничения (возможность расширения посредством собственной функциональности).
  • Простой API (например, для использования требуется только Template.php файл).
  • Независимость от других библиотек (например, Pear).

Структура приложения на базе Separate

Приложения, которые основаны на Separate, состоят из уровня представления (Presentation Layer) и бизнес-логики. Уровень представления содержит HTML код, переменные шаблона и другие конструкты шаблонизатора Separate. В бизнес-логике осуществляются различные вычисления, а затем сгенерированные данные передаются соответствующим переменным шаблона.
 

 
Верхний рисунок изображает бизнес-логику и уровень представления (Presentation Layer), которые обрабатываются шаблонизатором Separate. В качестве конечного результата шаблонизатор генерирует HTML код.
 

Интеграция в собственный проект

Для Separate требуется PHP7 или выше. Чтобы использовать Separate, нужно подключить Template класс.
require_once './Template.php';

Затем нужно загрузить файл шаблона. Для этого используется метод \separate\Template::initialize('...') .
$t = \separate\Template::initialize('./index.htm');

После успешной загрузки могут выполняться основные действия, как, например, присваивание значений к переменным шаблона.
$t->assign('MY_VARIABLE', 'my value');

Чтобы в завершении сгенерировать HTML код, используется метод \separate\Template::display().
\separate\Template::display();

Следующий код содержит все выше описанные шаги имплементации.
<?php

require_once './Template.php';

$t = \separate\Template::initialize('./index.htm');
$t->assign('MY_VARIABLE', 'my value');
\separate\Template::display();

Переменные шаблона

Для каждой динамической информационной единицы в шаблоне указывается переменная. В процессе генерации страницы шаблонизатор заменяет эти переменные информацией. Синтаксис выглядит следующим образом:
${<название переменной>}

Динамические блоки

Динамическими блоками вы можете разделить исходный код на разделы, которые во время выполнения могут повторяться любое количество раз. Данная возможность предназначена, например, для генерации таблицы с динамическим количеством строк. Синтаксис выглядит следующим образом:
<!-- BEGIN <название блока> -->
    HTML код...
<!-- END <название блока> -->

В PHP коде каждый блок является Template объектом. Методом Template->fetch(...) создается новый блок. После манипуляции блок передается методом Template->assign(...) обратно исходному Template объекту. В зависимости от количества данных этот процесс необходимо повторить определенное количество раз.
 
Ниже приведенный пример демонстрирует простую реализацию динамических блоков.

PHP код:
<?php

require_once './Template.php';

$rootTemplate = \separate\Template::initialize('./index.htm');

for($row = 1; $row <= 3; $row++)
{
    //fetch row block from root template
    $rowBlock = $rootTemplate->fetch('row');
    
    for($column = 1; $column <= 3; $column++)
    {
        //fetch column block from row block
        $columnBlock = $rowBlock->fetch('column');
        
        $columnBlock->assign('ROW_NUMBER', $row);
        $columnBlock->assign('COLUMN_NUMBER', $column);
        
        //assign modified column block back to row block
        $rowBlock->assign('column', $columnBlock);
    }
    
    //assign modified row block back to root template
    $rootTemplate->assign('row', $rowBlock);
}

\separate\Template::display();

?>

Исходный код шаблона (index.htm):
<html>
    <body>
        <table>
            <!-- BEGIN row -->
                <tr>
                    <!-- BEGIN column -->
                        <td>Row: ${ROW_NUMBER} Column: ${COLUMN_NUMBER}</td>
                    <!-- END column -->
                </tr>
            <!-- END row -->
        </table>
    </body>
</html>

Как вы видите, в блоках могут также определяться дальнейшие под-блоки. Сгенерированный HTML код выглядит следующим образом:
<html>
    <body>
        <table>
            <tr>
                <td>Row: 1 Column: 1</td>
                <td>Row: 1 Column: 2</td>
                <td>Row: 1 Column: 3</td>
            </tr>
            <tr>
                <td>Row: 2 Column: 1</td>
                <td>Row: 2 Column: 2</td>
                <td>Row: 2 Column: 3</td>
            </tr>
            <tr>
                <td>Row: 3 Column: 1</td>
                <td>Row: 3 Column: 2</td>
                <td>Row: 3 Column: 3</td>
            </tr>
        </table>
    </body>
</html>

Присвоение значений

Чтобы присвоить шаблонным переменным значения, в PHP коде используются определенные методы. Существуют три вида таких методов:
 

1. Простое присвоение значений

Видимость значений, которые были присвоены методом Template->assign(...), ограничивается текущим блоком или корневым уровнем шаблона. Переменные, которые находятся в других блоках, при этом игнорируются.
$t->assign('MY_VARIABLE', 'my value');

2. Блок-релевантное присвоение значений

Этим методом можно присвоить значение к переменной, которая находится в определенном блоке (включая дальнейшие под-блоки). Переменные, находящиеся в других блоках, игнорируются.
$t->assignForBlock('MY_BLOCK_VARIABLE', 'my block value');

3. Глобальное присвоение значений

С методом Template->assignForGlobal(...) можно присвоить значения ко всем переменным, независимо от того, в каком блоке они находятся. Использование данного метода имеет смысл в основном только для тех переменных, которые часто встречаются в разных областях исходного кода.
$t->assignForGlobal('MY_GLOBAL_VARIABLE', 'my global value');

Форматирование значений

По умолчанию все значения, которые были присвоены переменным шаблона, представляются в HTML коде без изменений. Но иногда бывают ситуации, когда необходимо изменить значение. Например, если на странице представлен текст, содержащий управляющие символы HTML (<, >, &, ...). Эти символы необходимо конвертировать при генерировании страницы. Чтобы сделать весь процесс максимально удобным и динамичным, Separate поддерживает так называемые Value Formatter.
 
Value Formatter содержит определенные инструкции для форматирования информации. Значения, которые передаются переменной с использованием Value Formatter, отображаются в конвертированном виде. Синтаксис переменной с Value Formatter выглядит следующим образом:
${(<название форматера>)<название переменной>}

Следующий пример показывает реализацию простого форматирования с использованием Value Formatter, которое конвертирует Unix Timestamp значение в читабельное обозначение даты или времени.
 
PHP код:
<?php

require_once './Template.php';
require_once './formatter/DateFormatter.php';
require_once './formatter/TimeFormatter.php';

$t = \separate\Template::initialize('./index.htm');
$t->assign('UNIX_TIMESTAMP', time());
\separate\Template::display();

?>

Исходныи код шаблона (index.htm):
<html>
    <body>
        Timestamp: ${UNIX_TIMESTAMP}<br>
        Date: ${(Date)UNIX_TIMESTAMP}<br>
        Time: ${(Time)UNIX_TIMESTAMP}
    </body>
</html>

Сгенерированный HTML код выглядит следующим образом:
<html>
    <body>
        Timestamp: 1520104433<br>
        Date: 03.03.2018<br>
        Time: 19:13
    </body>
</html>

Форматирование значений по умолчанию

С помощью метода Template::setDefaultFormatter(...) можно установить Value Formatter, который будет по умолчанию применяться во всех переменных шаблона.
\separate\Template::setDefaultFormatter(new TextFormatter());

Уже существующие Value Formatter классы

В Separate уже включенo несколько Value Formatter классов.
 
Класс Название форматера Описание
DateFormatter Date Конвертирует Unix Timestamp в читабельную дату, например, 03.03.2018
TimeFormatter Time Конвертирует Unix Timestamp в читабельное обозначение времени, например, 19:13
DateTimeFormatter DateTime Конвертирует Unix Timestamp в читабельную дату с дополнительным обозначением времени, например, 03.03.2018 19:13
TextFormatter Text Заменяет все управляющие символы HTML (например, <, > или &) предусмотренными для этого символами (например, &lt;, &gt; или &amp;).
UrlFormatter Url Создает URL-совместимую строку, которая в первую очередь предназначена для гиперссылок.
HashFormatter Hash Используется в IF-условии для сравнения двух неизвестных строк.
IsEmptyFormatter IsEmpty Используется в IF-условии для того, чтобы проверить, является ли переменная пустой.

Собственные Value Formatter классы

Наряду с уже существующими Value Formatter классами можно также создавать собственные. Для этого необходимо создать класс который наследует от класса \separate\ValueFormatter и имплементирует \separate\ValueFormatter->formatValue(...) метод.
 
При наименовании собственного Value Formatter класса нужно придерживаться определенным правилам нотации. Название класса начинается с названия форматера, который используется с переменными, и всегда заканчивается словом "Formatter".
<название форматера>Formatter

Следующий пример с собственным Value Formatter классом конвертирует переданное значение в верхний регистр.
 
PHP код:
<?php

require_once './Template.php';

class ToUpperFormatter extends \separate\ValueFormatter
{
    public function formatValue(string $value) : string
    {
        return strtoupper($value);
    }
}


$t = \separate\Template::initialize('./index.htm');
$t->assign('MY_VARIABLE', 'my value');
\separate\Template::display();

?>

Код шаблона (index.htm):
<html>
    <body>
        ${(ToUpper)MY_VARIABLE}
    </body>
</html>

Сгенерированный HTML код выглядит следующим образом:
<html>
    <body>
        MY VALUE
    </body>
</html>

Переменные без возможности форматирования

Иногда важно чтобы HTML код генерировался с максимально возможной скоростью. Для этого требования существует специальный вид переменных, которые в процессе генерации обрабатываются очень быстро, но не поддерживают форматирование значений.
 
В коде шаблона переменные такого рода начинаются с символа #:
#{<название переменной>}

В PHP коде для этого должны использоваться специальные Assign-методы. Эти методы идентичны с обычными Assign-методами, но начинаются с символа х.
$t->xassign('MY_VARIABLE', 'my value');
$t->xassignForBlock('MY_BLOCK_VARIABLE', 'my block value');
$t->xassignForGlobal('MY_GLOBAL_VARIABLE', 'my global value');

Интеграция дополнительных файлов в шаблон

В основной шаблонный код можно интегрировать код из других файлов.
 
Синтаксис команды:
<!-- INCLUDE <название файла> -->

Следующий пример показывает реализацию интеграции дополнительных файлов в шаблон.
 
Header-файл (header.htm):
<html>
    <body>

Footer-файл (footer.htm):
    </body>
</html>

Код основного шаблона (index.htm):
<!-- INCLUDE header.htm -->
    <p>Hallo</p>
<!-- INCLUDE footer.htm -->

IF-условия

Иногда требуется расположить IF-условия на уровне представления. В Separate это возможно. Синтаксис выглядит следующим образом:
<!-- IF <условие 1> -->
    HTML код...
<!-- ELSE IF <условие 2> -->
    HTML код...
<!-- ELSE -->
    HTML код...
<!-- END IF -->

Условие может состоять из нескольких переменных. Также можно использовать все операторы сравнения доступные в PHP. Далее иллюстрируется простая реализация IF-условия.
 
PHP код:
<?php

require_once './Template.php';

$t = \separate\Template::initialize('./index.htm');
$t->assign('MY_VARIABLE', 'hallo');
\separate\Template::display();

?>

Код шаблона (index.htm):
<html>
    <body>
        <!-- IF '${MY_VARIABLE}' == 'hallo' -->
            The value of MY_VARIABLE is 'hallo'
        <!-- ELSE -->
            The value of MY_VARIABLE is '${MY_VARIABLE}'
        <!-- END IF -->
    </body>
</html>

Особенности сравнения значений

Для обеспечения максимальной скорости, шаблонизатором не осуществляются определенные проверки значений. Поэтому разработчику необходимо самостоятельно обращать внимание на некоторые особенности.
 
Чтобы сравнить два неизвестныx значения, нужно использовать Hash-форматер, который преобразует значения в хеш-строки.
<!-- IF '${(Hash)MY_VARIABLE_A}' == '${(Hash)MY_VARIABLE_B}' -->
    ...
<!-- END IF -->

Чтобы проверить, содержит ли переменная пустую строку, нужно использовать IsEmpty форматер. Если переменная содержит пустую строку, значение конвертируется в "TRUE". В противном случае значение конвертируется в "FALSE".
<!-- IF '${(IsEmpty)MY_VARIABLE}' == 'TRUE' -->
    ...
<!-- END IF -->

Чтобы упростить логические сравнения, можно воспользоваться методом \separate\Template::booleanToString(...). Он преобразует логическое значение в строковое "TRUE" или "FALSE".
 
PHP код:
$t->xassign('LOGGED_IN_FLAG', \separate\Template::booleanToString(...));

Код шаблона:
<!-- IF '#{LOGGED_IN_FLAG}' == 'TRUE' -->
    ...
<!-- END IF -->

Параметры шаблона

С помощью параметров шаблона можно установить любые настройки в самом коде шаблона. Эти параметры потом доступны в PHP коде. Для чего это нужно? Вот пример из практики:
 
Иногда веб-приложения имеют несколько интерфейсов. Например, когда наряду с обычным интерфейсом также предоставляется интерфейс для мобильных устройств. В таком случае для одной и той же бизнес-логики разрабатываются два различных шаблона – один для стандартного интерфейса, другой– для мобильных устройств. Предположим, что у нас есть динамически сгенерированная таблица с множеством данных, которые в свою очередь распределены по многим страницам. В стандартном интерфейсе на каждой странице будут показываться 100 строк. В интерфейсе для мобильных устройств на странице можно показать максимально 10 строк записи, большее количество там просто не поместится. Чтобы реализовать это, не прибегая к каким-либо изменениям в PHP коде, и разработаны так называемые параметры шаблона.
 
Синтаксис:
<!-- PARAMETER <название параметра> '<значение параметра>' -->

Пример:
<!-- PARAMETER NUMBER_OF_ROWS '100' -->

В PHP коде все доступные параметры можно прочитать методом Template::getParameters(). Кроме того, методом Template::setParameterValue(...) во время выполнения можно установить новые параметры или поменять уже существующие.
 

Комментарии в шаблоне

Всем известно, что в HTML есть комментарии, которые выглядят следующим образом:
<!-- HTML комментарий... -->

У таких комментариев существует два недостатка: во-первых, они отсылаются клиенту и создают ненужный трафик. Во-вторых, эти комментарии видны в HTML коде. По этой причине Separate позволяет создавать специальные комментарии в шаблоне. Эти комментарии удаляются в сгенерированном HTML коде, и поэтому не передаются клиенту.
 
Синтаксис выглядит следующим образом:
<!--- Шаблонный комментарий... --->

Рекомендации

Наименование многих компонентов исходного кода предоставляется самому программисту. Тем не менее, рекомендуется использовать заранее постановленные правила.
 

Наименование Template переменных в PHP коде

Рекомендуется сохранять все Template объекты в одном массиве (например, $t). Название блока при этом просто передается в виде ключа. В нижеприведенном примере $t['.'] содержит корневой Template объект, а $t['block']['.'] и $t['block']['sub_block']['.'] соответствующие Template объекты блоков.
$t['.'] = \separate\Template::initialize('./index.htm');

for(...)
{
    $t['block']['.'] = $t['.']->fetch('block');
    
    for(...)
    {
        $t['block']['sub_block']['.'] = $t['block']['.']->fetch('sub_block');
        
        //...
        
        $t['block']['.']->assign('sub_block', $t['block']['sub_block']['.']);
    }
    
    $t['.']->assign('block', $t['block']['.']);
}

\separate\Template::display();

Наименование переменных шаблона в больших проектах

В больших проектах может случиться так, что у одного названия переменной существует несколько специальных значений. Например, в многоязычном приложении переменная NAME может использоваться как для имени пользователя (например, "Вася Пупкин") так и для языковых фраз (например, "Имя"). Чтобы избежать таких конфликтов, рекомендуется определить префикс для каждой смысловой области.
#{LANGUAGE.NAME}: ${VALUE.NAME}

В выше приведенном примере все переменные для фраз на актуальном языке начинаются со слова LANGUAGE, а все переменные для динамических значений – со слова VALUE.
 
Еще одно преимущество заключается в том, что при каждой генерации страницы можно автоматически присваивать значения переменным с префиксом LANGUAGE. Метод Template->getVariableNames() используется для того, чтобы определить все LANGUAGE переменные. После этого переменным присваиваются значения методом Template->xassignForGlobal(...).
 

Лицензия

Шаблонизатор Separate разработан Эдуардом Судником и является фреймворком с открытым исходным кодом для PHP, который предоставляется в распоряжение посредством лицензии MIT.
© 2004—2024 Эдуард Судник Адрес эл. почты: separate@esud.info