作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
定义好表单以后,通常接下来的工作就是为表单添加验证函数,用来检查用户的输入,让我们在代码中添加验证函数对应的代码:
/**
* contactus_form表单的验证函数
*/
function contactus_form_validate($form, &$form_state){
//这里使用正则表达式,来验证邮箱的有效性,注意,这里的正则表达式,包围在"/...../"之间。
if(!preg_match("/^[\w\-\.]+@[\w\-\.]+(\.\w+)+$/", $form_state['values']['mail'])){
form_set_error('mail',t('您输入的电子邮件地址格式不正确'));
}
}
在这里,对于用户的输入,我们只对电子邮件字段进行了检查。如果我们在电子邮件输入框中输入了非法的电子邮件,比如:
那么当我们提交表单时,系统就会给出错误提示:
通过上面的例子,我们可以看出,form_set_error的第一个参数,对应于表单元素的ID,第二个参数为显示给用户的错误提示。
在我们的这个默认的验证函数中,我们可以为所有的表单元素添加验证规则,因此在一般情况下,一个默认的验证函数就足够了。当然,我们可以使用#validate属性,为表单添加一组验证。我们在用户系统一章,讲到的用户登录表单,就用到了#validate属性。此外,对于单个的表单元素,我们也可以为其设置验证函数,这和表单的验证函数类似,不过需要使用表单元素的#element_validate属性。
如果我们在验证函数做了大量的处理,而你又想把结果保存下来,供后面的提交函数使用,此时有两种不同的实现方式。一是使用form_set_value(),二是使用$form_state。我们来看一下$form_state的这种方式,这种方式我用到过:
由于$form_state在验证和提交函数中都是通过引用传递的,所以在验证函数中,可以将数值存储在这里,而在提交函数中,就可以使用它了。最好在$form_state中加上你模块的命名空间,这样有利于避免命名冲突。
在实际的工作中,我就用到过这一点,在一个模块的验证函数中,我需要从远程获取一个图书的ID号,这个操作由于调用的是web service,所以比较耗费资源,而在提交处理函数中,我需要使用这个ID号。
//通过调用web service获取图书的唯一ID
$book_id = my_module_get_book_id_by_service($bsno);
//我们将在验证中获取的值保存起来,这样在提交函数中可以使用。
$form_state['my_module']['book_id'] = $book_id;
接着,在提交函数中,我这样访问该数据:
$book_id = $form_state['my_module']['book_id'];
表单完全通过验证后,接下来我们需要对通过表单提交的数据进行处理。让我们为表单添加对应的提交处理函数。
/**
* contactus_form表单的提交函数
*/
function contactus_form_submit($form, &$form_state){
//把表单的值存放在会话中去,由于这里涉及到了两个不同的表单之间传值。
$_SESSION['contactus_form'] = $form_state['values'];
//表单重定向到确认页面
$form_state['redirect'] = 'contactus/confirm';
}
在我们的这个处理函数,逻辑相当简单,我们仅仅把表单的提交值,保存到了会话信息中。然后将表单重定向到了确认页面。如果我们不修改$form_state['redirect']的话,表单提交后,仍然会回到当前表单所在的页面。另外,这里最好不要使用drupal_goto,尽量使用$form_state['redirect']的方式。如果存在多个提交处理函数的话,你使用了drupal_goto,那么接下来的提交处理函数可能就被跳过了。如果我们有多个提交处理函数,每个函数中都设置了$form_state['redirect'],那么最后起作用的应该是最后设置的那个。
在两个表单页面之间传值,可以通过URL,也可以先将值保存到数据库中,然后再读取。我们这里用到的会话方式,本质上就是使用的后一种方式。刚学Drupal的时候,对这一点还不是很熟悉,总以为不应该向会话信息中保存太多信息,Java中就是这样,但是Drupal与Java不同,这里的会话信息会保存在数据库中,而不是停留在内存中供下次调用。