您的位置:首页 > 其它

Drupal 模块开发实例之一:表单的…

2012-11-29 14:20 218 查看
表单是网站最重要的组成部分,以用户交互为主的站点,表单几乎无处不在。所以,表单的生成、验证、提交,也是程序中很重要的部分,成熟的程序,几乎都有自成体系的表单机制。drupal
也不例外。drupal 的表单系统相当强大,可以让程序员不写任何 html
代码,完成表单的生成、验证、提交、入库等一系列流程。在模块开发中,几乎都会和表单打交道。

这篇教程是 drupal 表单的基本应用实例,涉及表单的定义、验证、提交等基本环节。

本系列教程,都以 drupal 6 为基础,以模块为载体,每篇教程即为一个模块,以后不再做特殊说明。

web
表单交互的基本流程大致是:用户访问某个页面,输出表单界面,用户填写表单,提交,程序验证,通过验证或让用户重新填写。流程基本固定,但实现的方式有许多种,在
drupal 中,这整个流程均可以在模块中完成,甚至不用写一行 html 代码。下面开始创建模块。

模块名称:myform。模块名称根据需要自定义,一般来说,不与现有的第三方模块重名。这个模块我们命名为:myform。

实现功能:定义一个页面,生成一个表单,让所有可以提交信息。

权限设置:不做权限验证,所有人均可提交。本教程重点在表单的基本应用,权限部分留待以后。

以下是详细步骤:

第一步:定义模块信息,添加模块信息文件:myform.info

查看代码

打印代码?

1
// $Id$
2
name =
myform
3
description =
用户反馈表单
4
core =

"6.x"
第二步:创建数据表,添加模块安装文件:myform.install

1、实现 hook_schema,drupal
为了实现多种数据库的兼容,有自成体系的数据库抽象层,包括创建表、增删查,均有详细接口。此部分留待后文讲述。

查看代码

打印代码?

01
04
function

myform_schema() {
05
$schema
[
'myform'
] =

array
(
06
'description'

=>
'反馈表单字段'
,
07
'fields'

=>
array
(
08
'id'

=>
array
(
09
'type'

=>
'serial'
,
10
'unsigned'

=> true,
11
'not
null'
=>
true,
12
'description'

=>
'自增主键'
13
),
14
'title'

=>
array
(
15
'type'

=>
'varchar'
,
16
'length'

=> 255,
17
'not
null'
=>
true,
18
'default'

=>
''
,
19
'description'

=>
'标题'
,
20
),
21
'name'

=>
array
(
22
'type'

=>
'varchar'
,
23
'length'

=> 64,
24
'not
null'
=>
true,
25
'default'

=>
''
,
26
'description'

=>
'昵称'
,
27
),
28
'mail'

=>
array
(
29
'type'

=>
'varchar'
,
30
'length'

=> 255,
31
'not
null'
=>
true,
32
'default'

=>
''
,
33
'description'

=>
'邮件'
,
34
),
35
'timestamp'

=>
array
(
36
'type'

=>
'int'
,
37
'not
null'
=>
true,
38
'default'

=> 0,
39
'description'

=>
'留言时间'
40
),
41
'body'

=>
array
(
42
'description'

=>
'留言内容'
,
43
'type'

=>
'text'
,
44
'not
null'
=>
false,
45
'size'

=>
'big'
,
46
'serialize'

=> true
47
),
48
),
49
'indexes'

=>
array
(
50
'timestamp'

=>
array
(
'timestamp'
),
51
),
52
'primary
key'
=>

array
(
'id'
),
53
);
54
return
$schema
;
55
}
2、实现 hook_install。在模块被安装时,将调用此钩子。通常,若以 hook_schema 定义了数据表结构,将使用
drupal_install_schema 来完成安装。同时,可以在 hook_install
进行其它操作,比如写入一些默认数据等。

查看代码

打印代码?

1
4
function

myform_install() {
5
drupal_install_schema(
'myform'
);
6
}
3、实现 hook_uninstall。在模块卸载时,将调用此钩子。这并不是必须的,但推荐实现,若你的模块创建了数据表,可调用
drupal_uninstall_schema 删除表。注意:用户禁用模块,并不会调用此钩子。

查看代码

打印代码?

1
4
function

myform_uninstall() {
5
drupal_uninstall_schema(
'myform'
);
6
}
第三步:创建模块主文件,添加模块主文件:myform.module

根据我们的需要,需要定义一个页面,使用 hook_menu 完成。drupal 是一个单入口程序,所有请求均由 index.php
解析分发,hook_menu 定义的路径,实际上就相当于
$_GET['q'],即:index.php?q={path}。用户发起访问请求,系统判断请求路径由哪个模块定义,根据最大匹配原则,找到最接近的定义者。

比如:用户请求的路径为:test/abcd,匹配的顺序大致如:test/abcd -> test/%
-> test。如以上三个路径都没有被定义,则返回错误,无法找到页面。以下是本模块需要定义路径。
hook_menu 将被写入数据库 menu 表中,并被缓存,所以,有任何关于 hook_menu
的改动,建议先清除缓存。

注意:如果两个模块定义了相同的路径,将根据 weight 来决定使用谁的配置。

hook_menu 是一个相当重要的钩子,几乎每个模块都要用到,但不是本篇教程的重点,只做以上简单介绍。

查看代码

打印代码?

01
04
function

myform_menu() {
05
$item
=

array
();
06
 
07
$item
[
'myform'
] =

array
(
08
'description'

=>
'用户反馈'
,
09
'page
callback'
=>

'drupal_get_form'
,
10
'page
arguments'
=>

array
(
'myform_page_form'
),
11
'access
callback'
=>
true,
12
'file'

=>
'myform.page.inc'
,
13
'type'

=>
MENU_CALLBACK,
14
);
15
 
16
return
$item
;
17
}
第四步:创建表单,创建文件:myform.page.inc

为什么要将表单代码写在另一个文件呢?drupal
在每次初始化时,将加载每个模块的主文件(如:myform.module),我们可以把只在特定路径使用到的代码,写在另一个文件里,减少主模块文件的大小,以加速系统运行。当然,这所带来的效率提升可能是微乎其微,甚至没有,但养成这个习惯也不是坏事,另外这也让模块的文件结构更清晰,易于维护。

根据 hook_menu 里的定义,drupal_get_form
是页面回调函数,相当于:drupal_get_form('myform_page_form')。我们只需要按规定格式定义表单,然后调用
drupal_get_form,便能得 html 代码,输出到页面即可。

在 myform.page.inc 中创建表单函数:myform_page_form。

查看代码

打印代码?

1
5
function

myform_page_form(&
$form_state
)
{
6
}
这儿有一个参数: &$form_state,这是 drupal_get_form
自动传递的,其中包含表单 id、token 等信息,若处于验证或提交环节,包含所有用户输入值,即 $_POST。使用
drupal_get_form 也可以传递自定义参数,比如:drupal_get_form('myform_page_form',
$test),那么 myform_page_form 函数则要这样:

查看代码

打印代码?

1
7
function

myform_page_form(&
$form_state
,

$test
)
{
8
}
此处不做深入讨论,回到本教程,创建表单的全部代码如下:

查看代码

打印代码?

01
05
function

myform_page_form(&
$form_state
)
{
06
 
07
$form
[
'title'
] =

array
(
08
'#title'

=>
'主题'
,

// 字段名称
09
'#type'

=>
'textfield'
,

// 字段类型,此处为单行文本
10
'#required'

=> true,
// 是否必填
11
'#default_value'

=>
''
,
// 默认值,可选
12
);
13
 
14
$form
[
'name'
] =

array
(
15
'#title'

=>
'昵称'
,
16
'#type'

=>
'textfield'
,
17
'#required'

=> true,
18
'#description'

=>
'请输入您的昵称,不低于 2 个字符'
19
);
20
 
21
$form
[
'mail'
] =

array
(
22
'#title'

=>
'邮件'
,
23
'#type'

=>
'textfield'
,
24
'#required'

=> true,
25
'#description'

=>
'请输入您的常用邮件,便于我们联系您'
26
);
27
 
28
$form
[
'body'
] =

array
(
29
'#title'

=>
'内容'
,
30
'#type'

=>
'textarea'
,

// 多行文本
31
'#required'

=> true,
32
);
33
 
34
41
$form
[
'#validate'
] =

array
(
'myform_page_form_validate'
);
42
 
43
50
$form
[
'submit'
] =

array
(
51
'#type'

=>
'submit'
,

// 提交按钮
52
'#value'

=>
'确认提交'
,

// 按钮值
53
'#submit'

=>
array
(
'myform_page_form_submit'
),
//
提交函数
54
);
55
 
56
return
$form
;
57
}
接下来是表单验证函数。刚接触 drupal 的朋友可能有这个疑惑,drupal
为什么要把表单的验证和提交环节分开呢,这不是影响效率吗,验证完毕不是可以直接做入库等提交操作吗?实际上,这是为了让表单机制更灵活,假设验证和提交环节不分开,某个模块定义了表单,其它模块也想要验证这个表单,怎么办?验证和提交分离,其它模块可以轻松的通过
hook_form_alter
添加一个验证函数,在该函数中,可阻止表单提交。国内很多程序,均不考虑这些需要,所以,如果要进行二次开发,只有在源代码上进行修改,缺乏灵活性。myform_page_form
表单的验证函数代码如下:

查看代码

打印代码?

01
08
function

myform_page_form_validate(&
$form
,
&
$form_state
)
{
09
 
10
15
if
(drupal_strlen(
$form_state
[
'values'
][
'name'
])
< 2) {
16
20
form_set_error(
'name'
,

'昵称不能少于 2 个字符'
);
21
}
else

if
(drupal_strlen(
$form_state
[
'values'
][
'title'
])
> 255) {
22
form_set_error(
'title'
,

'标题长度不能大于 255 个字符'
);
23
}
24
 
25
// 如验证通过,将进入表单提交环节
26
}
以上只验证了长度是否合法,实际应用中,可能还需要验证电子邮件是否合法等。验证通过后,进行提交环节,代码如下:

查看代码

打印代码?

01
06
function

myform_page_form_submit(&
$form
,
&
$form_state
)
{
07
10
db_query("INSERT INTO {myform} (id, title, name, mail,
timestamp, body)
11
VALUES (null,
'%s'
,

'%s'
,
'%s'
, %d,

'%s'
)",
$form_state
[
'values'
][
'title'
],
12
$form_state
[
'values'
][
'name'
],

$form_state
[
'values'
][
'mail'
],
13
$_SERVER
[
'REQUEST_TIME'
],

$form_state
[
'values'
][
'body'
]);
14
 
15
// 获取上一条 insert sql 返回的主键,以此判断是否执行成功
16
if
(db_last_insert_id(
'myform'
,

'id'
))
{
17
 
18
22
drupal_set_message(
'感谢您,反馈已经提交,我们将尽快和您取得联系'
);
23
 
24
//
如果想将用户重定向到一个页面,可修改 $form['#redirect'] 值,如:
25
 
26
$form
[
'#redirect'
]
=
'test/abcde'
;
27
 
28
32
 
33
}
else

{
34
 
35
//
数据写入失败了
36
drupal_set_message(
'抱歉,遇到问题,提交失败了'
,

'error'
);
37
 
38
}
39
 
40
}
表单成功写入数据库,整个表单的流程就走完了。很简单吧?因为规则不熟悉,可能不明白为什么要这样写,实际上,刚开始做模块开发,只需要知道要这样即可以,不必深究为什么要这样。倘若先拿一本书,务必把每个术语搞清楚,理解透彻,没有实际开发经验,我想还是比较困难的。好读书不求甚解,大概也是这个道理吧。做多了,自然就明白了,可能我是实践主义者。

以上就是本篇教程的全部内容,下一篇将继续研究表单,说说关于文件上传。

启用后,访问 http://www.mysite.com/?q=myform 即可提交表单。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: