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

 

译者:老葛

  添加数据填充表单

 为了使用户可以进入一个web页面的笔记部分,我们需要为它提供一个位置。下面我们为笔记添加一个表单:

/**

* Implementation of hook_nodeapi().

*/

function annotate_nodeapi(&$node, $op, $teaser, $page) {

switch ($op) {

case 'view':

global $user;

// If only the node summary is being displayed, or if the

// user is an anonymous user (not logged in), abort.

if ($teaser || $user->uid == 0) {

break;

}

$types_to_annotate = variable_get('annotate_nodetypes', array('story'));

if (!in_array($node->type, $types_to_annotate)) {

break;

}

// Add our form as a content item.

$node->content['annotation_form'] = array(

'#value' => drupal_get_form('annotate_entry_form', $node),

'#weight' => 10

);

}

}

这个例子看起来有些复杂,所以让我们详细的分析一下。首先,注意到我们在这里实现了Drupal的另一个钩子。这次是_nodeapi,在drupal对节点进行各种处理的时候将会调用它,所以其他模块(比如我们的)在处理过程继续之前可以修改节点。我们使用变量$node来表示一个节点。注意第一个参数前面的&意味着对于$node对象这里使用参数传递,这非常棒,因为我们在这里对$node所做的任何修改将被保存下来。我们的目标是追加一个表单,所以我们非常高兴我们可以修改节点。

  我们仍然需要一些在我们的代码被调用时Drupal内部将会发生什么的信息.这些信息保存在参数$op中了,它可以是insert(节点被创建),delete(节点被删除),或者一个其它的值。当前,我们仅对当节点被准备显示出来时,修改节点感兴趣。在这种情况,变量$op的值为view。我们在这里是用了switch控制语句,这样我们可以非常容易的看到在每种情况下我们的模块将会做什么。

  接下来,我们快速的检查了一些我们不想呈现注释域的情况。一种情况是当参数$teaser为真时.如果它为真,这意味着,这个节点并不是单独呈现了,而是呈现在一个列表中,比如说一个搜索引擎的结果中。在这种情况下,我们不需要添加任何东西。另一种情况是$user对象的用户ID0时,这意味着用户没有登录。(注意,在这里我们是用了关键字global来把$user 对象引进来)。我们使用break语句来跳出switch语句从而阻止修改页面。

  在我们为web页面添加注释表单的以前,我们需要检查一下,将要进行显示的节点的类型是不是我们在设置页面所设置的类型中的一个,所以我们回显了在我们实现的设置钩子中所保存的节点类型,并将它保存到了具有可读性的变量$types_to_annotate中去。对于variable_get()中的第2个参数,我们在这里声明了一个默认数组,用于当站点管理员还没有访问我们的模块的配置页面并设置配置属性的情况。下面要做的就是检查一下,我们所要处理的节点的类型是不是确实是$types_to_annotate中的一种。同样,我们使用了break语句来放弃,如果节点类型不是我们想要注释的时候。

  我们最后要做的就是创建表单,并把它添加到$node对象的内容属性中去。首先,我们需要定义一个表单,这样我们就有了添加的东西。我们将在一个单独的函数中完成这件事,它的唯一责任就是定义表单:

/**

* Define the form for entering an annotation.

*/

function annotate_entry_form($node) {

$form['annotate'] = array(

'#type' => 'fieldset',

'#title' => t('Annotations')

);

$form['annotate']['nid'] = array(

'#type' => 'value',

'#value' => $node->nid

);

$form['annotate']['note'] = array(

'#type' => 'textarea',

'#title' => t('Notes'),

'#default_value' => $node->annotation,

'#description' => t('Make your personal annotations about this content

here. Only you (and the site administrator) will be able to see them.')

);

$form['annotate']['submit'] = array(

'#type' => 'submit',

'#value' => t('Update')

);

return $form;

}

和我们在函数annotate_admin_settings()使用的方式一样,通过创建一个键入的数组我们创建了表单—只是在这次我们把我们的文本输入框和提交按钮放到了fieldset中去,这样他们在web页面中就组织到了同一个组下。首先,我们创建一个数组,它的#type为fieldset,并为它提供了一个标题。然后我们创建文本域数组。注意,文本域数组的数组键是fieldset数组中的一员。换句话说,我们使用$form['annotate']['note']替换了$form['note']。这样,Drupal将把这个文本域元素当作fieldset元素中的一员。最后,我们创建了提交按钮,然后返回了定义我们表单的数组。

  现在让我们回到annotate_nodeapi()上,通过向节点的内容添加一个#value和一个#weight,我们将创建的表单追加到了页面的内容上。值包含了要展示的内容,重量告诉Drupal把它展示到哪里。我们想把我们的注释表单放到页面的下面,所以我们为它分配了一个相对较大的重量10.我们要展示的是我们的表单,所以我们调用函数drupal_get_form()来将我们的表单从一个描述如何创建它的数组的形式转化为最终的HTML表单。注意,在这里我们事如何将$node对象传递到我们的表单函数中去的。我们需要这样做来得到以前的注释并把它预先填充到表单中。

使用你的web浏览器查看一个页面,你应该可以看到这个用于追加的注释表单(如图2-2所示):

 

  

     2-2出现在drupal web 页面上的注释表单

 

  当我们点击Update按钮时,将会发生什么呢?什么都没有,因为我们还没有为它写任何代码呢。现在就让我们添加这些代码。但是在我们出发以前,我们不得不考虑一下我们将把用户输入的数据存储到哪里。

 

             把数据存储到数据库表中

存储一个模块的数据的最常用的方式是为这个模块创建一个单独的数据库表。这将使得模块的数据与drupal核心数据表区分开来。当决定为你的模块创建那些字段时,你应该问自己:你需要存储哪些数据?如果我对这个表进行查询时,我将需要什么?最后,还要为我的模块考虑将来的有哪些计划?

   我们需要存储的数据仅仅为注释的文本,注释所用到的节点的数字ID,和填写注释的用户的用户ID。保存一个时间戳也会非常有用,这样我们可以按照时间戳将最近更新的注释排成一列展示出来。最后,我们查询这张表的主要问题是,”这个用户对这个节点做了哪些注释?我们将在uidnid字段上创建一个复合的索引,从而使我们最常用的查询尽可能的快。用来创建我们的表sql语句如下所示:

CREATE TABLE annotate (

uid int NOT NULL default '0',

nid int NOT NULL default '0',

note longtext NOT NULL,

timestamp int NOT NULL default '0',

PRIMARY KEY (uid, nid),

);

我们可以仅仅把这段sql语句放到我们模块的README.txt文件中,这样其他想要安装这个模块的用户将不得不手工的将数据库表添加到他们的数据库中。另一种方式,当你启用你的模块时,Drupal为你提供了自动创建相应的数据库表的工具,我们将充分利用这种方式的优势。我们创建一个特定的文件;文件名开始部分为你的模块名以后缀.install结束,所以对于annotate模块,这个文件名应为annotate.install:

<?php

// $Id$

function annotate_install() {

drupal_set_message(t('Beginning installation of annotate module.'));

switch ($GLOBALS['db_type']) {

case 'mysql':

case 'mysqli':

db_query("CREATE TABLE annotations (

uid int NOT NULL default 0,

nid int NOT NULL default 0,

note longtext NOT NULL,

timestamp int NOT NULL default 0,

PRIMARY KEY (uid, nid)

) /*!40100 DEFAULT CHARACTER SET utf8 */;"

);

$success = TRUE;

break;

case 'pgsql':

db_query("CREATE TABLE annotations (

uid int NOT NULL DEFAULT 0,

nid int NOT NULL DEFAULT 0,

note text NOT NULL,

timestamp int NOT NULL DEFAULT 0,

PRIMARY KEY (uid, nid)

);"

);

$success = TRUE;

break;

default:

drupal_set_message(t('Unsupported database.'));

}

if ($success) {

drupal_set_message(t('The module installed tables successfully.'));

}

else {

drupal_set_message(t('The installation of the annotate module

was unsuccessful.'),'error');

}

}

这个文件简单直接。当第一次启用annotate 模块时,drupal会寻找文件annotate.install并运行函数annotate_install(),如果一切顺利的话,数据库表将被创建。通过禁用然后再启用这个模块,现在就可以完成它。

 

  秘密消息:如果在你的.install文件中包含一个文字错误,或者由于其他原因执行失败,你可以使drupal忘记你的模块和它对应的表,Administer Site building Modules禁用你的模块,然后在数据库的system表中删除对应模块的一行。

 

   当创建了用以存储数据的表以后,我们将不得不对我们的代码做一些修改。其一,我们将需要添加一些代码,一旦用户填入注释并且点击Update按钮以后,用来解决对数据的处理流程。我们用于表单提交的函数如下:

/*

* Save the annotation to the database.

*/

function annotate_entry_form_submit($form_id, $form_values) {

global $user;

$nid = $form_values['nid'];

$note = $form_values['note'];

db_query("DELETE FROM {annotations} WHERE uid = %d and nid = %d", $user->uid,

$nid);

db_query("INSERT INTO {annotations} (uid, nid, note, timestamp) VALUES (%d, %d,

'%s', %d)", $user->uid, $nid, $note, time());

drupal_set_message(t('Your annotation was saved.'));

}

 

由于我们仅允许一个用户对一个节点只能有一个注释,所以我们可以安全的删除以前的注释(如果存在的话)然后插入我们自己的到数据库中。对于我们于数据库的交互,有几点需要注意。首先,我们不需要考虑数据库连接,这是因为在Drupal的引导程序中他已经为我们完成了这一工作。第2,当我们是用一个数据库表时,我们需要把它放到花括号里{}.这样可使数据库的前缀化无缝的集成(参看http://drupal.org/node/2622)。第三,我们在查询语句中使用了占位符,然后为其提供相应的变量,这样Drupal内建的查询清洁机制可以启用以阻止SQL注入攻击。我们使用%d占位符用于数字,使用%s占位符用于字符串。然后,我们使用drupal_set_message()来在用户的会话中插入一消息,它将会在用户查看的下一个页面中被Drupal作为一个通知展示出来。这样,用户可以获得一些反馈信息。

  最后,我们需要修改我们的nodeapi钩子代码,这样的话,如果已经存在了一个注释,它将被从数据库中取出。恰好在我们把我们的表单分配给$node->content以前,我们添加以下代码:

// Get previously saved note, if any.

$result = db_query("SELECT note FROM {annotations} WHERE uid = %d AND nid = %d",

$user->uid, $node->nid);

$node->annotation = db_result($result);

  我们首先查询数据库以取出这一用户对一节点所做的注释。接着,我们使用db_result来从结果集中取出第一行。由于我们仅允许一个用户对同一节点只能做一个注释,所以结果集中也只有一行。

  测试你的模块。他现在应该能够保存和回显注释了。拍下你的背---你已经从头开始创建了一个模块了。现在你已经站在了成为Drupal核心开发者的大道上了。

  

                       更远的一些步骤

  我们将与开源社区分享这一模块,这是自然的,所以需要创建一个README.txt文件,然后把它放到annotation的目录下,和notate.info,annotate.module,annotate.install文件放在一起。接下来,你可以把它上传到drupal.org上的贡献模块库中,然后创建一个项目页面来追踪社区中其他用户的反馈。

 

 

               总结

当读完这一章后,你应该可以:

从头创建一个Drupal模块

了解如何钩住Drupal代码的执行

存储和回显特定模块的设定

使用Drupal的表单API来创建和处理一些简单的表单

使用数据库来存储和回显数据。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值