您在這裡

請教: 這種模組開發的方式

bobju's 的頭像
bobju 在 2010-06-16 (三) 01:11 發表

期待有模組開發經驗的高手們給 bobju 一些指引, 問題條列如下:

1 設計一個[簡訊管理模組], 需要處理兩個 content type 分別為:
1.1 {門號}
1.2 {己發簡訊}

2 由於每通{已發簡訊}必定是由一個{門號}發出, 所以{已發簡訊}要有一個 node reference 參考{門號}

3 資料的新增方式:
3.1 透過 url 傳資料, 走 HTTP GET, 不考慮加密. 例如: http://主機網址/接收點/門號值/簡訊內容
3.2 [簡訊管理模組]能夠處理接收到的 門號值 及 簡訊內容 , 將之存到資料庫.

4 現在打算這樣設計:
4.1 先建立{門號}及{已發簡訊}這兩個 content type,
4.2 再以 CCK 建立{已發簡訊}對{門號}的 node reference,
4.3 然後再針對{門號}及{已發簡訊}, 實作[簡訊管理模組]來處理上述的 3.
4.4 能夠另外透過 Views 做{門號}及{已發簡訊}的報表管理.

5 目前參考的資料主要有:
5.1 Pro Drupal Development :
5.1.1 此書當中採用方式是一體成形法. 連同資料的 schema definition 都包在 [module].install 裏.
5.2 drupal.orgAPI reference 下的:
5.2.1 Components of Drupal 下的:
5.2.1.1 Menu system
5.2.2 Example modules 下的:
5.2.2.1 How to define content (node) types
5.2.2.2 How to extend existing content types
5.2.2.3 How to define pages

6 目前問題:
6.1 不知 4 這樣的方式是否可行?
6.2 上述 5 所參考的資料中所採用的方式, 似乎都沒涉及 CCK. 若不用 CCK 的話, 那麼上述 4.4 的支援度是否會變差?

謝謝看完. XD

真的可以呢,跟著看到最後就完成了,以後要多跟 bobju 學習。

不知你的{門號}是什麼,match 資料時要注意效能,是否唯一,可否當作使用者,有沒有存在等問題 ....

還要注意這個:
http://support.microsoft.com/kb/208427
(其他瀏覽器會多一點)

---
notaBlueScreen | 一天一翻譯,好過吃蘋果

Kay.L 真是太強了, 跟著看完就完成了. XD
我還搞不太懂在程式中如如何建立{已發簡訊}對{門號}的關聯. 因為我目前看到的例子可能還太少, 沒有範例. 只知應該是跟hook_nodeapi 有關.
我應該拆成兩個模組分別做{已發簡訊}以及{門號}的新增嗎? 意即{門號}在[門號模組]當中先新增, 而[已發簡訊模組]則利用hook_node_api 攔截 'insert' 這項操作, 在判定: "是由 '門號' 的 node 所發出" 的條件成立時, 再把其node->nid 填入 {已發簡訊} 的 node reference 欄位?

我想的比較單純,不知是否你想達到的

HTTP 請求:example/625/this is a message --->
你上面的 page_example 處理 --->
假如 {門號} 是已存在 -> SAVE 成為 {已發簡訊}
當然你要新增 {門號} 才 SAVE 也可以... (我以為世界沒有免費午餐)

我參考了這篇:
http://www.notabluescreen.com/create-node-migrating-site
然後修改 page_example ,有用了 arg(),以及很基本的 PHP

門號 = 電話號碼 ??

---
notaBlueScreen | 一天一翻譯,好過吃蘋果

是的, {門號} 意指 電話號碼.

我是想做一個網站的api, 接收這種形式: "http://伺服主機網址/接收點/門號/簡訊內容" 的 url 所傳進來的 data.

這個過程中, 沒有 user 手動 key 資料的動作介入, 完全是由遠端主機(資料來源)裏會有一支專門餵資料的程式, 會以上述的 url 將資料傳到伺服主機這邊來.

而我所要做的安排是: 伺服主機這邊收到了, 就從 hook_menu() 處理 url 開始, 直到所有資料都存入了該存的資料庫欄位裏, 並回應結果訊息.

若照一般 php 程式的寫法來做的話, 是不成問題的. 但現在卡在對於 drupal hook system 不熟, 整個流程分解成好幾個小動作: 接收url, 剖析參數, 針對所需的 content type 新增 node, 建立 node 之間的關聯, 每個小動作對我而言都形同卡關, 還要持續奮鬥下去. XD

node 之間的關聯, 我想用 CCK 的 node reference 做的原因是: 後續 Views 對 CCK 的支援比較完整, 要拉報表就簡單多了.

目前是不了解該如何在程式中建立 CCK node reference 來聯結{門號}及{已發簡訊}, 只知應該跟 hook_nodeapi 有關.

嗨嗨, Kay.L 大:

我最後發現原來是我想偏了, 未必要跟 nodeapi 有關. 您在部落格上提到的 node_save() 即是關鍵.

要儲存{門號}跟{已發簡訊}之間的關聯(CCK node reference)沒有想像中那麼複雜, 因為執行 node_save($node) 或是 content_insert($node) 時, 其內部運作已把細節都處理掉了.

以下是我整理出來的程式碼, 目前已把原來發問要做的東西搞定. 或許還有些細節沒處理到, 但至少確定方法是可行的了.

<?php
function node_example_menu() {
// 在 hook_menu 當中, 定義接收參數的路徑, 把接收到的參數引導到指定的callback: _node_example_sms 處理
$items['sms/%/%'] = array(
'title' => 'Node example: (sms)',
'page callback' => '_node_example_sms', // 指定 callback
'page arguments' => array(1, 2), // 指定要傳給 _node_example_sms 的參數是 第1個, 及第2個. (0-base, 第0個是 sms)
'type' => MENU_CALLBACK,
'access callback' => TRUE
);

return $items;
}

function _node_example_sms($mobile_phone, $sms) {
// 若門號不是數字, 則回傳 'false', 代表錯誤.
if ( !is_numeric($mobile_phone) ) {
return 'false';
}
//先新增一筆{門號}, (暫不考慮例外處理)
$mp = _build_new_mobile_phone($mobile_phone);

//再新增一筆{已發簡訊}, (暫不考慮例外處理)
_build_new_sms($mp, $sms);

//回傳 'ok', 代表處理成功.
return 'ok';

}

function _build_new_sms(&$mobile_phone, $title_hint=NULL){
$newnode = new stdClass();
$newnode->is_new=1;
$newnode->title = !empty($title_hint) ? $title_hint:"0";
$newnode->type = 'sms'; // {已發簡訊} 的 content type 名稱.
$newnode->uid = 1;
$newnode->teaser = "";
$newnode->status = 0; //unpublished
$newnode->created = time();
$newnode->changed = time();
$contenttype = content_types($newnode->type);

//在此指定 {門號} 的 nid 給 {已發簡訊} 的 node reference.
$newnode->field_mobile_phone[0]['nid'] = $mobile_phone->nid;

// 若 $newnode 尚有屬性在上面未給值, 卻在widget裏有定義預設值, 則在此指定預設值:
foreach ($contenttype['fields'] as $fieldname => $field) {
if(isset($field['widget']['default_value']) && empty($newnode->$fieldname) ) {
$newnode->$fieldname = $field['widget']['default_value'];
}
}
// node_save 儲存成功後, $newnode 的 nid 及 vid 自動會被填值.
node_save($newnode);

// 若 $newnode 裏有 CCK 建立的欄位, 則由 cotent_insert 負責處理儲存的細節.
content_insert($newnode);

return $newnode;
}

function _build_new_mobile_phone($title_hint){ // {門號}的新增函式, 結構跟{已發簡訊}的新增函式差不多.
$newnode = new stdClass();
$newnode->is_new=1;
$newnode->title = !empty($title_hint) ? $title_hint:"0";
$newnode->type = 'mobile_phone'; // {門號} 的 content type 名稱.
$newnode->uid = 1;
$newnode->teaser = "";
$newnode->status = 0; //unpublished
$newnode->created = time();
$newnode->changed = time();
$contenttype = content_types($newnode->type);
foreach ($contenttype['fields'] as $fieldname => $field) {
if( isset($field['widget']['default_value']) && empty($newnode->$fieldname) ) {
$newnode->$fieldname = $field['widget']['default_value'];
}
}
node_save($newnode);
content_insert($newnode);

return $newnode;
}

?>

^_^

如果你用了

<?php
node_object_prepare($node);
?>
就不用再指定一些預設的東西,如:

<?php
$newnode->created = time();
$newnode->changed = time();
?>

像是 teaser 並不會自動生成的
<?php
$newnode->teaser = "";
?>

除非你有這一步
<?php
$new_node = node_submit($node);
?>

還要注意 node_save() 是沒有驗證資料的正確性的,要留意,也沒有 catch err (D7 有)
使用 drupal_execute() 模擬 FORM 提交就會很完整,但這會比前者慢 !!

多來支持我的 BLOG 哦 ^_^
---
notaBlueScreen | 一天一翻譯,好過吃蘋果