Выпуск 9. Ноябрь 2013
← От редактора | Содержание | Обзор изменений Perl 5.19.5 →Использование HTML::FormFu при работе с Catalyst
Введение в использование HTML::FormFu
под Catalyst
. Очень простые примеры, комментарии. Руководство для начинающих. Как создать Catalyst
-приложение с нуля.
Все примеры были выполнены специально для публикации, в Windows-среде, под Strawberry Perl. В среде UNIX развернуть все необходимое и заставить работать должно быть даже проще. Приведенные примеры кода будут работать и в том, и в другом случае — они достаточно простые, чтобы не зависеть от тонкостей использования среды.
Для того, чтобы получить более полное представление о работе HTML::FormFu
в Catalyst
, создадим Catalyst
-приложение с нуля. Более того, установим Catalyst
под Windows. Можно было пойти более простым путем, и использовать уже готовое рабочее UNIX-окружение, но тогда оставалась вероятность, что в описании забудется какой-нибудь важный модуль, или аспект, без внимания к которому подключить HTML::FormFu
будет не просто.
Введение
Что такое Catalyst?
Catalyst
— это фреймворк для создания веб-приложений. Поддерживает концепцию MVC (Model-View-Controller).
Catalyst
поставляется вместе со своим собственным HTTP-сервером, который можно использовать для разработки и тестирования. В боевых условиях, его используют в связке nginx + FastCGI, или Apache + mod_perl. Можно использовать другие серверы, но такие решения встречаются значительно реже.
Несмотря на регулярную критику, Catalyst
остается самым мощным и популярным фреймворком в Perl-среде.
Что такое HTML::FormFu?
HTML::FormFu
— это менеджер форм для Perl-приложений. Гибкий и мощный инструмент. Поддерживает все этапы работы с формами: создание форм, их валидацию, вывод ошибок, сохранение данных в БД. HTML::FormFu
считается одной из самых мощных и функциональных систем для работы с формами в Perl.
Как установить Catalyst под Windows
Запускаем cpan
в Perl-консоли. Потом вводим первую команду:
force install Catalyst::Runtime
На этом этапе может случится первый fail — если пытаться установить Catalyst
(ну правильно, документацию читают только слабаки) вот так:
force install Catalyst
cpan
что-то долго думает, что-то закачивает, устанавливает, но в итоге все заканчивается ошибкой. Устанавливать надо Catalyst::Runtime
, а не Catalyst
!
force install
нужен, чтобы запретить cpan
слишком много думать и обращать внимание на результаты тестов. При установке Perl-модулей под Windows — это необходимо.
Потом устанавливаем еще немного дополнительных модулей, без которых сложно построить минимальное Catalyst
-приложение или не будет работать HTML::FormFu
.
force install Catalyst::Controller::HTML::FormFu
force install Catalyst::Devel
force install DBD::mysql
force install DBI
force install DBIx::Class
force install Catalyst::Model::DBIC::Schema
force install Catalyst::View::TT
force install DBIx::Class::Schema::Loader
Для того, чтобы беспроблемно установить DBIx::Class::Schema::Loader
— желательно прописать в переменных окружения путь к вашему локальному mysql-демону (во время тестирования использовалась локальная mysql-БД).
force install MooseX::MarkAsMethods
force install Catalyst::Plugin::Unicode::Encoding
Как создать каркас Catalyst-приложения под Windows
Создаем директорию, в которой будет расположен проект. Например: C:\Documents and Settings\username\www
.
Совет: создавая директорию, следует избегать русскоязычных имен в пути к вашему проекту. В дальнейшем это может привести к возникновению проблем.
Переходим в созданную директорию. В командной строке Strawberry Perl вводим:
catalyst.pl MyApp
В результате, в каталоге www
будет создана директория с именем MyApp
, содержащая каркас Catalyst
-приложения.
Как создать контроллер
Создаем контроллер Admin.pm
, в дальнейшем он нам пригодится. Для этого в Perl-консоли выполняем команду:
perl script/myapp_create.pl controller Admin
Остальные контроллеры создаем вручную.
Как создать View
В отличие от контроллера, view вручную лучше не создавать. В Perl-консоли выполняем команду:
perl script/myapp_create.pl view TT TT
Команда создаст файл TT.pm
в директории /lib/MyApp/View/TT.pm
. Модуль TT.pm
требуется отредактировать, добавив настройки:
package MyApp::View::TT;
use Moose;
use namespace::autoclean;
extends 'Catalyst::View::TT';
__PACKAGE__->config(
TEMPLATE_EXTENSION => '.tt',
render_die => 1,
CATALYST_VAR => 'c',
ENCODING => 'utf-8',
);
1;
Далее, открываем файл MyApp.pm
и добавляем еще немного конфигурационных данных для TT в блоке __PACKAGE__->config()
:
__PACKAGE__->config(
# ...
'View::TT' => {
INCLUDE_PATH => [
__PACKAGE__->path_to( 'root', 'src' ),
],
},
);
Кроме того, в блок use Catalyst qw/.../;
добавляем Unicode::Encoding
. Это делается для того, чтобы Catalyst
смог нормально обрабатывать русскоязычные символы в шаблонах.
use Catalyst qw/
# ...
Unicode::Encoding
/;
Если Unicode::Encoding
не подключить, в дальнейшем можно будет увидеть в логах ошибку:
[error] Caught exception in engine "Wide character in syswrite at C:/strawberry/ perl/lib/IO/Handle.pm line 474."
Terminating on signal SIGINT(2)
Настройки для HTML::FormFu
В файле MyApp.pm
в блок __PACKAGE__->config()
добавляем настройки:
__PACKAGE__->config(
# ...
'Controller::HTML::FormFu' => {
'model_stash' => {
schema => 'DB'
},
constructor => {
tt_args => {
ENCODING => 'UTF-8',
}
}
}
);
Как создать модель
В Perl-консоли выполняем команду:
perl script/myapp_create.pl model DB DBIC::Schema MyApp::Schema::DB create=static "dbi:mysql:test" "root" ""
После этого в блоке connect_info
файла lib/MyApp/Model/DB.pm
добавляем параметр mysql_enable_utf8
:
connect_info => {
dsn => 'dbi:mysql:test',
user => 'root',
password => '',
mysql_enable_utf8 => 1
}
Этот параметр позволит корректно отображать данные из таблиц БД. Разумеется, если данные хранятся в кодировке UTF-8.
Как запустить сервер Catalyst под Windows
В консоли выполняем команду:
perl script/myapp_server.pl
Это позволит запустить специальный web-сервер. Для боевого использования он не подходит, а для тестирования новых возможностей — вполне. В эту же консоль будет печататься вывод отладочной информации сервера.
В браузере вводим адрес:
http://localhost:3000
Создаем интерфейс администратора с помощью HTML::FormFu и Catalyst
Панель администратора — это скрытый от обычных посетителей блок сайта, который позволяет владельцу осуществлять управление контентом сайта и принципами его отображения. Например, настроить список используемых виджетов, добавить новые публикации, разместить баннеры и т.п.
Почти вся админка — это бесконечное число разнообразных форм. Использование менеджера форм тут более чем оправдано.
Поэтому в качестве простого примера создадим примитивный интерфейс администратора:
- главную страницу панели администратора;
- страницу со списком публикаций на сайте;
- страницу для редактирования статей (на основе
HTML::FormFu
); - страницу для создания новой публикации (на основе
HTML::FormFu
).
Кроме того, позволим пользователю удалять статьи.
Дамп БД
Для начала нам потребуется база данных. Ниже — дамп БД, которая использовалась для приведенных примеров. Установить БД, если ее у вас нет, лучше еще до начала установки Catalyst
с его модулями для создания моделей.
Теперь просто создаем таблицу и следим за кодировками, дабы избежать проблем в будущем. Как современные люди, мы выбираем UTF-8.
CREATE DATABASE IF NOT EXISTS `test`;
USE `test`;
CREATE TABLE IF NOT EXISTS `articles` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`full` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `articles` (`id`, `name`, `full`) VALUES
(1, 'name', 'text'),
(2, 'name2', 'текст');
Главная страница панели администратора
Для максимально удобной работы с HTML::FormFu
в Catalyst
, существует модуль Catalyst::Controller::HTML::FormFu
. Если планируем в создаваемом контроллере использовать менеджер форм, подключаем Catalyst::Controller::HTML::FormFu
с помощью extends
.
Создать форму можно либо определив ее параметры в непосредственно в коде, либо — по конфигурационному файлу. Конфигурационный файл предпочтительней. Во-первых, это все-таки элементы HTML-кода, и уже давно стало хорошим правилом отделять разметку от кода. Во-вторых, при создании панели администратора в боевых условиях форм будет очень много, и удобнее хранить их отдельно.
Чтобы создать форму, нужно задать в атрибутах Catalyst
action
— :FormConfig
. Если не указать путь к форме в атрибуте :FormConfig
, система решит, что в качестве имени формы следует использовать имя action
. Поиск файла будет осуществляться примерно по такому пути: root/forms/controller_name/action_name.yml
.
Наличие атрибута :FormConfig
говорит системе, что требуется создать объект формы и разместить его в хранилище Catalyst
— $c->stash->{form}
. Чтобы вывести форму на html-странице, достаточно добавить в шаблон инструкцию: [% form %]
. form
— это полностью готовый блок HTML-кода формы.
Проверить, была ли отправлена форма и корректны ли ее данные можно с помощью метода $form->submitted_and_valid
.
Другой метод позволит получить данные из полей формы: $form->param_value('field_name')
. Кроме того, можно получить значения полей формы с помощью $c->req->param('field_name')
.
Модуль /lib/MyApp/Controller/Admin.pm
package MyApp::Controller::Admin;
use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }
sub index :Path :Args(0) {
my ( $self, $c ) = @_;
$c->stash->{template} = 'admin/index.tt';
$c->forward('View::TT');
}
__PACKAGE__->meta->make_immutable;
1;
Шаблон /root/src/admin/index.tt
Переходим в директорию root
. Создаем в ней каталог src
. В каталоге src
создаем каталог admin
.
Не забываем, что все шаблоны должны быть в кодировке UTF-8 .
<h1>Панель администратора</h1>
<ul>
<li><a href="[% c.uri_for( 'articles' ).path_query %]">Список публикаций</a></li>
</ul>
Для наглядности TT-шаблоны не содержат никакого HTML-кода, кроме самого необходимого.
Работа с публикациями
Модуль /lib/MyApp/Controller/Admin/Articles.pm
Один модуль будет отвечать и за отображение списка публикаций, и за создание новых, редактирование старых, и за удаление статей.
package MyApp::Controller::Admin::Articles;
use Moose;
use namespace::autoclean;
BEGIN { extends qw/
Catalyst::Controller::HTML::FormFu
/ }
=head2 index
Отображение страницы со списком статей
=cut
sub index :Chained('') :Path :Args(0) {
my ( $self, $c ) = @_;
$c->stash->{articles_list} = [$c->model('DB::Article')->search(
{}
)->all];
$c->stash->{template} = 'admin/articles.tt';
$c->forward('View::TT');
}
=head2 remove
Удаление статьи по ее идентификатору в БД
=cut
sub remove :Chained('') :Path('remove') :Args(1) {
my ( $self, $c, $id ) = @_;
$c->model('DB::Article')->find({ id => $id})->delete;
$c->res->redirect($c->uri_for('/admin/articles'));
}
=head2 update
Данный блок кода отвечает за отображение страницы для редактирования статьи,
и за обновление статьи в БД.
=cut
sub update :Chained('') :Path('update') :Args(1) :FormConfig('article/update.yml') {
my ( $self, $c, $id ) = @_;
my $form = $c->stash->{form};
if ($form->submitted_and_valid) {
eval {
my $obj = $c->model('DB::Article')->update_or_create({
id => $form->param_value('id'),
name => $form->param_value('name') || undef,
full => $form->param_value('full') || undef
});
};
$c->warn('DB error') if $@;
} else {
my $article = $c->model('DB::Article')->search( {
id => $id,
} )->first;
$c->stash->{form}->default_values({
'name' => $article->name,
'full' => $article->full,
'id' => $article->id
});
}
$c->stash->{template} = 'admin/article/update.tt';
$c->forward('View::TT');
}
=head2 create
Страница для создания новой статьи. Если пользователь нажал кнопку "Сохранить",
статья отправляется в БД, затем клиента перенаправляют на страницу со списком статей.
=cut
sub create :Chained('') :Path('create') :Args(0) :FormConfig('article/create.yml') {
my ( $self, $c, $id ) = @_;
my $form = $c->stash->{form};
if ($form->submitted_and_valid) {
eval {
my $obj = $c->model('DB::Article')->create({
name => $form->param_value('name') || undef,
full => $form->param_value('full') || undef
});
};
$c->warn('DB error') if $@;
$c->res->redirect($c->uri_for('/admin/articles'));
} else {
$c->stash->{template} = 'admin/article/create.tt';
$c->forward('View::TT');
}
}
__PACKAGE__->meta->make_immutable;
1;
default_values
— позволяет задать значения по умолчанию полям формы, то, что увидит пользователь, если откроет страницу с формой.
Можно использовать метод $form->submitted
, чтобы понять, была форма отправлена или нет. Форма может быть отправлена, но не пройти валидацию. Метод $form->submitted_and_valid
учитывает и отправку, и благополучное прохождение валидации.
Шаблон /root/src/admin/articles.tt
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Формочка</title>
<link rel="stylesheet" type="text/css" href="/static/style.css" />
</head>
<body>
<table cellspacing="0" id="result_list">
[% FOREACH article = articles_list %]
<tr>
<td>
<a href="[% c.uri_for( 'update', article.id ).path_query %]">[% article.name %]</a>
<a href="[% c.uri_for( 'remove', article.id ).path_query %]">Удалить</a>
</td>
</tr>
[% END %]
</table>
<a href="[% c.uri_for( 'create' ).path_query %]">Добавить новую статью</a>
</body>
</html>
Шаблон /root/src/admin/article/update.tt
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Формочка</title>
<link rel="stylesheet" type="text/css" href="/static/style.css" />
</head>
<body>
Update article
[% form %]
</body>
</html>
Шаблон /root/src/admin/article/create.tt
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Формочка</title>
<link rel="stylesheet" type="text/css" href="/static/style.css" />
</head>
<body>
Create new article
[% form %]
</body>
</html>
CSS-стили для формы /root/static/style.css
Добавим совсем простую CSS-таблицу, которая позволяет аккуратно вывести элементы формы. В дальнейшем, CSS можно усложнить, создавая с его помощью профессиональное оформление всей панели администратора.
form {
width: 40em;
}
.submit {
display: block;
}
label {
display: block;
}
YAML-конфиг для формы /root/forms/article/update.yml
По умолчанию Catalyst
-приложение будет искать формы в директории root/forms
. Для работы с конфигурационными файлами Catalyst::Controller::HTML::FormFu
использует Config::Any
. Соответственно, хранить конфигурационную информацию о формах кроме YAML-формата можно в XML, JSON, конфигах в стиле Apache, Perl-коде и т.п.
Переходим в директорию root
. Создаем в ней каталог forms
. В каталоге forms
создаем каталог article
и файл update.yml
.
---
attributes:
id: element-form
auto_fieldset:
attributes:
class: module aligned
---
elements:
- type: Hidden
name: id
- type: Text
name: name
label: Название статьи
- type: Textarea
name: full
label: Текст статьи
- type: Submit
name: submit
value: Сохранить
YAML-конфиг для формы /root/forms/article/create.yml
---
attributes:
id: element-form
auto_fieldset:
attributes:
class: module aligned
---
elements:
- type: Text
name: name
label: Название статьи
- type: Textarea
name: full
label: Текст статьи
- type: Submit
name: submit
value: Сохранить
Вот и все. Простой прототип панели администратора с использованием HTML::FormFu
готов. Теперь на основе полученных результатов можно пробовать усложнять формы, вводить в работу сложные поля и правила валидации, добавлять JavaScript для работы со сложными элементами, CSS для создания современного интерфейса.
В данном руководстве ничего не сказано про работу HTML::FormFu
с БД своими средствами. Честно говоря, автора эти возможности не впечатлили. Возможно, примеры, которые встречались в сети, были слишком простыми. Но пока не видно никакой разницы, использовать для сохранения в БД средства HTML::FormFu
или стандартный запрос с помощью DBIx
.
← От редактора | Содержание | Обзор изменений Perl 5.19.5 →