Лето близится к концу, однако ещё остались дни, чтобы насладиться солнцем, отпуском, Perl и Dancer2. Последним двум будет посвящена эта статья.

Поговорим про:

  • Выбор шаблонного движка

  • Сессии

  • Флэш-сообщения

Выбор шаблонного движка

В предыдущей статье Dancer2 или современное web-приложение на PERL мы поверхностно затронули тему шаблонов. Пришло время разобраться с деталями.

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

С сайта https://www.perldancer.org/

В документации активно продвигается самый популярный в среде 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-сущности

Догадались в чем проблема? Правильно, 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 - работа с базой, модели и миграции

Ссылки