老葛的Drupal培训班 http://zhupou.cn
在许多开源的应用中,你可以通过修改源代码来定制应用。这是一种方法, 用来获得你想要的功能;但是在drupal中,一般不赞成这样做,只有在万不得已的情况下才使用这一手段。修改源代码,意味着随着Drupal的每次更新,你必须要做更多的工作----你必须测试一下你的修改是否还能正常工。代替的,Drupal的设计从底层便考虑了模块化和扩展性。
在本章,我们将从头开始创建一个模块;在你创建模块时,你将学到模块必须遵守的一些标准。我们需要一个现实的目标,所以让我们考虑以下现实中的注释问题。当用户在Drupal网站上浏览内容时,如果管理员启用了评论模块,那么用户可能会对内容发表评论。但是如果是在一个网页上添加一个注释(一种仅有用户可见的笔记类型),那该怎么样?这对私密的内容评审可能非常有用(我知道这看起来可能有点做作,但是大家还是容忍一下吧)。
老葛的Drupal培训班 Think in Drupal
首先我们要做的是为模块起一个名字。名字“annotate”看起来还是比较合适的—简洁而生动。接着,我们需要找个地方来放置这个模块。我们可以把这个模块放在核心模块所在的目录中去,不过这样的话,我们需要记住哪些是核心模块,哪些是我们的模块,这样一来,就增加了维护成本。让我们把它放在目录sites/all/modules下面,以将其与核心模块区分开来。
老葛的Drupal培训班 Think in Drupal
Drupal有多种不同的节点类型(在用户界面称之为内容类型),比如Story和Page。我们想将注释的使用限定在特定的一些节点类型上。为了实现这一点,我们需要创建一个页面,在里面告诉我们的模块我们想注释哪些节点类型。在该页面,我们将呈现一组复选框,每一个复选框就对应一个已有的内容类型。这样终端用户就可以通过选中或者取消选中复选框(如图2-1所示),就可以决定哪些内容类型可被注释。这样的页面就是一个管理页面,只有在需要的时候才加载和解析合成该页面的代码。因此,我们把代码放在了一个单独的文件中,而不是放在我们的annotate.module文件里,而对于每个web请求,都会加载和运行annotate.module文件。由于我们告诉了Drupal,在文件annotate.admin.inc中查找我们的设置表单,所以创建文件sites/all/modules/custom/annotate/annotate.admin.inc,并向里面添加以下代码:
在Drupal中,表单被表示为一个嵌套的树状结构;也就是说,一个数组的数组。这个结构向Drupal的表单呈现引擎(rendering engine)描述了表单是如何表示的。为了可读性,我们将数组中的每个元素单独成行。每一个表单属性都以”#”开头,并作为数组的键。我们首先声明了表单元素的类型为checkboxes,这意味着通过使用一个带键的数组来构建多个复选框。我们在变量$options中已经得到了带键的数组。
老葛的Drupal培训班 Think in Drupal
这里值得讨论一下#default_value的值:
仅用了几行代码,我们就为我们的模块提供了一个可用的配置表单,它将自动的保存和记住我们的设置!好的,尽管代码中的一行有点太长了,但是没有关系,你现在应该能够感受到撬动Drupal的力量了。
为了让用户可以为一个web页面输入笔记,我们需要为它提供一个地方,专门用来输入笔记。下面我们在annotate.module中为笔记添加一个表单:
老葛的Drupal培训班 Think in Drupal
这个看起来有点复杂,所以让我们详细的分析一下。首先要注意的是,我们在这里实现了Drupal的另一个钩子。这次是nodeapi钩子,在drupal对节点进行各种处理时将会调用该钩子,这样其它的模块(比如我们的)在处理继续往下以前可以修改节点。我们通过变量$node将节点传递过来。注意第一个参数前面的&,这意味着它实际上是对$node对象的一个引用,这点非常好,因为我们在这里对$node所做的任何修改都将被保存下来。由于我们的目标是追加一个表单,所以我们非常高兴地看到我们可以修改节点。
我们最后要做的就是创建表单,并把它添加到$node对象中。首先,我们需要定义一个表单,这样我们就有了要添加的东西。我们将在annotate.module中的一个单独的函数中完成这件事,它唯一的责任就是定义表单:
当我们点击更新按钮时,将会发生什么呢?什么都没有,因为我们还没有为输入的表单内容编写任何逻辑代码呢。现在就让我们添加它。但是在我们继续以前,我们需要考虑一下,我们将把用户输入的数据存储到哪里呢?
老葛的Drupal培训班 Think in Drupal
存储模块所用数据的最常用方式,就是为这个模块的数据创建一个单独的数据库表。这将使得该数据与drupal核心数据库表独立开来。当你决定为模块创建哪些字段时,你应该问问自己:需要存储什么数据呢?如果我要对这个表进行查询,那么我需要使用什么字段和索引?最后,还要考虑一下,我在将来对这个模块可能会作哪些扩展?
老葛的Drupal培训班 Think in Drupal
我们可以把这段sql语句放到我们模块的README.txt文件中,这样我们就省事了,但是想要安装这个模块的其他用户就麻烦了,他们需要手工的将数据库表添加到他们的数据库中。换种方式,我们知道,在你启用你的模块时,Drupal能帮你创建相应的数据库表;我们这里将利用Drupal的这一点。我们将创建一个特殊的文件;文件的名字将使用你的模块名,而后缀则使用.install,所以对于annotate.module,这个文件名应该为annotate.install。创建文件sites/all/modules/custom/annotate/annotate.install,并输入以下代码:
老葛的Drupal培训班 Think in Drupal
当Drupal创建了用来存储数据的annotations表以后,我们需要修改一下我们的代码。其一,我们将需要添加一些逻辑代码,这样在用户输入注释并且点击更新按钮以后,它可以用来负责对输入数据的处理工作。我们的表单提交函数如下所示:
最后,我们需要修改nodeapi钩子中代码,这样,如果已经存在了一个注释,那么它将被从数据库中取出,并用来预先填充我们的表单。在我们把我们的表单分配给$node->content的代码前面,我们添加以下代码,这里用粗体将其标出了:
测试一下你的模块。它现在应该能够保存和取回注释了。现在可以喘口气了---你已经从头创建了一个模块。在通往Drupal专业开发者的道路上,你已经迈出了关键的一步。
老葛的Drupal培训班 Think in Drupal
Drupal有多个管理设置的类别,比如内容管理和用户管理,都出现在主管理页面上。如果你的模块需要一个自己的类别,那么你可以非常容易的创建一个。在这个例子中,我们创建一个名为“Node annotation”的新类别。为了实现这一点,我们修改我们的菜单钩子以定义新类别:
在注释模块中,我们允许管理员选择哪些节点类型支持注释(如图2-1所示)。让我们深入学习一下这是如何工作的。
老葛的Drupal培训班 Think in Drupal
下面让我们看一下定义表单的函数,它为节点类型定义了一个复选框(参看图2-1),并且增加了另外两个选项。函数位于sites/all/modules/custom/annotate/annotate.admin.inc中:
如果由函数system_settings_form()为我们负责保存表单数值,那么我们如何才能判定在“Annotations per node”字段中输入的是一个数字?我们可以钩住表单提交的处理过程么?当然可以了。我们只需在sites/all/modules/custom/annotate/annotate.admin.inc中定义一个验证函数,如果我们发现有任何异常的话,就使用这个函数来设置一个错误消息。
在前面的例子中,修改设置并点击“保存配置”按钮,可以正常工作。如果点击了“重置为默认值”按钮,那么各个字段将被重置为它们的默认值。下面部分将描述如何实现这一点。
老葛的Drupal培训班 Think in Drupal
当你的模块取回已存储的设置时,应该使用variable_get():
我们将与开源社区分享这一模块,这是自然的,所以需要创建一个README.txt文件,然后把它放到annotation的目录下,和annotate.info,annotate.module,annotate.install文件放在一起。README.txt文件一般包含的信息有,谁编写了这个模块,以及如何使用这个模块。这里不需要包含许可证信息,这是因为所有上传到drupal.org的模块都将采用GPL许可,而drupal.org上的打包脚本将会为模块自动添加一个LICENSE.txt文本。接下来,你就可以把它上传到drupal.org上的第3方模块资源库中了,然后创建一个项目页面,用来追踪社区中其他用户的反馈。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
当读完这一章后,你应该可以处理以下任务: