Catalyst::Manual::Tutorial::09_AdvancedCRUD
学习笔记 (2010-8-28 星期六) -- 高阶 CRUD
文章来源:http://search.cpan.org/~hkclark/Catalyst-Manual-5.8004/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD.pod
概述
......
可用的高阶 CRUD
-
FormFu
-
FormHandler
-
FormBuilder
Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormFu 学习
|
本节内容来自:http://search.cpan.org/~hkclark/Catalyst-Manual-5.8004/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormFu.pod
概述
本节探索 HTML::FormFu ,用于管理表单,输入校验,通过数据库保存及回复数据。本章基于 HTML::FormFu 版本 0.05001。
HTML::FormFu 表单创建
从 Catalyst::Controller::HTML::FormFu 继承
首先, 修改文件 lib/MyApp/Controller/Books.pm ,改变继承关系,将如下:
BEGIN {extends 'Catalyst::Controller'; }
|
修改为:
BEGIN {extends 'Catalyst::Controller::HTML::FormFu'; }
|
记得修改 Makefile.PL :
requires 'Catalyst::Controller::HTML::FormFu';
|
添加 Action 用于显示和保存表单
编辑文件 lib/MyApp/Controller/Books.pm :
sub formfu_create :Chained('base') :PathPart('formfu_create') :Args(0) :FormConfig {
my ($self, $c) = @_;
my $form = $c->stash->{form};
if ($form->submitted_and_valid) {
# 创建一本书
my $book = $c->model('DB::Book')->new_result({});
# 保存表单中该书信息
$form->model->update($book);
# 为用户设置一条状态信息
$c->flash->{status_msg} = 'Book created';
# 返回书目列表页面
$c->response->redirect($c->uri_for($self->action_for('list')));
$c->detach;
} else {
# 从数据库获取作者信息
my @author_objs = $c->model("DB::Author")->all();
# 创建一个数组或数组引用,每个元素指向一个作者
my @authors;
foreach (sort {$a->last_name cmp $b->last_name} @author_objs) {
push(@authors, [$_->id, $_->last_name]);
}
# 从配置文件获取需要添加选择项的元素
my $select = $form->get_element({type => 'Select'});
# 将作者添加进去
$select->options(\@authors);
}
# 设置模板
$c->stash(template => 'books/formfu_create.tt2');
}
|
编写一个表单配置文件(Config File)
尽管 HTML::FormFu 支持 Config::Any 能识别的任意格式,但大多数人倾向于 YAML 格式。首先创建一个目录用于保存你的表单配置文件:
mkdir -p root/forms/books
|
创建文件 root/forms/books/formfu_create.yml :
---
# indicator is the field that is used to test for form submission
indicator: submit
# Start listing the form elements
elements:
# The first element will be a text field for the title
- type: Text
name: title
label: Title
# This is an optional 'mouse over' title pop-up
attributes:
title: Enter a book title here
# Another text field for the numeric rating
- type: Text
name: rating
label: Rating
attributes:
title: Enter a rating between 1 and 5 here
# Add a drop-down list for the author selection. Note that we will
# dynamically fill in all the authors from the controller but we
# could manually set items in the drop-list by adding this YAML code:
# options:
# - [ '1', 'Bastien' ]
# - [ '2', 'Nasseh' ]
- type: Select
name: authors
label: Author
# The submit button
- type: Submit
name: submit
value: Submit
|
注意: 从 perl 文档格式复制粘贴 YAML 文件比较麻烦。参考本章 "Config::General Config for this tutorial" 这一小节,介绍了一个绝不会出错的配置文件格式。
更新 CSS 文件
编辑 root/static/css/main.css ,文件末尾添加:
...
input {
display: block;
}
select {
display: block;
}
.submit {
padding-top: .5em;
display: block;
}
|
这些设置用于垂直排列显示表单元素。注意现存的 .error 类的定义关联到色彩方案设置,这个设置是由 TTSite helper 生成的 root/lib/config/col 文件定义的。这样就有一个切入点可以控制 CSS 色彩设定。
创建一个模板页面用于显示表单:
编辑文件 root/src/books/formfu_create.tt2 :
[% META title = 'Create/Update Book' %]
[%# Render the HTML::FormFu Form %]
[% form %]
<p><a href="[% c.uri_for(c.controller.action_for('list'))
%]">Return to book list</a></p>
|
创建一个链接 for Create and Update via HTML::FormFu
编辑 root/src/books/list.tt2 ,在文件底部添加:
...
<p>
HTML::FormFu:
<a href="[% c.uri_for(c.controller.action_for('formfu_create')) %]">Create</a>
</p>
|
这样就在书目列表页面底部添加了一个新的链接,可以通过这个链接调用基于 HTML::FormFu 的表单。
测试 HTML::FormFu 添加书目的表单
使用 -r 参数启动服务:
$ script/myapp_server.pl -r
|
以用户 test01(密码:mypass)登录。进入书目列表页面后,点击表单底部的 HTML::FormFu "Create" 链接,输入以下内容:
Title: Internetworking with TCP/IP Vol. II
Rating: 4
Author: Comer
|
点击提交按钮,然后返回到书目列表页面,你会看到 "Book created" 状态信息。
以上实现方式允许你输入任何乱七八糟的数据。尽管说我们通过下拉选择列表对作者一栏的录入进行了约束(其实对于侵略性的用户,依然可以通过"hacking"手段录入任何数值,这个防护并不严密),但是对于其他栏目并没有限制,比如标题栏没有限定长度(你甚至可以录入只有一个字母的书目),投票栏也没有限定类型(你可以输入数字,也可以输入非数字字符)。接下来的章节我们进行讨论。
注意: 依赖于你所使用的数据库,以及表中所建立的字段,数据库提供了一种直观的不同水平层级的数据 "类型约束"。前面章节一再强调了一个重要观点,web 应用程序本身不能进行任何数据校验。
HTML::FormFu 数据校验及过滤
虽说前面部分的 HTML::FormFu 的示例演示了一种很好的自动创建表单的机制,但是这个模块的真正威力在于对用户输入数据的自动校验及过滤。校验约束可以保证用户输入适当的数据(比如说表单的 email 一栏就需要合法的 email 地址)。过滤机制可以滤掉输入信息中的空白字符,或者对元字符进行转义处理。
Add Constraints
编辑 root/forms/books/formfu_create.yml :
---
# indicator 域是用来测试表单提交
indicator: submit
# 列出表单所有元素
elements:
# 第一个元素是文本类型的 title 域
- type: Text
name: title
label: Title
# 此项可选,定义鼠标滑过时的 title 提示信息
attributes:
title: Enter a book title here
# 添加此域的约束
constraints:
# 定义长度必须为 5-40 个字符
- type: Length
min: 5
max: 40
# 重新定义无效输入时的提示信息
message: Length must be between 5 and 40 characters
# 定义一个文本域,用于输入 rating 数字
- type: Text
name: rating
label: Rating
attributes:
title: Enter a rating between 1 and 5 here
# Use Filter to clean up the input data
# Could use 'NonNumeric' below, but since Filters apply *before*
# constraints, it would conflict with the 'Integer' constraint below.
# So let's skip this and just use the constraint.
#filter:
# Remove everything except digits
#- NonNumeric
# Add constraints to the field
constraints:
# 确保输入为一个数字
- type: Integer
message: "Required. Digits only, please."
# 检查最大、最小值
- type: Range
min: 1
max: 5
message: "Must be between 1 and 5."
# 这里设定 author 选择列表,由于我们从 controller 直接获取 authors 列表添加进来
# 因此就不用手工添加如下 YAML 代码:
# options:
# - [ '1', 'Bastien' ]
# - [ '2', 'Nasseh' ]
- type: Select
name: authors
label: Author
# Convert the drop-down to a multi-select list
multiple: 1
# Display 3 entries (user can scroll to see others)
size: 3
# One could argue we don't need to do filters or constraints for
# a select list, but it's smart to do validation and sanity
# checks on this data in case a user "hacks" the input
# Add constraints to the field
constraints:
# Make sure it's a number
- Integer
# The submit button
- type: Submit
name: submit
value: Submit
# Global filters and constraints.
constraints:
# The user cannot leave any fields blank
- Required
# If not all fields are required, move the Required constraint to the
# fields that are
filter:
# Remove whitespace at both ends
- TrimEdges
# Escape HTML characters for safety
- HTMLEscape
|
狗日的服务器,本来这章还有 FormHandler 都写完了,编辑好的一大段文字都凭空消失了,不写了。
。。。。