添加數(shù)據(jù)填充表單
為了使用戶可以進入一個web頁面的筆記部分,我們需要為它提供一個位置。下面我們?yōu)楣P記添加一個表單:
/**
* 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(‘a(chǎn)nnotate_nodetypes‘, array(‘story‘));
if (!in_array($node->type, $types_to_annotate)) {
break;
}
// Add our form as a content item.
$node->content[‘a(chǎn)nnotation_form‘] = array(
‘#value‘ => drupal_get_form(‘a(chǎn)nnotate_entry_form‘, $node),
‘#weight‘ => 10
);
}
}
這個例子看起來有些復雜,所以讓我們詳細的分析一下。首先,注意到我們在這里實現(xiàn)了Drupal的另一個鉤子。這次是_nodeapi,在drupal對節(jié)點進行各種處理的時候將會調用它,所以其他模塊(比如我們的)在處理過程繼續(xù)之前可以修改節(jié)點。我們使用變量$node來表示一個節(jié)點。注意第一個參數(shù)前面的&意味著對于$node對象這里使用參數(shù)傳遞,這非常棒,因為我們在這里對$node所做的任何修改將被保存下來。我們的目標是追加一個表單,所以我們非常高興我們可以修改節(jié)點。
我們仍然需要一些在我們的代碼被調用時Drupal內部將會發(fā)生什么的信息.這些信息保存在參數(shù)$op中了,它可以是insert(節(jié)點被創(chuàng)建),delete(節(jié)點被刪除),或者一個其它的值。當前,我們僅對當節(jié)點被準備顯示出來時,修改節(jié)點感興趣。在這種情況,變量$op的值為view。我們在這里是用了switch控制語句,這樣我們可以非常容易的看到在每種情況下我們的模塊將會做什么。
接下來,我們快速的檢查了一些我們不想呈現(xiàn)注釋域的情況。一種情況是當參數(shù)$teaser為真時.如果它為真,這意味著,這個節(jié)點并不是單獨呈現(xiàn)了,而是呈現(xiàn)在一個列表中,比如說一個搜索引擎的結果中。在這種情況下,我們不需要添加任何東西。另一種情況是$user對象的用戶ID為0時,這意味著用戶沒有登錄。(注意,在這里我們是用了關鍵字global來把$user 對象引進來)。我們使用break語句來跳出switch語句從而阻止修改頁面。
在我們?yōu)?/span>web頁面添加注釋表單的以前,我們需要檢查一下,將要進行顯示的節(jié)點的類型是不是我們在設置頁面所設置的類型中的一個,所以我們回顯了在我們實現(xiàn)的設置鉤子中所保存的節(jié)點類型,并將它保存到了具有可讀性的變量$types_to_annotate中去。對于variable_get()中的第2個參數(shù),我們在這里聲明了一個默認數(shù)組,用于當站點管理員還沒有訪問我們的模塊的配置頁面并設置配置屬性的情況。下面要做的就是檢查一下,我們所要處理的節(jié)點的類型是不是確實是$types_to_annotate中的一種。同樣,我們使用了break語句來放棄,如果節(jié)點類型不是我們想要注釋的時候。
我們最后要做的就是創(chuàng)建表單,并把它添加到$node對象的內容屬性中去。首先,我們需要定義一個表單,這樣我們就有了添加的東西。我們將在一個單獨的函數(shù)中完成這件事,它的唯一責任就是定義表單:
/**
* Define the form for entering an annotation.
*/
function annotate_entry_form($node) {
$form[‘a(chǎn)nnotate‘] = array(
‘#type‘ => ‘fieldset‘,
‘#title‘ => t(‘Annotations‘)
);
$form[‘a(chǎn)nnotate‘][‘nid‘] = array(
‘#type‘ => ‘value‘,
‘#value‘ => $node->nid
);
$form[‘a(chǎn)nnotate‘][‘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[‘a(chǎn)nnotate‘][‘submit‘] = array(
‘#type‘ => ‘submit‘,
‘#value‘ => t(‘Update‘)
);
return $form;
}
和我們在函數(shù)annotate_admin_settings()使用的方式一樣,通過創(chuàng)建一個鍵入的數(shù)組我們創(chuàng)建了表單—只是在這次我們把我們的文本輸入框和提交按鈕放到了fieldset中去,這樣他們在web頁面中就組織到了同一個組下。首先,我們創(chuàng)建一個數(shù)組,它的#type為fieldset,并為它提供了一個標題。然后我們創(chuàng)建文本域數(shù)組。注意,文本域數(shù)組的數(shù)組鍵是fieldset數(shù)組中的一員。換句話說,我們使用$form[‘a(chǎn)nnotate‘][‘note‘]替換了$form[‘note‘]。這樣,Drupal將把這個文本域元素當作fieldset元素中的一員。最后,我們創(chuàng)建了提交按鈕,然后返回了定義我們表單的數(shù)組。
現(xiàn)在讓我們回到annotate_nodeapi()上,通過向節(jié)點的內容添加一個#value和一個#weight,我們將創(chuàng)建的表單追加到了頁面的內容上。值包含了要展示的內容,重量告訴Drupal把它展示到哪里。我們想把我們的注釋表單放到頁面的下面,所以我們?yōu)樗峙淞艘粋€相對較大的重量10.我們要展示的是我們的表單,所以我們調用函數(shù)drupal_get_form()來將我們的表單從一個描述如何創(chuàng)建它的數(shù)組的形式轉化為最終的HTML表單。注意,在這里我們事如何將$node對象傳遞到我們的表單函數(shù)中去的。我們需要這樣做來得到以前的注釋并把它預先填充到表單中。
使用你的web瀏覽器查看一個頁面,你應該可以看到這個用于追加的注釋表單(如圖2-2所示):
圖2-2出現(xiàn)在drupal web 頁面上的注釋表單
當我們點擊Update按鈕時,將會發(fā)生什么呢?什么都沒有,因為我們還沒有為它寫任何代碼呢?,F(xiàn)在就讓我們添加這些代碼。但是在我們出發(fā)以前,我們不得不考慮一下我們將把用戶輸入的數(shù)據(jù)存儲到哪里。
把數(shù)據(jù)存儲到數(shù)據(jù)庫表中
存儲一個模塊的數(shù)據(jù)的最常用的方式是為這個模塊創(chuàng)建一個單獨的數(shù)據(jù)庫表。這將使得模塊的數(shù)據(jù)與drupal核心數(shù)據(jù)表區(qū)分開來。當決定為你的模塊創(chuàng)建那些字段時,你應該問自己:你需要存儲哪些數(shù)據(jù)?如果我對這個表進行查詢時,我將需要什么?最后,還要為我的模塊考慮將來的有哪些計劃?
我們需要存儲的數(shù)據(jù)僅僅為注釋的文本,注釋所用到的節(jié)點的數(shù)字ID,和填寫注釋的用戶的用戶ID。保存一個時間戳也會非常有用,這樣我們可以按照時間戳將最近更新的注釋排成一列展示出來。最后,我們查詢這張表的主要問題是,”這個用戶對這個節(jié)點做了哪些注釋?”我們將在uid和nid字段上創(chuàng)建一個復合的索引,從而使我們最常用的查詢盡可能的快。用來創(chuàng)建我們的表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文件中,這樣其他想要安裝這個模塊的用戶將不得不手工的將數(shù)據(jù)庫表添加到他們的數(shù)據(jù)庫中。另一種方式,當你啟用你的模塊時,Drupal為你提供了自動創(chuàng)建相應的數(shù)據(jù)庫表的工具,我們將充分利用這種方式的優(yōu)勢。我們創(chuàng)建一個特定的文件;文件名開始部分為你的模塊名以后綴.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‘);
}
}
這個文件簡單直接。當?shù)谝淮螁⒂?span lang="EN-US">annotate 模塊時,drupal會尋找文件annotate.install并運行函數(shù)annotate_install(),如果一切順利的話,數(shù)據(jù)庫表將被創(chuàng)建。通過禁用然后再啟用這個模塊,現(xiàn)在就可以完成它。
秘密消息:如果在你的.install文件中包含一個文字錯誤,或者由于其他原因執(zhí)行失敗,你可以使drupal忘記你的模塊和它對應的表,Administer ? Site building ? Modules禁用你的模塊,然后在數(shù)據(jù)庫的system表中刪除對應模塊的一行。
當創(chuàng)建了用以存儲數(shù)據(jù)的表以后,我們將不得不對我們的代碼做一些修改。其一,我們將需要添加一些代碼,一旦用戶填入注釋并且點擊Update按鈕以后,用來解決對數(shù)據(jù)的處理流程。我們用于表單提交的函數(shù)如下:
/*
* 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.‘));
}
由于我們僅允許一個用戶對一個節(jié)點只能有一個注釋,所以我們可以安全的刪除以前的注釋(如果存在的話)然后插入我們自己的到數(shù)據(jù)庫中。對于我們于數(shù)據(jù)庫的交互,有幾點需要注意。首先,我們不需要考慮數(shù)據(jù)庫連接,這是因為在Drupal的引導程序中他已經(jīng)為我們完成了這一工作。第2,當我們是用一個數(shù)據(jù)庫表時,我們需要把它放到花括號里{}.這樣可使數(shù)據(jù)庫的前綴化無縫的集成(參看http://drupal.org/node/2622)。第三,我們在查詢語句中使用了占位符,然后為其提供相應的變量,這樣Drupal內建的查詢清潔機制可以啟用以阻止SQL注入攻擊。我們使用%d占位符用于數(shù)字,使用%s占位符用于字符串。然后,我們使用drupal_set_message()來在用戶的會話中插入一消息,它將會在用戶查看的下一個頁面中被Drupal作為一個通知展示出來。這樣,用戶可以獲得一些反饋信息。
最后,我們需要修改我們的nodeapi鉤子代碼,這樣的話,如果已經(jīng)存在了一個注釋,它將被從數(shù)據(jù)庫中取出。恰好在我們把我們的表單分配給$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);
我們首先查詢數(shù)據(jù)庫以取出這一用戶對一節(jié)點所做的注釋。接著,我們使用db_result來從結果集中取出第一行。由于我們僅允許一個用戶對同一節(jié)點只能做一個注釋,所以結果集中也只有一行。
測試你的模塊。他現(xiàn)在應該能夠保存和回顯注釋了。拍下你的背---你已經(jīng)從頭開始創(chuàng)建了一個模塊了?,F(xiàn)在你已經(jīng)站在了成為Drupal核心開發(fā)者的大道上了。
更遠的一些步驟
我們將與開源社區(qū)分享這一模塊,這是自然的,所以需要創(chuàng)建一個README.txt文件,然后把它放到annotation的目錄下,和notate.info,annotate.module,annotate.install文件放在一起。接下來,你可以把它上傳到drupal.org上的貢獻模塊庫中,然后創(chuàng)建一個項目頁面來追蹤社區(qū)中其他用戶的反饋。
總結
當讀完這一章后,你應該可以:
從頭創(chuàng)建一個Drupal模塊
了解如何鉤住Drupal代碼的執(zhí)行
存儲和回顯特定模塊的設定
使用Drupal的表單API來創(chuàng)建和處理一些簡單的表單
使用數(shù)據(jù)庫來存儲和回顯數(shù)據(jù)。
發(fā)表于 @ 2007年09月22日 17:10:00|評論(0)|編輯