
Лето близится к концу, однако ещё остались дни, чтобы насладиться солнцем, отпуском, Perl и Dancer2. Последним двум будет посвящена эта статья.
Поговорим про:
Выбор шаблонного движка
Сессии
Флэш-сообщения
Выбор шаблонного движка
В предыдущей статье Dancer2 или современное web-приложение на PERL мы поверхностно затронули тему шаблонов. Пришло время разобраться с деталями.
По умолчанию в конфигурации нашего проекта установлен самый базовый шаблонный движок Dancer2::Template::Simple (все ссылки в конце). Он умеет делать только две вещи: интерполировать переменные и подключать макет. Почти для любого приложения этого недостаточно. Хочется использовать циклы, условия и удобно работать со сложными структурами данных. Dancer2 имеет адаптеры к большому количеству популярных модулей для создания шаблонов:

В документации активно продвигается самый популярный в среде Perl Template::Toolkit. Это настоящий кухонный комбайн с большими набором встроенных функций, фильтров и прочего. На мой взгляд, для web-приложения у него есть один существенный недостаток: вывод не экранируется по умолчанию. Для того, чтобы преобразовать все HTML-значимые-символы в HTML-сущности, нужно явно применить соответствующий фильтр. А значит получение XSS-уязвимости - дело времени (рано или поздно кто-нибудь из команды обязательно забудет применить нужный фильтр).
После продолжительного времени, проведенного в поисковиках, на форумах и даже в специализированных чатах, я нашел прекрасное современное решение Dancer2::Template::Handlebars (да-да, в Перле много современного, бывает надо просто хорошенько поискать). В нем используется приятный "усатый" синтаксис {{ }}, весь вывод фильтруется по умолчанию, из коробки предоставляются хелперы: with, each, if, unless и, что немаловажно, он легко расширяется с помощью модуля Dancer2::Template::Handlebars::Helpers.
Приступим к подключению. Для начала, в консоли:
cpan Dancer2::Template::Handlebars
Следом пропишем необходимые поля в config.yml:
views: "views" # путь к директории шаблонов template: "handlebars" # меняем значение на "handlebars"
Теперь необходимо для всех шаблонов и макетов (находятся в директории views) изменить расширение с .tt на .hbs, результат должен быть таким:

А внутри самих файлов изменить <% var %> на новый синтаксис с фигурными скобками {{ var }}. Код page.hbs:
<h1>Hi!</h1> <p>You are on page: <b>{{ page }}</b></p>
Открываем http://localhost:5000/pages/11 и видим:

Догадались в чем проблема? Правильно, HTML-фильтр по умолчанию. Поправить можно легко, для этого надо заключить переменную content в макете layouts/main.hbs в тройные "усы", вот так: {{{ content }}} (таким образом не применяется фильтр). Теперь всё в порядке:

Для тех, кто захочет изучить Dancer2::Template::Handlebars детальнее, в конце будет ссылка. А мы переходим к сессиям.
Сессии
Фреймворк предлагает различные технологии хранения сессий на выбор:
In-memory
YAML
Cookie
База данных
Redis/Memcached
и другие
Например, Dancer2::Session::YAML, хранящая данные в yml на сервере. При использовании этой технологии в продакшене, следует озаботиться механизмом удаления старых файлов, например через cron.
Начинаем с установки модуля:
cpan Dancer2::Session::YAML
Далее в config.yml:
session: "YAML" engines: session: YAML: session_dir: "tmp/sessions" # путь к хранилищу cookie_name: "sessid" # название куки cookie_duration: 3600 # время жизни куки is_secure: 1 # только HTTPS is_http_only: 1 # не доступна JS
Директорию tpm/sessions лучше создать самостоятельно и добавить её в .gitignore.
Работа с сессией происходит с помощью функции session, для записи передаем ей два аргумента, а для чтения один:
# запись session 'user_info' => { name => 'Petya', created => '15.08.2021', }; # чтение my $user_info = session 'user_info';
Содержимое файла с сессией будет выглядеть так:
--- user_info: created: 15.08.2021 name: Petya
Флэш-сообщения
Лучший способ продемонстрировать работу сессии - использовать флэш-сообщения. Из коробки Dancer их не предоставляет, но существует несколько плагинов, реализующих данную функцию. Например Dancer2::Plugin::FlashNote:
cpan Dancer2::Plugin::FlashNote
Config.yml:
plugins: FlashNote: queue: "single" # хранится только одно сообщение dequeue: "when_used" # сообщение удаляется при использовании
Подключаем модуль вверху lib/MyApp.pm:
use Dancer2::Plugin::FlashNote;
И в наше распоряжение попадает функция flash, плюс одноименная переменная будет доступна в шаблонах.
Соединяем полученные знания
Для закрепления материала реализуем следующую задачу:
Создание роута logout, который установит флэш-сообщение и перенаправит пользователя на главную.
Создание главной страницы, на которой будет выводится флэш-сообщение при его наличии.
Приведу весь код для lib/MyApp.pm:
package MyApp; use Dancer2; use Dancer2::Plugin::FlashNote; our $VERSION = '0.1'; get '/' => sub { template 'index'; # шаблон главной страницы }; get '/logout' => sub { flash 'Bye bye!'; # установка флэш-сообщения redirect '/'; # перенаправление на главную }; get '/pages/:page[Int]' => sub { my $page = route_parameters->get('page'); template 'page', { page => $page, }; }; true;
И код шаблона index.hbs с использованием блока if:
{{#if flash }} <p><b>{{ flash }}</b></p> {{/if }} <p>Let's dance!</p>
Теперь при открытии http://localhost:5000/logout мы окажемся на главной и увидим:

При повторном обращении к главной, сообщение пропадет.
Итог
Мы преодолели немалый путь и научились создавать роуты и шаблоны для них, использовать сессии и флеш-сообщения, а также расширять стандартную функциональность фреймворка плагинами. В следующей части поговорим про работу с базой, модели и миграции.
Весь код, который был написан в процессе создания этой статьи выложен на гитхаб (ссылка в конце). Создавайте свои web-приложения легко и танцуйте вместе с Perl и Dancer2!
Серия статей про Dancer2
Часть I - установка, роутинг и шаблоны
Часть II (текущая) - выбор шаблонного движка, сессии и флэш-сообщения
Часть III - работа с базой, модели и миграции
