Dancer2 или современное web-приложение на PERL. Часть III

от автора

Современные web-приложения в большинстве случаях хранят данные в SQL базах данных. Для доступа к этим данным используются объекты модели, которые позволяют совершать все основные операции: SELECT, INSERT, UPDATE, DELETE, но не ограничиваясь ими.

В этой части мы поговорим про работу с базой в Dancer2, а также научимся создавать модели и миграции на основе DBIx::Class (можно сказать, что эта статья является вводным руководством и по нему).

Для удобства будем считать, что термин база данных в нашем изложении, означает именно СУБД SQL: MySQL, MariaDB, PostgreSQL, SQLite и другие.

Подключение к БД

Dancer2 не регламентирует правила и методы для работы с базой. Разработчик волен выбрать любое подходящее решение. Для небольших приложений — это могут быть прямые SQL-запросы, для больших проектов можно реализовать DDD с репозиториями и фабриками или удобный ActiveRecord. Начнем с простого.

В perl стандартным интерфейсом для работы с БД является DBI, который использует DBD-драйверы для установки конкретных соединений (например, для интеграции с MySQL следует дополнительно к DBI установить драйвер DBD::mysql). Dancer использует модуль обертку над ним Dancer2::Plugin::Database, которая упрощает задачу создания соединения и добавляет в наш арсенал хелпер database. Установим его:

cpan Dancer2::Plugin::Database

Подключаем модуль вверху lib/MyApp.pm:

use Dancer2::Plugin::Database;

В качестве базы будем использовать SQLite, она не требует поднятия сервера и проста в использовании. Фактически нам нужен лишь драйвер:

cpan DBD::SQLite

Добавим в секцию plugins файла config.yml:

  Database:     driver: "SQLite"     database: "dancr.db"

Чтобы не хранить в репозитории потенциально большой и часто изменяемый файл (в котором еще и могут оказаться персональные данные), добавьте dancr.db в .gitignore.

Теперь проверим соединение. Для этого создадим роут в lib/MyApp.pm, в котором вызовем пинг:

get '/db' => sub {     'Соединение с базой установлено' if database->ping; };

При открытии http://localhost:5000/db мы увидим соответствующее сообщение.

Как видно из примера, общение происходит через объект, возвращаемый функцией database. Через него можно обращаться к бд и выполнять любые SQL запросы (подробный мануал можно найти в документации DBI на metacpan). Многим приложениям этого более чем достаточно. Но мы пойдем дальше и реализуем слой моделей.

DBIx::Class

Для создания моделей будем использовать паттерн ActiveRecord, объединяющий в моделях бизнес логику и методы по работе с данными. В перле он реализован популярным и очень мощным модулем DBIx::Class, а Dancer имеет соответствующий плагин Dancer2::Plugin::DBIC.

Устанавливаем:

cpan Dancer2::Plugin::DBIC

Далее необходимо создать классы, описывающие схему данных нашего проекта. Для примера реализуем логику работы с пользователями.

Создадим корневой класс lib/MyApp/Schema.pm:

package MyApp::Schema;  use warnings; use strict; use parent qw/DBIx::Class::Schema/;  our $VERSION = '1.00';  __PACKAGE__->load_namespaces;  1;

Его основная задача подключать классы, представляющие конкретные таблицы. Для пользователей это будет lib/MyApp/Schema/Result/User.pm:

package MyApp::Schema::Result::User;  use warnings; use strict; use parent qw/DBIx::Class::Core/;  __PACKAGE__->table('user');  __PACKAGE__->add_columns(     id => {         data_type => 'integer',         is_auto_increment => 1     },     login => {         data_type => 'text',     },     email => {         data_type => 'text',     }, );  __PACKAGE__->set_primary_key('id');  __PACKAGE__->add_unique_constraint([qw/login/]);  __PACKAGE__->add_unique_constraint([qw/email/]);  1; 

Тут мы описываем название таблицы (7 строка), потом её атрибуты и их свойства. В 22 строке определили первичный ключ и установили предикат UNIQUE для поля login в 24 и email в 26.

В результате получим следующую структуру в директории lib:

Создадим директорию db, чтобы хранить там базу и всё, что к ней относится:

mkdir db

Теперь подключаем плагин в config.yml, секция plugins:

  DBIC:     default:       dsn: "dbi:SQLite:dbname=db/dancr.db"       schema_class: "MyApp::Schema"

С созданием модели мы разобрались, осталось создать таблицы и наполнить их.

Миграции

Это набор скриптов и файлов позволяющий версионировать базу данных, а также переносить её между машинами. Миграции удобны при работе в команде. Любой разработчик может установить актуальную схему просто клонировав репозиторий проекта и запустив нужный скрипт.

Воспользуемся пакетом DBIx::Class::Migration:

cpan DBIx::Class::Migration

После установки мы сможем использовать утилиту dbic-migration для работы с миграциями. Она принимает, в том числе, следующие опции:

  • -I — путь к директории, где хранятся модули нашего проекта

  • —schema_class — имя корневого класса

  • —dsn — строка с данными для подключения к базе

  • —target_dir — директория для хранения миграций

Как видите, их довольно много и работать с этим набором из командной строки достаточно проблематично. Для удобства, создадим простой скрипт обертку migration.pl в корне проекта:

$base = 'dbic-migration -I lib --schema_class MyApp::Schema --dsn dbi:SQLite:dbname=db/dancr.db --target_dir db';  for (shift) {      if (/prepare/) { exec "$base prepare"; }     if (/install/) { exec "$base install"; } }

В нем мы реализовали две простые команды:

  • prepare — создаст весь необходимый скелет и базовые миграции, ориентируясь на нашу схему

  • install — применит миграции к базе

Запускаем prepare в консоли:

perl migration.pl prepare

Получим следующую структуру в db:

Рассмотрим подробнее каждую поддиректорию:

  • fixtures — тут хранятся фикстуры в виде json-файлов. Обычно их применяют для тестирования базы, но это выходит за рамки данной статьи.

  • migrations — состоит из _source (не спроста начинается с нижнего подчеркивания) и migrations, где собственно и хранятся файлы миграции, созданные на основе нашей схемы, например 001-auto.sql (в нем вы найдете sql-код для создания таблицы users).

Обратите внимание, что путь к фикстурам и миграциям содержит номер версии схемы, указанный в MyApp::Schema — это основной способ управления ими.

Чтобы наполнить базу первоначальными данными, создадим вручную файл db/migrations/SQLite/deploy/1.00/002-users.sql:

BEGIN TRANSACTION;  INSERT INTO user ("login", "email") VALUES ("Jenya", "j@mail.ru"),      ("Mila", "m@mail.ru");  COMMIT;

Теперь применим миграции:

perl migration.pl install

Выводим данные (вместо заключения)

Напишем простой роут, по которому будем отдавать список пользователей:

get '/users' => sub { my @users = map { { $_->get_columns } } schema->resultset('User')->all;  template 'users', {         users => \@users,     }; };

В нем мы получаем данные из базы данных и передаем их в представление в виде массива хэшей. Реализуем представление views/users.hbs:

<h1>Users</h1>  {{#each users}}     <p>логин: {{ login }}, email: {{ email }}</p> {{/each}}

Теперь по http://localhost:5000/users можно будет увидеть список всех пользователей системы. Тем самым мы полностью реализовали основу полноценного MVC-проекта. Используя эту структуру, вы сможете легко решить любую бизнес задачу и создать современное web-приложение.

Весь код можно найти на гитхабе (ссылка в конце).

P.S.

Следующая часть будет заключительной, там будет самое интересное!

Серия статей про Dancer2

  • Часть I — установка, роутинг и шаблоны

  • Часть II — выбор шаблонного движка, сессии и флэш-сообщения

  • Часть III (текущая) — работа с базой, модели и миграции

Ссылки


ссылка на оригинал статьи https://habr.com/ru/articles/579668/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *