我们没有直接输出HTML,而是创建了一个数组并让引擎生成HTML。

由于我们将表单的表示作为结构化的数据进行处理,所以我们可以添加、删除、重新排序、和修改表单。当你想用一种干净利索的方式对其它模块创建的表单进行修改时,这会特别方便。

任意的表单元素可以映射到任意的主题函数上。

可以将额外的表单验证或处理函数添加到任意表单上。

对表单操作进行了保护,从而防止表单注入攻击,比如当用户修改了表单并接着试图提交它时。

使用表单的学习曲线有点高.

 

Drupal专业开发指南-表单_表单

理解表单处理流程:

Drupal的表单引擎负责为要显示的表单生成HTML,并使用三个阶段来安全的处理提交了的表单:验证、提交、重定向。


流程初始化

在处理表单时,有3个变量非常重要。第一个就是$form_id,它包含了一个标识表单的字符串。第二个就是$form,它是一个描述表单的结构化数组。而第三个就是$form_state,它包含了表单的相关信息,比如表单的值以及当表单处理完成时应该发生什么。drupal_get_form()在开始时,首先会初始化$form_state。

设置一个令牌(token)

表单系统的一个优点是,它尽力的去保证被提交的表单就是Drupal实际创建的,这主要是为了安全性和防止垃圾信息或潜在的站点攻击者。为了实现这一点,Drupal为每个Drupal安装都设置了一个私钥。这个私钥是在安装流程期间随机生成的,它能将这个特定的Drupal安装与其它的Drupal区别开来。一旦私钥生成后,它将作为drupal_private_key存储在variables表中。Drupal将基于私钥生成一个随机的令牌,而该令牌将作为隐藏域发送到表单中。当表单提交时,会对令牌进行测试。相关背景信息请参看drupal.org/node/28420。令牌仅用于登录用户,因为匿名用户的页面通常会被缓存起来,这样它们就没有唯一的令牌了。

设置一个ID

一个包含了当前表单ID的隐藏域,将作为表单的一部分被发送给浏览器。该ID一般对应于定义表单的函数,它将作为drupal_get_form()的第一个参数传递过来。例如函数user_register()定义了用户注册表单,它的调用方式如下:

$output = drupal_get_form('user_register');


收集所有可能的表单元素定义:

接着,调用element_info()。它将调用所有实现了hook_elements()的模块上的这个钩子函数。在Drupal核心中,标准的元素,比如单选按钮和复选框,都定义在modules/system/system.module中的hook_elements()实现中(参看system_elements())。如果模块需要定义它们自己的元素类型,那么就需要实现这个钩子。在以下几种情况中,你可能需要在你的模块中实现hook_elements():你想要一个特殊类型的表单元素时,比如一个图像上传按钮,在节点预览期间可用来显示缩略图;或者,你想通过定义更多的属性来扩展已有的表单元素时。

钩子element_info()为所有的表单元素收集所有的默认属性,并将其保存到一个本地缓存中。在进入下一步----为表单寻找一个验证器----以前,对于那些在表单定义中尚未出现的任何默认属性,都将在这里被添加进来。


寻找一个验证函数:

通过将表单的属性#validate设置为一个数组,其中函数名为为值,从而为表单分配一个验证函数。在调用验证函数时,后面的数组中的任何数据都将被传递给验证函数。可以使用下面的方式来定义多个验证器:

// We want foo_validate() and bar_validate() to be called during form validation.
$form['#validate'][] = 'foo_validate';
$form['#validate'][] = 'bar_validate';

如果表单中没有定义属性#validate,那么接下来就要寻找名为“表单ID”+“_validate”的函数。所以,如果表单ID为user_register,那么表单的#validate属性将被设置为user_register_validate。


寻找一个提交函数:

通过将表单的#submit属性设置为一个数组,其中以函数名为键/值,这里的函数名就是用来处理表单提交的函数的名字,从而为表单分配一个提交函数:

// Call my_special_submit_function() on form submission.
$form['#submit'][] = 'my_special_submit_function';
// Also call my_second_submit_function().
$form['#submit'][] = 'my_second_submit_function';

如果表单没有名为#submit的属性,那么接下来就要寻找名为“表单ID”+“_submit”的函数。所以,如果表单ID为user_register,那么Drupal将把#submit属性设置为它所找到的表单处理器函数;也就是user_register_submit。


允许模块在表单构建以前修改表单

在构建表单以前,模块有两个可以修改表单的机会。模块可以实现一个名字源于form_id + _alter的函数,或者可以简单的实现hook_form_alter()。任何模块,只要实现了这两个钩子中的任意一个,那么就可以修改表单中的任何东西。对于由第3方模块创建的表单,我们主要可以使用这种方式对其进行修改、覆写、混合。

构建表单

现在表单被传递给了form_builder(),这个函数将对表单树进行递归处理,并为其添加标准的必须值。这个函数还将检查每个元素的#access键,如果该元素的#access为FALSE,那么将拒绝对该表单元素及其子元素的访问。

允许函数在表单构建后修改表单

函数form_builder()每次遇到$form树中的一个新分支时(例如,一个新的字段集或表单元素),它都寻找一个名为#after_build的可选属性。这是一个可选的数组,里面包含了当前表单元素被构建后会立即调用的函数。当整个表单被构建后,最后将调用可选属性$form[‘#after_build’]中定义的函数。$form和$form_state将作为参数传递给所有的#after_build函数。Drupal核心中有一个实际例子,那就是在“管理➤站点配置➤文件系统”中,文件系统路径的显示。这里使用了一个#after_build函数(在这里就是system_check_directory()),用来判定目录是否存在或者是否可写,如果不存在或不可写,那么将为该表单元素设置一个错误消息。

检查表单是否已被提交

如果你是按照流程往下走的话,那么你将看到我们现在来到了一个分叉点。如果表单是初次显示的话,那么Drupal将会为其创建HTML。如果表单正被提交的话,那么Drupal将处理在表单中所输入的数据;我们稍后将会讨论这一点(参看后面的“验证表单”一节)。现在,我们将假定表单是初次显示。有一点非常重要,那就是不管表单是初次显示,还是正被提交,在此以前,它所走过的流程是一样的。

为表单查找一个主题函数

如果$form['#theme']已被设置为了一个已有函数,那么Drupal将简单的使用该函数来负责表单的主题化。如果没有设置,那么主题注册表将查找一个对应于这个表单的表单ID的条目。如果存在这样的一个条目,那么就会将表单ID分配给$form['#theme'],在后面,当Drupal呈现表单时,它将基于表单ID来寻找主题函数。例如,如果表单ID为taxonomy_overview_terms,那么Drupal将调用对应的主题函数theme_taxonomy_overview_terms()。当然,可以在自定义主题中,使用主题函数或者模板文件来覆写这个主题函数。

允许模块在表单呈现以前修改表单

最后剩下的一件事,就是将表单从结构化的数据转化为HTML。但是在这以前,模块还有最后一个机会来调整表单。对于跨页面表单向导,或者需要在最后时刻修改表单的其它方式,这将会非常有用。此时将会调用$form['#pre_render']属性定义的任何函数,并将正被呈现的表单传递给这些函数。


呈现表单:

为了将表单树从一个嵌套数组转化为HTML代码,表单构建器调用drupal_render()。这个递归函数将会遍历表单树的每个层次,对于每个层次,它将执行以下动作:

1. 判定是否定义了#children属性(这句话就是说,是否已经为该元素生成内容了);如果没有,那么按照以下步骤来呈现这个树节点的孩子:

• 判定是否为这个元素定义了一个#theme函数。

• 如果定义了,那么将这个元素的#type临时设置为markup(标识字体)。接着,将这个元素传递给主题函数,并将该元素重置为原来的样子。

• 如果没有生成内容(可能是因为没有为这个元素定义#theme函数,或者因为调用的#theme函数在主题注册表中不存在,或者因为调用的#theme函数没有返回东西),那么逐个呈现这个元素的子元素(也就是,将子元素传递给drupal_render())。

• 另一方面,如果#theme函数生成了内容,那么将内容存储在这个元素的#children属性中。

2. 如果表单元素本身还没有被呈现出来,那么调用这个元素所属类型的默认主题函数。例如,如果这个元素是表单中的一个文本字段(也就是说,在表单定义中,它的#type属性被设置为了textfield),那么默认主题函数就是theme_textfield()。如果没有为这个元素设置#type属性,那么默认为markup。核心元素(比如文本字段)的默认主题函数位于includes/form.inc中。

3. 如果为这个元素生成了内容,并且在#post_render属性中找到了一个或多个函数名字,那么将分别调用这些函数,并将内容和该元素传递过去。

4. 在内容前面添#prefix,在后面追加#suffix,并将它从函数中返回。

这个递归迭代的作用就是为表单树的每个层次生成HTML。例如,一个表单了包含一个字段集,而字段集里面又包含两个字段,那么该字段集的#children属性将包含两个字段的HTML,而表单的#children属性将包含整个表单的HTML(其中包括字段集的HTML)。

生成的HTML将会返回给drupal_get_form()的调用者。这就是呈现表单所要做的全部工作!我们到达了流程中中的终点“返回HTML”。


验证表单:

我们在“检查表单是否已被提交”一节中所提到的分叉点。现在让我们假定表单已被提交并包含了一些数据;这样我们将沿着另一分支前进,看看这种情况是怎么样的。使用以下两点来判定一个表单已被提交:$_POST不为空,$_POST['form_id']中的字符串匹配刚被构建的表单定义中的ID。如果这两点都满足了,那么Drupal 将开始验证表单。

验证的目的是为了检查证被提交的数据的合理性。验证或者通过,或者失败。如果验证在某一点上失败了,那么将为用户重新显示这个表单,并带有错误消息。如果所有的验证都通过了,那么Drupal将对提交的数据进行实际的处理。

令牌验证

在验证中首先检查的是,该表单是否使用了Drupal的令牌机制。使用令牌的所有Drupal表单,都会有一个唯一的令牌,它和表单一起被发送给浏览器,并且应该和其它表单值一同被提交。如果提交的数据中的令牌与表单构建时设置的令牌不匹配,或者令牌不存在,那么验证将会失败(尽管验证的其余部分也会继续执行,这样其它验证错误也会被标识出来)。

内置验证

接着,检查必填字段,看用户有没有漏填的。检查带有#maxlength属性的字段,确保它没有超过最大字符数。检查带有选项的元素(复选框、单选按钮、下拉选择框),看所选的值是否是位于构建表单时所生成的原始选项列表中。

特定元素的验证

如果为单个表单元素定义了一个#validate属性,那么将会调用这个属性所定义的函数,并将$form_state和$element作为参数传递过去。

验证回调

最后,表单ID和表单值将被传递到表单的验证器函数中(函数名一般为:“表单ID”+ “_validate”)。


提交表单:

如果验证通过了,那么现在就应该把表单和它的值传递到一个函数中,该函数将做些实际的处理,以作为表单提交的结果。实际上,由于#submit属性可以包含一个数组,里面包含多个函数名字,所以可以使用多个函数来处理表单。调用数组中的每个函数,并向其传递参数$form和$form_state。


重定向:

用来处理表单的函数,应该把$form_state['redirect']设置为一个Drupal路径,比如node/1234,这样就可以将用户重定向到这个页面了。如果#submit属性中有多个函数,那么将会使用最后一个函数设置的$form_state['redirect']。如果没有函数把$form_state['redirect']设置为一个Drupal路径,那么用户将返回原来的页面(也就是,$_GET['q']的值)。在最后一个提交函数中返回FALSE,将会阻止重定向

通过在表单中定义#redirect属性,就可以覆写在提交函数中$form_state['redirect']设置的重定向了,比如

$form['#redirect'] = 'node/1'或$form['#redirect'] = array('node/1', $query_string, $named_anchor)

如果使用drupal_goto()中所用的参数术语,那么最后的一个例子将被改写为

$form['#redirect'] = array('node/1', $query, $fragment)

表单重定向的判定,是由includes/form.inc中的drupal_redirect_form()完成的。而实际的重定向则由drupal_goto()实现,它为Web服务器返回一个Location头部。 drupal_goto()的参数与后一个例子中的参数一致:drupal_goto($path = '', $query = NULL, $fragment = NULL)。


创建基本的表单: ....


表单属性:

属性和元素有哪些区别呢?最基本的区别就是,属性没有属性,而元素可以有属性。提交按钮就是一个元素的例子,而提交按钮的#type属性就是一个属性的例子。你一眼便可以认出属性,这是因为属性拥有前缀“#”。我们有时把属性称为键,因为它们拥有一个值,为了得到该值,你必须知道相应的键。一个初学者常见的错误就是忘记了前缀“#”,此时,无论是Drupal还是你自己,都会感到非常困惑。如果你看到了错误消息“Cannot use string offset as an array in form.inc”,那么十有八九就是你忘记了字符“#”。

属性是通用的,而有些则特定于一个元素,比如一个按钮。 例:

$form['#method'] = 'post';
$form['#action'] = 'http://example.com/?q=foo/bar';
$form['#attributes'] = array(
'enctype' => 'multipart/form-data',
'target' => 'name_of_target_frame'
);
$form['#prefix'] = '<div class="my-form-class">';
$form['#suffix'] = '</div>';

#method属性的默认值为post,它可以被忽略。表单API不支持get方法,该方法在Drupal中也不常用,这是因为通过Drupal的菜单路由机制可以很容易的自动解析路径中的参数。#action属性定义在system_elements(),默认值为函数request_uri()的结果。通常与显示表单的URL相同。


表单IDs:

drupal_get_form()的调用中,所用的就是ID.对于大多数表单,其ID的命名规则为:模块名字+一个表述该表单做什么的标识。

Drupal使用表单ID来决定表单的验证、提交、主题函数的默认名字.另外,Drupal使用表单ID作为基础来为该特定表单生成一个<form>标签中的HTML ID属性,这样在Drupal中所有的表单都有一个唯一的ID。通过设置#id属性,你可以覆写该ID:

$form['#id'] = 'my-special-css-identifier';

生成的HTML标签将会是这样的:

<form action="/path" "accept-charset="UTF-8" method="post"

id="my-special-css-identifier">


字段集:

属性#collapsible和#collapsed来使用Javascript让它可以伸缩。

属性#tree设为TRUE,你将得到一个嵌套的表单值数组。将属性#tree设为FALSE(默认情况),你将得到一个未嵌套的表单值数组。


主题化表单:


使用主题函数:

主题化表单的最灵活的方式,就是为表单或者表单元素使用一个特定的主题函数。首先,Drupal需要知道我们的模块将实现哪些主题函数。这可以通过hook_theme()来完成。拥有我们自己的主题函数的好处是,我们可以按照我们的意愿对变量$output进行解析、混合、添加等操作。


告诉Drupal使用哪个主题函数:

通过为一个表单声明#theme属性,你可以命令Drupal使用一个不匹配“‘theme_’+表单ID名字”格式的主题函数:

// Now our form will be themed by the function
// theme_formexample_alternate_nameform().
$form['#theme'] = 'formexample_alternate_nameform';

或者,你也可以让Drupal为一个表单元素使用一个专门的主题函数:

// Theme this fieldset element with theme_formexample_coloredfieldset().
$form['color'] = array(
'#title' => t('Color'),
'#type' => 'fieldset',
'#theme' => 'formexample_coloredfieldset'
);

注意,在前面的两种情况中,你在#theme属性中定义的函数必须是主题注册表中注册过的;也就是说,必须在一个hook_theme()实现中对其进行了声明。


使用hook_forms()声明验证和提交函数:

你想让许多不同的表单共用一个验证或者提交函数。这叫做代码复用,可以用hook_forms()将多个表单ID映射到验证和提交函数上。在Drupal取回表单时,它首先查找基于表单ID定义表单的函数(正因为这样,在我们的代码中,我们使用函数formexample_nameform())。如果找不到该函数,它将触发hook_forms(),该钩子函数在所有的模块中查找匹配的表单ID以进行回调。

主题、验证、提交函数的调用次序:

对于一个主题函数,假定你使用基于PHPTemplate的名为bluemarine的主题,并且你正在调用drupal_get_form('formexample_nameform')。然而,这还取决于你的hook_theme()实现。

首先,如果在表单定义中将$form['#theme']设置为了'foo':

1. themes/bluemarine/foo.tpl.php // Template file provided by theme.
2. formexample/foo.tpl.php // Template file provided by module.
3. bluemarine_foo() // Function provided theme.
4. phptemplate_foo() // Theme function provided by theme engine.
5. theme_foo() // 'theme_' plus the value of $form['#theme'].

然而,如果在表单定义中没有设置$form['#theme']:

1. themes/bluemarine/formexample-nameform.tpl.php // Template provided by theme.
2. formexample/formexample-nameform.tpl.php // Template file provided by module.
3. bluemarine_formexample_nameform() // Theme function provided by theme.
4. phptemplate_formexample_nameform() // Theme function provided by theme engine.
5. theme_formexample_nameform() // 'theme_' plus the form ID.

在验证期间,表单验证器的设置次序如下:

1. A function defined by $form['#validate']
2. formexample_nameform_validate // Form ID plus 'validate'.

当需要查找处理表单提交的函数时,查找的次序如下:

1. A function defined by $form['#submit']
2. formexample_nameform_submit // Form ID plus 'submit'.


编写一个验证函数:


从验证函数中传递数据:

如果你的验证函数做了大量的处理,而你又想把结果保存下来以供提交函数使用,那么有两种不同的方式。你可以使用form_set_value()或者使用$form_state。


针对表单元素的验证:

一般情况下,一个表单使用一个验证函数。但是也可以为单个表单元素设置一个验证函数,这和整个表单的验证函数一样。为了实现这一点,我们需要将元素的属性#element_validate设置为一个数组,其中包含了验证函数的名字。表单数据结构中该元素分支的一份完整拷贝,将被作为验证函数的第一个参数。在调用完所有表单元素的验证函数以后,仍需调用表单验证函数。提示 在你的表单元素未通过验证,你希望为它显示一条错误消息时,如果你知道表单元素的名字,那么使用form_set_error(),如果你拥有表单元素本身,那么使用form_error()。后者对前者做了简单封装。


表单重新构建:

在验证期间,你可能判定你没有从用户那里获取足够的信息。例如,你可能将表单数值放到一个文本分析引擎中进行检查,然后判定这一内容很有可能是垃圾信息。最后,你想重新显示表单(里面包含用户已输入的值),不过这次添加了一个CAPTCHA,用来证明这个用户不是一个机器人。通过在你的验证函数中设置$form_state['rebuild'],你就可以通知Drupal需要进行一次重构了.


编写提交函数:

提交函数是表单通过验证后负责实际的表单处理的函数。只有在表单验证完全通过,并且表单没有被标记为重新构建时,它才会执行。提交函数通常需要修改$form_state['redirect']。 如果你有多个函数用来处理表单提交,只有最后一个设置$form_state['redirect']的函数返才拥有最后的发言权。可以通过在表单中定义#redirect属性来覆写提交函数的重定向。通常使用hook_form_alter()来实现这一点。


使用hook_form_alter()修改表单:


使用drupal_execute()通过程序来提交表单:

drupal_execute($form_id, $form_state);


修改一个特定的表单:

如果有很多模块来修改表单,而每个表单都传递给所有的hook_form_alter()实现.然而可以通过根据表单ID构造一个函数并调用它。

函数的名字是这样构造的:modulename + 'form' + form ID + 'alter'

例如'formexample' + 'form' + 'user_login' + 'alter' 将生成 formexample_form_user_login_alter


添加到所有表单元素上的属性:

当表单构建器使用表单定义构建表单时,它需要保证每一个表单元素都要有一些默认设置。这些默认值在includes/form.inc的函数_element_info()中设置,但是可以被hook_elements()中的表单元素定义所覆写。

#description

该字符串属性将添加到所有表单元素上,默认为NULL。通过表单元素的主题函数来呈现它。例如,一个文本字段的描述呈现在textfield的下面。

#required

该布尔值属性将被添加到所有表单元素上,默认为FALSE。将它设为TRUE,如果表单被提交以后而字段未被完成时,Drupal内置的表单验证将抛出一个错误消息。还有,如果将它设为TRUE,那么就会为这个元素设置一个CSS类(参看includes/form.inc中的theme_form_element())

#tree

该布尔值属性将被添加到所有表单元素上,默认为FALSE。如果将它设为TRUE,表单提交后的$form_state['values']数组将会是嵌套的(而不是平坦的)。这将影响你访问提交数据的方式。(参看本章中的“字段集”部分)。

#post

该数组属性是原始$_POST数据的一个拷贝,它将被表单构建器添加到所有的表单元素上。这样,在#process 和 #after_build中定义的函数就可以基于#post的内容做出聪明的决定。

#parents

该数组属性将被添加到所有表单元素上,默认为一个空数组。它在表单构建器的内部使用,以标识表单树中的父元素。更多信息,参看http://drupal.org/node/48643。

#attributes

该数组属性将被添加到所有表单元素上,默认为一个空数组,但是主题函数一般会填充该数组。该数组中的成员将被作为HTML属性添加进来。例如$form['#attributes'] = array('enctype' => 'multipart/form-data')。


表单API属性:

当在你的表单构建函数中构建一个表单定义时,数组中的键用来声明表单的信息。在下面部分中列出了最常用的键。表单构建器可以自动添加一些键。

表单根部的属性

下面所列的属性是特定于表单根部的。换句话说,你可以设置$form['#programmed'] = TRUE,但是如果你设置$form['myfieldset']['mytextfield'] [#programmed'] = TRUE那么对表单构建器来说没有任何意义。

#parameters

该属性是一个数组,包含了传递给drupal_get_form()的原始参数。通过drupal_retrieve_form()可添加该属性。

#programmed

这是一个布尔值属性,用来指示一个表单是以程序的方式来提交的, 比如通过drupal_execute()。如果在表单处理前设置了属性#post,那么可以使用drupal_prepare_form()来设置该属性。

#build_id

该属性是一个字符串(MD5哈希)。#build_id用来标识一个特定的表单实例。它作为一个隐藏域放在表单中,通过使用drupal_prepare_form()来设置这个表单元素,如下所示:

$form['form_build_id'] = array(
'#type' => 'hidden',
'#value' => $form['#build_id'],
'#id' => $form['#build_id'],
'#name' => 'form_build_id',
);

#token

这个字符串(MD5哈希)是一个唯一的令牌,每个表单中都带有它,通过该令牌Drupal能够判定一个表单是一个实际的Drupal表单,而不是一个恶意用户修改后的。

#id

这个属性是一个由form_clean_id($form_id)生成的字符串,并且它是一个HTML ID属性。$form_id中的任何背对的括号对“][”,下划线“_”,或者空格’’都将被连字符替换,以生成一致的CSS ID。在Drupal的同一个页面中,该ID是唯一的.如果同一个ID出现两次(例如,同一个表单在一个页面显示了两次),那么就会在后面添加一个连字符和一个自增的整数,例如foo-form, foo-form-1, 和foo-form-2。

#action

这个字符串属性是HTML表单标签的动作属性。默认情况,它是request_uri()的返回值。

#method

这个字符串属性指的是表单的提交方法---通常为post。表单API是基于post方法构建的,它将不会处理使用GET方法提交的表单。关于GET 和POST的区别,可参看HTML规范。如果在某种情况下,你想尝试使用GET方法,那么你真正需要可能是Drupal的菜单API,而不是表单API。

#redirect

该属性可以是一个字符串或者一个数组。如果是一个字符串,那么它是在表单提交以后用户想要重定向到的Drupal路径。如果是一个数组,该数组将作为参数被传递给drupal_goto(),其中数组中的第一个元素应该是目标路径(这将允许向drupal_goto()传递额外的参数,比如一个查询字符串)。

#pre_render

该属性是一个数组,它包含了在表单呈现以前所要调用的函数。每个函数都被调用,并且#pre_render所在的元素将被作为参数传递过来。例如,设置$form['#pre_render'] = array('foo', 'bar') 将使Drupal先调用函数foo(&$form),然后调用bar(&$form)。如果#pre_render是设置在一个表单元素上的话,比如$form['mytextfield']['#pre_render'] = array('foo'),那么Drupal将调用foo(&$element),其中$element就是$form['mytextfield']。当你想在表单验证运行以后,呈现以前,使用钩子修改表单结构时,这个属性非常有用。如果想在验证以前修改表单,那么使用hook_form_alter()。

#post_render

该属性是一个数组,它包含了一组函数,这些函数可对刚被呈现的内容进行修改。如果你设置了$form['mytextfield']['#post_render'] = array('bar'),那么你可以这样修改刚创建的内容:

function bar($content, $element) {
$new_content = t('This element (ID %id) has the following content:',
array('%id' => $element['#id'])) . $content;
return $new_content;
}

#cache

该属性控制着表单是否可被Drupal的一般缓存系统所缓存。对表单进行缓存意味着,在表单被提交时,它不需要再被重新构建。如果你想每次都重新构建表单的话,那么你可以设置$form['#cache'] = FALSE。


表单元素:

Textfield(文本字段)

Password(密码)

Password with Confirmation(带确认的密码)

Textarea(文本域)

Select(下拉选择框)

Radio Buttons(单选按钮)

Check Boxes(复选框)

Value(值)

Hidden(隐藏域)

Date(日期)

Weight(重量)

File Upload(文件上传)

Fieldset(字段集)

Submit(提交按钮)

Button(按钮)

Image Button(图片按钮)

Markup(标识文本)

Item(项目)

#ahah属性


跨页面表单:


通用的表单元素属性:

#type

该字符串声明了一个表单元素的类型。例如,#type = 'textfield'。表单根部必须包含声明#type = 'form'。

#access

该布尔值属性用来判定是否将该表单元素显示给用户。如果表单元素有子表单元素的话,如果父表单元素的#access属性为FALSE的话,那么子表单元素将不显示。例如,如果表单元素是一个字段集,并且它的#access为FALSE,那么字段集里面的所有字段都不显示。

#access属性可被直接设置为TRUE或FALSE,也可以设置为执行时返回TRUE或FALSE的函数。当表单定义被取回时,将会执行该函数。下面这个例子来自于Drupal的默认节点表单:

$form['revision_information']['revision'] = array(
'#access' => user_access('administer nodes'),
'#type' => 'checkbox',
'#title' => t('Create new revision'),
'#default_value' => $node->revision,
);
#process

该属性是一个关联数组。在数组的每个条目中,函数名作为键,传递给函数的任何参数作为值。当构建表单元素时将调用这些函数,从而允许在构建表单元素时对该元素进行额外的操作。例如,在modules/system/system.module定义了checkboxes类型,在构建表单期间,将调用includes/form.inc里面的函数expand_checkboxes():

$type['checkboxes'] = array(
'#input' => TRUE,
'#process' => array('expand_checkboxes'),
'#tree' => TRUE
);

还可参看本章中“收集所有可能的表单元素定义”部分中的例子。当#process数组中的所有的函数都被调用以后,将为每个表单元素添加一个#processed属性。

#after_build

该属性是一个函数数组,在构建完表单元素以后它们将被立即调用。每个要被调用的函数都有两个参数:$form 和 $form_state。例如,如果$form['#after_build'] = array('foo', 'bar'),那么Drupal在表单元素构建完以后,分别调用foo($form, $form_state)和bar($form, $form_state)。一旦这些函数都被调用以后,Drupal在内部将为每个表单元素添加一个#after_build_done属性。

#theme

该可选属性定义了一个字符串,当Drupal为该表单元素寻找主题函数时使用。例如,设置#theme = 'foo',Drupal将会在主题注册表中查找对应于foo的条目。参看本章前面的“为表单寻找主题函数”一节。

#prefix

该属性是一个字符串,在表单元素呈现时,它将被添加到表单元素的前面。

#suffix

该属性是一个字符串,在表单元素呈现时,它将被添加到表单元素的后面。

#title

该字符串是表单元素的标题。

#weight

该属性可以是一个整数或者小数。当呈现表单元素时,将根据它们的重量进行排序。重量小的元素将被放到前面,重量大的元素将被放到后面。

#default_value

该属性的类型取决于表单元素的类型。对于输入表单元素,如果表单还没有被提交,那么它就是在该字段中所用的值。不要将它与表单元素#value混淆了。表单元素#value定义了一个内部表单值,尽管用户看不到它,但是它却定义在表单中,并出现在$form_state['values']中。