Лето близится к концу, однако ещё остались дни, чтобы насладиться солнцем, отпуском, 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 - работа с базой, модели и миграции