当你自己创建一个模块时,你常常想让站点管理员能够通过选择不同的模块设置属性来改变模块的行为。本章将详细讲述如何将一个模块呈现在Drupal的管理页面,如何为用户呈现一个关于设置的表单,以及存储设置属性。
把你的模块放到管理页面的模块列表中
Drupal的管理页面为站点管理员展示了不同的站点配置选项。你想在这个配置页面找个未知把你的模块放下,这样站点管理员就可以调整你的模块的设置。现在让我们为前章所创建的注释模块添加更多的配置选项。
创建一个链接
我们需要在管理页面提供一个链接,这样站点管理员可以进入修改我们设置的页面。通过在菜单钩子(关于更多的菜单钩子的信息,参看第4章)上创建一个入口,我们将链接放在了站点配置设置下面。下面的就是在我们的模块中所实现的菜单钩子:
/**
* Implementation of hook_menu().
*/
function annotate_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/settings/annotate',
'title' => t('Annotation settings'),
'description' => t('Change how annotations behave.'),
'callback' => 'drupal_get_form',
'callback arguments' => array('annotate_admin_settings'),
'access' => user_access('administer site configuration')
);
}
return $items;
}
指向我们模块的链接现在出现在Drupal的管理页面的站点配置部分,如图3-1所示:

图3-1指向注释设置页面的链接
定义你自己的管理区域
Drupal 有多个管理设置的分类,比如内容管理和用户管理,都出现在主管理页面上。如果你的模块需要一个自己的分类,你可以非常容易得创建一个这样的分类。在这个例 子中,我们创建一个名为"Node annotation"的新的分类。为了这样,我们修改我们的菜单钩子以定义新的分类:
/**
* Implementation of hook_menu.
*/
function annotate_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/annotate',
'title' => t('Node annotation'),
'description' => t('Adjust node annotation options.'),
'position' => 'right',
'weight' => -5,
'callback' => 'system_admin_menu_block_page',
'access' => user_access('administer site configuration')
);
$items[] = array(
'path' => 'admin/annotate/settings',
'title' => t('Annotation settings'),
'description' => t('Change how annotations behave.'),
'callback' => 'drupal_get_form',
'callback arguments' => array('annotate_admin_settings'),
'access' => user_access('administer site configuration')
);
}
return $items;
}
现在我们代码的结果改变了,我们的模块设置的链接出现在了一个新的分类中了,如图3-2所示:

图3-2 指向注释设置模块的链接现在作为一个单独的分类出现
如果你是一步一步跟着做的,那么你需要清除菜单缓存来查看链接的呈现。
有两种方式:截去cache_menu表或者使用Drupal开发专用模块所提空的清空缓存链接。
秘密消息:开发专用模块(http://drupal.org/project/devel)是为了专门支持Drupal开发所写的一个模块。它能帮你获取多种开发功能,比如清空缓存,查看变量,追踪查询语句,以及更多。它是专业开发的必需品。
我们可以在两步内建立我们的新分类。首先,我们添加一个描述分类头部的菜单项。这个菜单项有一个唯一的路径(admin/annotate)。我们生命: 它应该放在右栏中,重量为-5,这是因为这个位置恰好位于站点配置分类的上面,这样方便我们截图,如图3-2所示的。^_^
第2步是告诉Drupal,把指向注释设置的真实链接放在分类" Node annotation"内部。我们通过修改原来菜单项的路径来这样做,以前路径为admin/settings/annotate,现在替换为了 admin /annotate/settings。以前,菜单项是站点配置分类的路径admin/settings的孩子,,如表3-1所示。
当 我们清空菜单缓存,Drupal重新构造菜单树,由于admin /annotate/settings是admin /annotate的孩子,这决定了像图3-2所展示的这样。将模块菜单项嵌套在如表3-1所示的任一路径下,将使模块出现在Drupal管理页面的该分 类下面。
当然,这是个有点做作的例子,在真实场景下,你必须有个很好的理由来创建一个新的分类,以阻止让管理员(通常是你自己)面对太多分类时所产生的困惑。
表3-1管理页面分类的路径
|
Path
|
Category
|
|
admin/content
|
Content management
|
|
admin/build
|
Site building
|
|
admin/settings
|
Site configuration
|
|
admin/user
|
User management
|
|
admin/logs
|
Logs
|
为用户呈现一个设置表单
当一个站点管理员想要修改注释模块的的设置时,我们需要展示一个表单以使管理员可以从中进行选择。在我们的菜单项中,我们把回调函数设置为drupal_get_form(),把回调参数设置为annotate_admin_settings.这意味着,当你访问http://example.com/?q=admin/
annotate/settings时,命令drupal_get_form('annotate_admin_settings')将被执行,它主要告诉Drupal构造由函数annotate_admin_settings()所定义的表单。
下面让我们看一下定义表单的函数,它定义了一个关于节点类型的复选框(参看图2-1),并且增加了另外两个选项:
/**
* Define the settings form.
*/
function annotate_admin_settings() {
$form['annotate_nodetypes'] = array(
'#type' => 'checkboxes',
'#title' => t('Users may annotate these node types'),
'#options' => node_get_types('names'),
'#default_value' => variable_get('annotate_nodetypes', array('story')),
'#description' => t('A text field will be available on these node types
to make user-specific notes.'),
);
$form['annotate_deletion'] = array(
'#type' => 'radios',
'#title' => t('Annotations will be deleted'),
'#description' => t('Select a method for deleting annotations.'),
'#options' => array(
t('Never'),
t('Randomly'),
t('After 30 days')
),
'#default_value' => variable_get('annotate_deletion', 0) // default to Never
);
Table 3-1. Paths to Administrative Categories
Path Category
admin/content Content management
admin/build Site building
admin/settings Site configuration
admin/user User management
admin/logs Logs
$form['annotate_limit_per_node'] = array(
'#type' => 'textfield',
'#title' => t('Annotations per node'),
'#description' => t('Enter the maximum number of annotations allowed per
node (0 for no limit).'),
'#default_value' => variable_get('annotate_limit_per_node', 1),
'#size' => 3
);
return system_settings_form($form);
}
我们添加了一个单选按钮来选择什么时候应该删除注释,添加了一文本输入框来限制一个节点所允许的注释数量(对此模块增强特性的实现留给读者作为练习)。在这 里,我们没有自己管理处理我们自己的表单的流程,而是使用了函数system_settings_form()来让系统模块为表单添加一些按钮,并让它管 理表单的验证和提交。图3-3显示的当前表单的选项的样子。

图3-3使用了复选框,单选按钮,文本输入框的增强的表单
验证用户提交的设置
如果由函数system_settings_form()为我们管理表单的话,那么我们如何才能检查是否在每一节 点多少个注释的输入框内输入的是一个真实的数字?我们可以钩住表单提交的处理过程么?以及怎么钩住?当然我们可以。我们仅需在我们的表单定义中定义一个验 证函数,然后创建这个验证函数。
/**
* Define the settings form.
*/
function annotate_admin_settings() {
$form['annotate_nodetypes'] = array(
28 CHAPTER 3 ■ MODULE-SPECI F IC SETTINGS
'#type' => 'checkboxes',
'#title' => t('Users may annotate these node types'),
'#options' => node_get_types('names'),
'#default_value' => variable_get('annotate_nodetypes', array('story')),
'#description' => t('A text field will be available on these node types to make
user-specific notes.'),
);
$form['annotate_deletion'] = array(
'#type' => 'radios',
'#title' => t('Annotations will be deleted'),
'#description' => t('Select a method for deleting annotations.'),
'#options' => array(
t('Never'),
t('Randomly'),
t('After 30 days')
),
'#default_value' => variable_get('annotate_deletion', 0) // default to Never
);
$form['annotate_limit_per_node'] = array(
'#type' => 'textfield',
'#title' => t('Annotations per node'),
'#description' => t('Enter the maximum number of annotations allowed per node (0
for no limit).'),
'#default_value' => variable_get('annotate_limit_per_node', 1),
'#size' => 3
);
// Define a validation function.
$form['#validate'] = array(
'annotate_admin_settings_validate' => array()
);
return system_settings_form($form);
}
// Validate the settings form.
function annotate_admin_settings_validate($form_id, $form_values) {
if (!is_numeric($form_values['annotation_limit_per_node'])) {
form_set_error('annotate_limit_per_node', t('Please enter a number.'));
}
}
现 在当Drupal处理这个表单时,它将回调annotate_admin_settings_validate()来进行验证。如果我们检测到输入的数据 是坏的,我们将在错误出现的字段上设置一个错误信息,这反映为在页面上方出现一个警告信息,并将该字段的值转化为红色,如图3-4所示:

图3-4 验证脚本设置了一个错误信息
存储设置
在前面的例子中,改变设置然后点击"Save configuration"按钮,可以正常工作。如果点击了"Reset to defaults"按钮,各字段值将重置为它们的默认值。下面部分将描述这是如何工作的。
使用Drupal的变量数据库表
首先,让我们看一下字段"Annotations per node"。它的#default_value这样设置:
variable_get('annotate_limit_per_node', 1)
Drupal在数据库中有一个名为variables的表,并且键值对可以使用方法variable_set($key,$value)来存储,使用方法 variable_get($key,$default)来回显。所以我们要说的就是,"将字段'Annotations per node'的默认值设置为数据库表variables所存储的变量annotate_limit_per_node的值,如果不存在的话,使用1作为默认 值"。所以当点击"Reset to defaults"按钮时,Drupal将使用默认值1.
警告:为了使在variables表中存储和回显的设置没有命名空间的冲突,你应该是你的表单字段名和变量的键(如上例中的annotate_limit_per_node)名称相同。命名方式为你的模块名加上一个描述性的名称。
由于" Annotations will be deleted"字段是一个单选按钮,它看起来复杂一点。这个字段的#option如下所示:
'#options' => array(
t('Never'),
t('Randomly'),
t('After 30 days')
)
当PHP遇到一个没有键的数组时,它默认的为其插入数字键,所以这个数组的真实表示如下所示:
'#options' => array(
[0] => t('Never'),
[1] => t('Randomly'),
[2] => t('After 30 days')
)
当我们为这个字段设置默认值时,我们使用:
'#default_value' => variable_get('annotate_deletion', 0) //默认为Never
它意味着,当有效时,默认为数组的第键值为0的元素,即是t("Never").
使用variable_get()来回显存储的值
当你的模块回显存储的设置时,应该采用
// Get stored setting of maximum number of annotations per node.
$max = variable_get('annotate_limit_per_node', 1);
注意,在这里variable_get()的默认值,也是在没有存储值可用的情况使用(可能管理员还没有访问设置页面)。
总结
当读完本章后,你应该可以:
创建一个链接,在Drupal的主配置页面,来指向你的模块的特定的配置设置页面。
在Drupal的主管理页面创建一个新的管理分类
定义一个表单,使得管理员可以为你的模块选择特定的选项
验证选项并且如果验证失败的话返回一个错误信息反馈。
理解Drupal如何使用自己内建的持久化变量系统来存储和回显模块的设置
最新评论