Использование шаблонизатора Twig в Bitrix

Использование шаблонизатора Twig в Bitrix Шаблоны Bitrix - мощнейший инструмент кастомизации вашего сайта. Однако, подход, выбранный Bitrix сильно отличается от принятого в современных фреймворках. Но мало кто знает (а еще меньше используют), что Bitrix позволяет использовать шаблонизаторы в шаблонах компонентов (да-да, шаблон сайта придется писать по-старому). Сегодня мы рассмотрим один из простейших вариантов работы.

В качестве подопытного кролика мы используем один из самых популярных PHP шаблонизаторов - Twig. На синтаксисе и методах работы мы останавливаться не будем, так что настоятельно рекомендую ознакомиться с русскоязычной документацией.

Для нашего небольшого эксперимента нам потребуется веб-сервер с PHP на борту (я использую OpenServer), Composer в качестве пакетного менеджера и минимальные навыки работы в консоли.

Установка Composer тривиальна. Идем на сайт https://getcomposer.org/, переходим в раздел Download и следуем простым инструкциям. Для пользователей Windows все сводится к скачиванию и установке Composer-Setup.exe и последовательному копипасту четырех команд в консоль:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === '55d6ead61b29c7bdee5cccfb50076874187bd9f21f65d8991d46ec5cc90518f447387fb9f76ebae1fbbacf329e583e30') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
Для более удобной работы с Composer, я создам bat-файл:
touch composer.bat
…и помещу в него вызов composer.phar:
@php "%~dp0composer.phar" %*
Теперь вместо длинной записи "php composer.phar" можно будет использовать сокращенную "composer".

Дальше нам необходимо задать некоторые настройки Composer. Дело в том, что по умолчанию, все пакеты зависимостей будут установлены в директорию /vendor. Мне это не нравится. Все дополнительные библиотеки я хочу видеть в папке /local/php_interface/lib/ и подключать их в init.php.

К счастью, пакетный менеджер позволяет легко это настроить. Создадим в корне сайта файл composer.json:
touch composer.json
И зададим нужную нам директорию таким вот образом:
{
    "config":   {
        "vendor-dir":   "local/php_interface/lib"
    }
}
Теперь можно выполнить команду добавления зависимости Twig в проект и произвести установку:
composer require twig/twig
Готово. После завершения установки в директории local/php_interface/lib/ должны появиться папки composer, twig и файл autoload.php.
Структура composer Autoload.php необходимо подключить в init.php для работы всех установленных с помощью composer пакетов:
<?php
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/local/php_interface/lib/autoload.php'))
        require_once $_SERVER['DOCUMENT_ROOT'] . '/local/php_interface/lib/autoload.php';
Теперь напишем обработчик. Для начала опишем в глобальной переменной $arCustomTemplateEngines список расширений и функцию-обработчик.
global $arCustomTemplateEngines;
 $arCustomTemplateEngines['twig'] = array(
    'templateExt' => array(
        'twig',
    ),
    'function'    => 'renderTwig'
);
Ну и опишем саму функцию-обработчик (в том же init.php). Функция принимает в себя все данные, с которыми работает шаблон. Из интересного тут: задание папки хранения кеша и его сброс при нажатии на Битриксовскую кнопку "Сбросить кеш". Остальное тривиально и описано в Basic API Usage на сайте Twig.
function renderTwig(
    $templateFile,
    $arResult,
    $arParams,
    $arLangMessages,
    $templateFolder,
    $parentTemplateFolder,
    $template
)
{
    $loader = new Twig_Loader_Filesystem($_SERVER['DOCUMENT_ROOT']);
    $twig = new Twig_Environment($loader, array(
        'cache' => '/bitrix/cache/twig/',
        'auto_reload' => isset( $_GET[ 'clear_cache' ] ) && strtoupper($_GET[ 'clear_cache' ]) == 'Y',
    ));
    echo $twig->render(
        $templateFile,
        array(
            'arResult' => $arResult,
            'arParams' => $arParams,
            'arLangMessages' => $arLangMessages,
            'template' => $template,
            'templateFolder' => $templateFolder,
            'parentTemplateFolder' => $parentTemplateFolder,
        )
    );
}
Давайте начнем экспериментировать. Добавим на тестовую страницу компонент списка новостей и настроим на вывод какого-нибудь инфоблока:

<?require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/header.php')?>
<?$APPLICATION->IncludeComponent(
"bitrix:news.list",
".default",
array(
"COMPONENT_TEMPLATE" => ".default",
"IBLOCK_TYPE" => "portfolio",
"IBLOCK_ID" => "2",
"NEWS_COUNT" => "10",
"SORT_BY1" => "ACTIVE_FROM",
"SORT_ORDER1" => "DESC",
"SORT_BY2" => "SORT",
"SORT_ORDER2" => "ASC",
"FILTER_NAME" => "",
"FIELD_CODE" => array(
0 => "",
),
"PROPERTY_CODE" => array(
0 => "",
),
"CHECK_DATES" => "Y",
"DETAIL_URL" => "",
"AJAX_MODE" => "N",
"AJAX_OPTION_JUMP" => "N",
"AJAX_OPTION_STYLE" => "Y",
 "AJAX_OPTION_HISTORY" => "N",
"AJAX_OPTION_ADDITIONAL" => "",
"CACHE_TYPE" => "A",
"CACHE_TIME" => "36000000",
"CACHE_FILTER" => "N",
"CACHE_GROUPS" => "Y",
"PREVIEW_TRUNCATE_LEN" => "",
"ACTIVE_DATE_FORMAT" => "d.m.Y",
"SET_TITLE" => "Y",
"SET_BROWSER_TITLE" => "Y",
"SET_META_KEYWORDS" => "Y",
"SET_META_DESCRIPTION" => "Y",
"SET_LAST_MODIFIED" => "N",
"INCLUDE_IBLOCK_INTO_CHAIN" => "Y",
"ADD_SECTIONS_CHAIN" => "Y",
"HIDE_LINK_WHEN_NO_DETAIL" => "N",
"PARENT_SECTION" => "",
"PARENT_SECTION_CODE" => "",
"INCLUDE_SUBSECTIONS" => "Y",
"DISPLAY_DATE" => "Y",
"DISPLAY_NAME" => "Y",
"DISPLAY_PICTURE" => "Y",
"DISPLAY_PREVIEW_TEXT" => "Y",
"PAGER_TEMPLATE" => ".default",
"DISPLAY_TOP_PAGER" => "N",
"DISPLAY_BOTTOM_PAGER" => "Y",
"PAGER_TITLE" => "Новости",
"PAGER_SHOW_ALWAYS" => "N",
"PAGER_DESC_NUMBERING" => "N",
"PAGER_DESC_NUMBERING_CACHE_TIME" => "36000",
"PAGER_SHOW_ALL" => "N",
"PAGER_BASE_LINK_ENABLE" => "N",
"SET_STATUS_404" => "N",
"SHOW_404" => "N",
"MESSAGE_404" => ""
),
false
);
?>

<?require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/footer.php')?>

Скопируем дефолтный шаблон и назовем его twig_test
Копирование шаблона компонента Вот наша структура шаблона:
Структура шаблона Смотрим, любуемся, а теперь берем и удаляем файл template.php. Вместо него создаем файл template.twig. Вот код файла template.twig целиком:
{% for item in arResult.ITEMS %}
     <div class="text_block">
         <h2><
             <a href="{{ item.DETAIL_PAGE_URL }}">{{ item.NAME }}</a>
         </h2>
         <img alt="{{ item.PREVIEW_PICTURE.ALT }}" src="{{ item.PREVIEW_PICTURE.SRC }}">
     </div>
 {% endfor %}
Судя по моим наблюдениям, twig с включенным кешированием не уступает в скорости шаблонам Bitrix с включенным композитом. Цифры примерно такие.

Шаблоны Bitrix + Кеш + Композит:
Скорость в композитном режиме Twig + Кеш:
Скорость с кешированием twig Как итог: шаблонизаторы в Bitrix использовать можно. Как минимум, это избавит разработчиков от вредной привычки получать данные в шаблоне компонента.

Возврат к списку