drupal 表单构造函数

在 Drupal 用语中,用于创建表单的函数叫做表单构造函数(constructor)。术语 constructor 没有特别的意义,与面向对象编程中的同名术语无关。

表单构造函数创建出一个复杂的数据结构,用于构造、验证、管理表单。其使用方式类似于钩子:遵循特定的命名约定,所有表单构造函数都返回同一类型的数据结构。

在研究表单构造函数之前,先看一下我们想要表单具备的特性的列表:

  • 首先,因为在整个处理过程中都要使用 $account 对象,因此我们希望保持一个对此对象的引用。通常这是用表单的隐藏域来实现的,但是 Drupal 有一个处理此类情况的更好方法。
  • 其次,我们需要有两个表单域用来存放email消息的标题(title)和正文(body)。
    • 标题域是单行文本输入框。
    • 正文域是多行文本区域。
  • 为了更好地组织我们的表单,我们要用一个 field set (HTML 中的<fieldset/> 标签),把上面的域组成一组。
  • 因为管理员是通过 Drupal 发送这个表单的,他或她也许需要一份发送消息的拷贝用于存档。因此,我们将添加一个单选按钮(checkbox)表明是否发送一份BCC (blind carbon copy) 消息给管理员。
  • 同样,为了保持表单的组织结构,我们将创建一个为单选按钮创建一个"details" field set。
  • 最后,我们需要一个提交(submit)按钮。

现在我们可以把这个任务清单转换成表单构造器了。这个函数有点长,因为需要创建很多域。不过,阅读起来并不复杂:

 

function emailusers_compose_form($context, $account) {
  // This is a value only -- equivalent to a hidden field, except
  // that it is never rendered into the HTML.
  $form['to'] = array(
    '#type' => 'value',
    '#value' => $account,
    );
  // Create a fieldset for the body:
  $form['message'] = array(
    '#type' => 'fieldset',
    '#title' => t('Compose the Message'),
    );
  // Textfield for subject of the body
  $form['message']['subject'] = array(
    '#type' => 'textfield',
    '#title' => t('Subject'),
    '#size' => 50,
    '#maxlengh' => 255,
    '#description' => t('The subject of the email message.'),
    );
  // And a text area for the body.
  $form['message']['body'] = array(
    '#type' => 'textarea',
    '#title' => t('Message'),
    '#cols' => 50,
    '#rows' => 5,
    '#description' => t('The body of the email message.'),
    );
  // Create a fieldset for details
  $form['details'] = array(
    '#type' => 'fieldset',
    '#title' => t("Details"),
    );
  // Checkbox: if checked, CC the author, too.
  $form['details']['cc_me'] = array(
    '#type' => 'checkbox',
    '#title' => t('BCC Yourself'),
    '#default_value' => 1,
    '#description' =>
    t('If this is checked, the message will also be sent to you.'),
    );
  // Finally, a submit button:
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Send Mail'),
    );
  return $form;
}

这个函数的一般结构并不陌生。它与其它 Drupal 函数很相似。变量 $form 是个关联数组,其中每一项对应(大体上)一个表单元素。一共有 7 个这样的表单元素,我们稍后详细分析。

 

$form 数组的每一项的值都是另一个关联数组,包含相应元素的配置信息。

此函数构造出 $form 数组,并把它返回。其它函数,比如 drupal_get_form(),调用这个函数,用这个表单定义达到各种目的,包括创建表单的HTML 表示形式,或进行基本的表单验证。

让我们详细分析一下 $form 数组的各个项。第一项存储账户信息:
 

$form['to'] = array(
  '#type' => 'value',
  '#value' => $account,
);

这一项是个 value 域。与我们将要看到的其它元素不同,它对应的不是一个可见的表单元素。它只是保存了某个 value 的引用(在本例中,是 $account 变量的引用),表单 API 在整个处理过程中都可以使用此引用。

 

因为这是个简短的定义,从它开始讲解比较好。在本例中,$forms 数组的 key 用于引用关于此表单的数据。以 HTML 表单为例,这大体上相当与表单元素的name 属性。

这一项的值是一个关联数组,它提供了关于此表单元素的信息。由于表单的复杂性,这个数组中可以使用的值有一大票,但这里的两个 key 对于很多表单域都是相同的。

提示:所支持参数的完整列表,参加表单 API 参考网页:http://api.drupal.org/api/file/developer/topics/forms_api_reference.html/6 除参数列表外,这个网页中还包含了指明哪个表单元素支持哪个参数的矩阵。

第一个,#type,表明这个表单元素为何种类型。每个 HTML 表单元素都有一个类型。还有几个特殊类型的表单域,value 类型即为其中之一,在很多方面,它与 <input type="hidden"/> HTML 表单域完成相似的功能。这使得用户可以为表单附加信息,而不必为用户提供修改信息的方式。但是,有一个很重要的方面是不同的:value 永远不会发送给客户端。它只是存储在服务器端。

提示:所有用于定义表单项的参数都以 # 开头。这用来区分参数和嵌套表单域。稍后关于 field set 的讨论中有相关示例。

下一个参数是 #value。这个参数也可以用于好几个不同的表单类型。它保存内容不能被用户修改的表单类型的域的值。在本例中,它引用 $account 数据。

提示:多数情况下,#value 域的值应该是一种易于打印的类型(比如字符串或整数)。不过当 #type 被设置为 value 时,#value 的引用可以是任何对象。

提示:在这里,对术语 'value' 的重复使用可能导致混淆。有一种 #type 叫做 value,它说明了所描述的是哪一种表单元素。数组中还有一个 #value 元素,它说明了表单元素应该被设置为什么值。在我们的示例中,就出现了一种不幸的情况,我们可以这样表述:元素 value 的值是 #value 的值。(the value of the value element is #value's value.)

我们大体上介绍了如何定义表单元素。现在让我们快速浏览一下 $form 数组中的其它项:

 

// Create a fieldset for the body:
$form['message'] = array(
  '#type' => 'fieldset',
  '#title' => t('Compose the Message'),
);
// Textfield for subject of the body
$form['message']['subject'] = array(
  '#type' => 'textfield',
  '#title' => t('Subject'),
  '#size' => 50,
  '#maxlengh' => 255,
  '#description' => t('The subject of the email message.'),
);
// And a text area for the body.
$form['message']['body'] = array(
  '#type' => 'textarea',
  '#title' => t('Message'),
  '#cols' => 50,
  '#rows' => 5,
  '#description' => t('The body of the email message.'),
);

这三项加在一起定义了一个 field set,包括一个 Subject 文本框和 Message 文本输入区。

 

三项中的第一项定义了一个 field set(注意 #type 的值为 fieldset)。参数 #title 可以用于大多数元素,它用来创建 field set 的说明以及其它表单域的标签(label)。

提示:与平常一样,传递给用户的普通文本应该放在 t() 转换函数之内。

下一项定义了 Subject 文本输入区。为了表明这个域属于 field set,subject 数组嵌入到 $form['message'] 数组之中,成为 $form['message']['subject']。使用这种嵌套功能,就可以有逻辑地构造出复杂的表单。当 Drupal 收到并处理提交的表单数据时,你就可以用上述数据结构访问它。

textfield 类型在 HTML 中显示为单行文本输入框(<input type="text"/>)。

在本例中,#size 和 #maxlength 参数用于设置可见区域的大小和域中可以包含的最大字符数。对于 #maxlength,不仅用于生成表单,当表单数据上传时,Drupal 在服务器端还要进行检查,以确保用户提交的数据不超过限制长度。#description 显示为输入区域的帮助文本。

与文本框一样,用于邮件正文(body)的文本区域定义为 $form['message'] 数组的子元素。文本输入区也被显示在 field set 之内。这里用了两个参数:#rows 和 #cols。它们与 HTML<textarea/> 元素的同名属性相对应。

至此,我们学习了几个 field,让我们看看 Drupal 如何把这个数据结构转换成表单。显示为 HTML 时,这三个项目如下所示:


插图 6-2

对于 field set,标题被嵌入边框中。对于另外两个元素,标题显示在域的上方,描述文本显示在域的下面。

最后三项定义作用是类似的:
 

// Create a fieldset for details
$form['details'] = array(
  '#type' => 'fieldset',
  '#title' => t('Details'),
);
// Checkbox: if checked, CC the author, too.
$form['details']['cc_me'] = array(
  '#type' => 'checkbox',
  '#title' => t('BCC Yourself'),
  '#default_value' => 1,
  '#description' =>
  t('If this is checked, the message will also be sent to you.'),
);
// Finally, a submit button:
$form['submit'] = array(
  '#type' => 'submit',
  '#value' => t('Send Mail'),
);

在本节中,为 details 创建了一个新的 field set。说明应该把邮件BBC 给发送者的单选框被加入了 details field set 之中。在 cc_me 单选框定义中,#default_value 说明单选框默认处于选中状态(1 = 选中, 0 = 未选中)。但是 #default_value 与 #value 有一点重要的差异,#default_value 说明用户可以根据自己的意愿选择不同的值,而用户不能改变 #value 的值。

 

最后,在带有单选框的 field set 之后是提交按钮。此处再次使用了 #value——这次是为了给提交按钮添加标签。

至此,如果我们用一个 URL 访问这个页面:http://example.com/drupal?q=admin/emailusers/compose/3 会出现什么情况呢?首先 emailusers_menu() 钩子致使 Drupal 使用emailusers_compose() 回调函数(传入整数 3)。这个函数装入用户的账户信息($account)、生成一行文本,然后把控制器交给 drupal_get_form()。drupal_get_form() 函数从 emailusers_compose_form() 中装入表单构造函数并把它显示为 HTML,然后再发送给用户。

提示:调试时,应清空缓存。表单以及支撑表单的对象是被缓存的。有时候,这种缓存会干扰开发。使用 Devel 模块中 Devel 区块的”清空缓存(Empty cache)链接可以避免这种困扰。

最终显示给用户的是如下截图所示的页面:

插图 6-3

但是,提交这个表单时,会发生什么呢?

评论

发表新评论

此内容将保密,不会被其他人看见。
  • 允许HTML标签:<a> <img><em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd><p>
  • 自动断行和分段。

更多关於格式化选项的信息

Image CAPTCHA
验证码
|