CGI::FormBuilder - очень удобный модуль для работы с web-формами, особенно когда в проекте их много, и в них много элементов. При этом он активно используется в связке с Catalyst'ом, но им можно пользоваться и отдельно, что я и рассмотрю в этой заметке. Модуль работает в связке с TT или HTML-Template, и кажется, он работает даже с Mason.
Итак, для наглядности создадим небольшую форму для обратной связи с помощью данного модуля. Будем использовать HTML-Template для обработки шаблонов (при этом нам не надо отдельно загружать данный модуль, CGI-FormBuilder будет использовать его абсолютно прозрачно для пользователя).
Создание формы мы начнем от обратного, то есть не с описания шаблона формы, а с программирования формы, пусть вам это не кажется странным, ведь в заметке я хочу в первую очередь показать, как работать с модулем из кода Perl, хотя и работу с шаблонами мы также рассмотрим.
11 my $form = CGI::FormBuilder->new(
12 source => './feedback.fb',
13 messages => './messages.ru',
14 template => './feedback.html',
15 title => 'Форма обратной связи',
16 );
Создаем объект для работы с формой. Рассмотрим опции переданные в конструктор new.
Source - указывает путь к файлу-шаблону формы
Message - указывает путь к файлу-шаблону для сообщений JavaScript, которые выводятся при проверке формы на валидность (по умолчанию модуль выводит сообщения на английском языке, и если вам нужна локализация - указываете нужный файл, о его формате я расскажу позже)
Template - указывает путь к файлу-шаблону HTML-Template
Title - это уже один из параметров для шаблона HTML-Template
Теперь напишем небольшой блок условий, для обработки добавленной формы:
20 if ($form->submitted && $form->validate) {
21 $form->title('Успешно добавлено');
22 $in{name} = $form->field('name');
23 $form->tmpl_param(user => $in{name});
24 print $form->confirm template => './success.htm');
25 }
26 else {
27 print $form->render(sticky => 1);
28 }
Методы CGI-FormBuilder submitted и validate возвращают true, если форма отправлена и прошла проверку, в противном случае возвращаем форму. Параметр sticky => 1 позволяет сохранить уже введенные пользователем данные и не очищать форму («приклеивает» значения формы).
Итак, если форма добавлена, мы перезаписываем title страницы с информацией типа «Успешно добавлено». Затем получаем из формы значение поля name, для этого используется модуль CGI. (NB: модуль предполагает использование CGI.pm для работы с входными/выходными данными, в данном случае я использую его так: use CGI qw (param header)).
Вот собственно и весь код по отображению формы. Теперь перейдем к написанию шаблонов.
Начнем с шаблона формы feedback.fb
# метод пост, заголовок не отправлять
method: POST
header: 0
# define fields
fields:
# имя
name:
label: Ваше имя
# type: text по умолчанию
size: 30
style: background:#FFF39C;text-align:right;
required: 1
# E-MAIL
email:
label: Эл. почта
size: 30
validate: EMAIL
style: background:#FFF39C;text-align:right;
required: 1
# сайт
domain:
label: Ваш сайт
size: 30
validate: /^.+\.ru/
style: background:#FFF39C;text-align:right;
required: 1
# сообщение
message
label: Сообщение
type: textarea
rows: 5
cols: 50
style: background:#FFF39C;text-align:right;
required: 1
# Кнопка сабмита
submit: Отправить вопрос
Язык описания шаблона формы - YAML, довольно простой и удобный, для интересующихся отправляю на википедию. Несколько пояснений:
- LABEL необходим для того чтобы JavaScript при генерации ошибок выдавал не имя формы из HTML (тэг name), а что-то человекопонятное.
- TYPE - по умолчанию text, для типа select можно передавать ссылку на массив в опции options
type: select
options: \&return_sources
При этом опция options: принимает ссылку на функцию, которая и возвращает нужный формат данных (return_sources - обычная функция описанная в теле основного скрипта, и не вызываемая оттуда, а просто описанная там в блоке sub {} )
- REQUIRED - опция принимает 0 или 1, и определяет является ли поле обязательным к заполнению
- STYLE - custom стиль для элемента
- VALIDATE - проверка для поля, поддерживает уже предопределенные регэкспы типа: EMAIL, PHONE, INT и т.п., а также custom регэкспы (никак не отвяжусь от этого custom...)
Опции также предусматривают custom JavaScript, То есть написанный прямо в этом файле в опциях конкретного поля.
Думаю, достаточно о шаблонах для формы, теперь к шаблону HTML.
Шаблон почти полностью повторяет стиль HTML-Template, только для того чтобы прописать где будет у нас находиться конкретное поле (тэг input) пишем:
<td height=30> <b>Ваш email: *</b></td>
<td bgcolor=#ffffff> <tmpl_var field-email></td>
Для того чтобы определить границы формы (тэги <form> и </form>) используем:
<tmpl_var form-start> и <tmpl_var form-end>, соответственно.
Для того чтобы модуль CGI-FormBuilder генерил JS код, необходимо в тэгах <head></head> вставить:
<tmpl_var js-head>
Вот собственно и все.
Шаблон для custom-сообщений JS (messages.ru) выглядит так:
#
# messages.ru - messages for Russian
#
js_invalid_start Обнаружено %s ошибок:
js_invalid_default - Поле "%s" заполнено неверно
js_invalid_input - Поле "%s" заполнено неверно
js_invalid_end For more help, click the "Help" button
form_invalid_text Форма заполнена неверно или с ошибками!
js_invalid_select - Не выбрана опция "%s" из списка
js_invalid_textarea - Не заполнено поле "%s"
# - Это комментарии, а дальше просто описаны события и значения для них на русском. Не буду подробно расписывать эти события, я думаю вы без труда отыщите и не описанные мной.
Итак - наша форма готова и работает:
Весь код описанный в заметке лежит здесь.
Резюме:
В итоге мы получили очень правильно структурированный проект (может слишком громко для такого примера, но кто сталкивался в практике - тот поймет). Если нам необходимо изменить длину какого-то поля, его тип, или вставить новое поле - достаточно внести изменения либо в один файл шаблон формы, либо в шаблон формы и шаблон html (в зависимости от глобальности изменений). В любом случае - проект очень ясный и легко читаемый, с ним удобно работать и развивать.



Интересно, обязательно прочитая вдумчиво еще раз. На мой взгляд пока из того что я видел мне больше врего пока нравится HTML::FormHandler в плане гибкости и того, что мне требовалось.
Незнаю насчет HTML::FormHandler, но то что я увидел в exampl'ах на спан по этому модулю - на мой взгляд определение формы там внесено в код, в отличие от CGI-FormBuilder, где оно вынесено в шаблон. Хотя я не работал с этим модулем, и могу ошибаться неверно истолковав примеры, или они просто не слишком удачные.
Все верно. Формы действительно описываются кодом, за счет этого получается очень гибко. А так как это Moose, то это уже не выглядит как каша. Плюс более гибкое разделение представления, валидности и ренденигна. Конечно это все выглядит громоздко, но с другой стороны возможность все это крутить под себя уж сильно манит.
Меня лично всегда пугала громоздкость таких решений как Catalyst, Moose и т.п. Если описание формы в коде - то разделение представления от контроллера уже менее гибкое.
Если пугает Moose, значит Perl6 заставит вас побороть эти фобии.
В случае HFH при описании используется syntactic sugar - по сути это тоже что и в FB только получаете все плюсы Moose. Если подвести итог, то можно сказать: Если решение позволяет вам реализовать ваши потребности, то это хорошее решение и за модой бежать не нужно.