Drupal专业开发指南 第2章 创建一个模块(1)

来源:百度文库 编辑:神马文学网 时间:2024/05/05 01:05:34
创建一个模块(Module)
在许多开源的应用中,你可以通过修改源代码来定制你的应用。这通常是一个获得你期望的行为的一种方式,但是在drupal中,一般是不赞成这样做的,它被是做万不得已的一个手段。修改源代码,意味着随着每次Drupal的升级,你必须要做更多的工作---你必须测试以下你的定制代码还想期望的那样工作。代替的,Drupal的设计从一开始便考虑到了模块化和可扩展性。
Drupal是个精简的并且优雅的用于开发应用的一个框架,它的默认安装通常被称作为Drupal的核心。通过启用新的模块来向核心添加功能,这些模块是一些包含PHP代码的文件,放置在你的Drupal安装路径sites/all/modules的子目录下。现在看一下这个子目录,现在你可以在你的Drupal站点上导航到Administer->Site building->Modules,比较一下子目录下的模块与网页上的模块列表。
在本章,我们将从头开始创建一个模块;你将学到模块必须遵守的一些标准。我们需要一个真实的目标,所以让我们考虑以下现实中的注释问题。当用户在Drupal网站上浏览内容时,用户可能对内容发表评论(如果管理员开启了评论(comment)模块).但是如果是在一个网页上添加一个注释(一种仅有用户可见得节点类型),那会怎么样?这对于私密的评价内容可能非常有用(我们知道这看起来有些做作,但是现在我们来试暂时忍受一下吧)。
创建相应的文件
首先我们要做的是为模块起一个名字,名字“annotate”看起来还是比较合适的—简洁并且生动。现在我们需要为它找一个放置的位置。让我们把它放在目录sites/all/modules下面来使它和核心模块区分开来。我们创建一个子目录,而不仅仅是一个annotate.module文件,这是应为在我们的模块发行版本中我们还需要一些其他的文件。比如我们需要一个README.txt文件,用来向其他用户解释我们的模块是做什么的,以及如何使用它,还有一个annotate.info文件用来向Drupal提供一些关于我们模块的信息。准备好了吗?
我们的annotate.info文件内容如下:
; $Id$
name = Annotate
description = Allows users to annotate nodes.
package = Example
version = "$Name$"
这个文件采用.ini格式,这是一个用于PHP配置文件的简单标准(参看http://php.
net/parse_ini_file)。我们从一个版本管理系统(CVS)的标识符的标签开始,并且为Drupal的网站上模块管理部分提供了相应的名称(name)和描述(description)。模块可以按组来展示,而组的划分是由包(package)决定的;这样,如果我们有3个不同的模块,他们都有package=Example,那么他们将被放在同一个组中。版本的值是另一个CVS的标示标签。如果我们想和其他用户分享这一模块,通过将它放到Drupal的贡献模块库中,这个值将会被自动填充。
注意:你可能在想,为什么我们需要一个单独的.info文件。为什么不在我们的主模块中写一个函数来返回这些元数据呢?这是因为在模块管理页面加载时,它将不得不加载并解析每一个模块,不管有没有启用,这比平时需要更多的内存并且可能超出分配给PHP的内存上限。
通过使用.info文件,信息可以更快速的加载并且使用更少的内存。
现在我们准备好创建一个真实的模块了。在你的子目录annotate下面创建一个名为annotate.module的文件。在文件的开始出使用PHP的开始标签和一个CVS标示符标签,并紧跟一个注释:
// $Id$
/**
* @file
* Lets users add private annotations to nodes.
*
* Adds a text field when a node is displayed
* so that authenticated users may make notes.
*/
首先,让我们看一下注释的风格。我们从/**开始,在接下来的每一行中缩进一格并以*开头,最后以*/结束。标记@file意味着在接下来的一行是对这个文件要做什么的一个描述。这一行的描述将被这样使用,Drupal的自动文档提取和格式化模块api.module用它来找出这个文件是做什么的。空了一行后,我们为可能检查(并且改进)我们代码的程序员提供了一个更长的说明。注意,我们在这里故意没有使用一个结束标签?>;这对于PHP来说是可选的,如果包含了它,就可能导致文件的尾部空格问题(参看http://drupal.org/node/545)。
注意:为什么我们在这里这么详细的讲述每一个细节?这是因为,如果来自世界各地的成千上百的人开发同一个项目的话,如果大家采用一种标准的方式的话,将会节省大量的时间。关于Drupal的代码风格的更详细的内容可以从Drupal的用户手册的“代码标准”一节中找到(http://drupal.org/node/318)。
保存你的文件,访问Administer->Site building->Modules.你的模块将会出现在列表中。多么激动人心啊。
下面我们要做的就是定义一些设置,这样我们就可以使用一个基于web的表单来选择哪些节点类型我们可以添加注释。这需要两步。首先我们定义一个我们可以访问我们设置的路径。然后我们创建设置的表单。
实现一个钩子
回想一下,Drupal是建立在一个钩子的系统之上,有时候称之为回调。在执行的过程中,Drupal询问模块看它们是不是想要做些事情。举例来说,当决定那一个模块负责当前的请求时,它向所有的模块询问是否提供提供相应的路径。通过制造一个所有模块的列表,并且调用每个模块中名为:模块名+_menu的函数,来做这件事。当它遇到我们的annotate模块时,它调用函数annotate_menu(),并向它传递一个参数。这个参数意味着这个模块的相应是否可被缓存。一般情况下,菜单项可以被缓存;我们将在第4章介绍例外情况,这章讲述了Drupal的菜单/回调系统。每一个菜单项是一个联合的数组。下面就是要向我们模块中添加的东西:
/**
* 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;
}
此时不要在细节上过于担心。这段代码说,“当用户访问页面http://example.com/?q=admin/settings/annotate时,调用函数drupal_get_form,并向它传递了一个表单ID annotate_admin_settings”。当Drupal完成了向所有的模块询问它们的菜单项时,它将会找到一个菜单以从中选择一个函数用于相应所请求的路径。
注意,所有将被展示给用户的文本被放在了函数t()中,它将会在字符串翻译时调用。通过对所有的可展示文本使用字符串的翻译函数,这使得本地化你的模块为另一个不同语言时非常方便。
注意:如果你对于钩子机制很感兴趣的话,参看文件includes/module.inc里面的函数module_invoke_all()。
现在你应该清楚我们为什么叫它hoo_menu或者菜单钩子了。Drupal的钩子通过在钩子的名称前加上你的模块名来创建。
秘密消息:Drupal的发展很快。一个支持的钩子的完全列表和它们的使用说明可在Drupal的API文档站点(http://api.drupal.org)上找到。
添加特定模块的设置
Drupal有多种不同的节点类型,比如Story和Page。我们想将评论的使用限定在特定的一些节点类型上。为了实现它,我们需要创建一个页面,在这里我们告诉我们的模块那些节点类型我们想评论。向annotate模块添加下面的代码:
/**
* 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[‘array_filter‘] = array(‘#type‘ => ‘hidden‘);
return system_settings_form($form);
}
在Drupal中,表单被表示为一个嵌套的树状结构;也就是说,一个数组的数组。这个结构向Drupal的表单呈现引擎(renderingengine)描述了表单是如何表示的。为了可读性,我们将数组中的每一个元素放到单独的一行里面。每一个指示都以”#”开头,它作为数组的键。我们首先声名了表单元素的类型为复选框,这意味着通过使用一个键入的数组来构建一个多选的复选框。我们为表单元素设置一个标题,像平常的一样使用了t()函数。然后我们将选项(options)赋值为node_get_types(‘names‘),它方便的返回了当前Drupal中可用的节点类型的键值数组。函数node_get_types(‘names‘)的输出看起来像这个样子:
‘page‘ => ‘Page‘, ‘story‘ => ‘Story‘
数组的键对应于节点类型在Drupal中的内部名称,而把可读性的名称(显示给用户的)放到右边。如果你启用了一个Savory Recipe模块,数组看起来将像这样:
‘page‘ => ‘Page‘, ‘savory_recipe‘ => ‘Savory recipe‘, ‘story‘ => ‘Story‘
因此,在我们的web表单中,就为page和story两种节点类型生成相应的复选框。下一个指示,#default_value,将是这个表单元素的默认值。由于checkboxes是一个多值的表单元素(即是说,存在多于一个的复选框),所以#default_value的值将会是一个数组。
#default_value的值值得讨论一下:
variable_get(‘annotate_nodetypes‘, array(‘story‘))
Drupal允许程序员使用特定的一对函数:varialble_get()和varialble_set()来存储和回显任意一个值。值被存储到了数据库表variables中,并且在处理一个请求的任一时候都是可用的。由于在处理每个请求时都会回显这些值,所以不能用这个方法来存储大数量的数据。但是它是个非常方便的方式用来存储模块的配置属性值。注意我们向方法varialble_get()中传递了一个对于值描述的键(所以我们可以取回来它),和一个默认值。在这种情况下,默认值是一个关于那些节点类型允许注释的数组。这样默认情况下,我们允许评论节点类型Story。
最后我们提供一个描述,用来告诉站点管理员关于这个域的一些更细节的信息。
现在导航到Administer ? Settings ? Annotate,我们将看到为annotate.module所显示的表单。

图2-1,为annotate.module生成的配置表单。
定义$form[‘array_filter‘]的这行代码看起来有点神秘。不过现在,我们只需要知道,当我们使用settings钩子的存储我们的复选框值的时候,它是必须的,者就可以了。
仅用了几行代码,我们为我们的模块提供了一个可用的配置表单,它将自动的保存和记起我们的设置。好的,代码中的一行长度适中,但是仍然,这会给你一种使用Drupalde 奇妙感觉。
发表于 @2007年09月22日 17:03:00|评论(0)|编辑
Drupal专业开发指南 第2章 创建一个模块(1) Drupal专业开发指南 第2章 创建一个模块(2) Drupal专业开发指南 第3章 模块特定设置(2) Drupal专业开发指南 第3章 模块特定设置(1) Drupal专业开发指南 第1章 Drupal工作原理(2)对请求提供服务 Drupal专业开发指南 第1章 Drupal工作原理(1) Drupal专业开发指南 第1章 Drupal工作原理(1) - g089h515r806的专栏 - CSDNBlog Drupal专业开发指南 第1章 Drupal工作原理(2)对请求提供服务 - g089h515r806的专栏 - CSDNBlog Drupal专业开发指南 第1章 Drupal工作原理(2)对请求提供服务 - g089h515r806的专栏 - CSDNBlog 使用开源软件设计、开发和部署协作型 Web 站点,第 5 部分: Drupal 入门 第2章 创建数据库和表 jbpm开发指南2 使用开源软件设计、开发和部署协作型 Web 站点,第 6 部分: 在 Drupal 中构建... 使用开源软件设计、开发和部署协作型 Web 站点,第 11 部分: 使用 Drupal 中... 业务流程: 学习 BPEL4WS,第 2 部分创建一个简单的流程 jBPM开发入门指南(1) 一步一步学Silverlight 2系列(1):创建一个基本的Silverlight应用 创建新的门户: 第 5 部分:开发、构建和部署门户 DNN模块开发系列文章(1)——分析设计 中国最后一个右派林希翎纽约痛欲“安乐死”(图) | drupal 创建文件或文件夹(C# 编程指南) Windows Mobile开发环境搭建指南1 开发端到端的 Ajax 应用程序,第 1 部分: 用一个场景设置 Ajax 环境 开发端到端的 Ajax 应用程序,第 1 部分: 用一个场景设置 Ajax 环境