這幾天剛開始學(xué)習(xí)Drupal, 把自己的一些理解記錄下來, 希望大家能指正, 也更希望結(jié)識(shí)正在學(xué)習(xí)的同道, 一起努力.
從頭學(xué)習(xí)Drupal--基本概念一
節(jié)點(diǎn)(Node)
我們知道Drupal是一個(gè)內(nèi)容管理系統(tǒng)(CMS), 而一般我們所管理的內(nèi)容, 就是新聞或博文之類的文章; 在通常意義上, 這些就是Drupal中的節(jié)點(diǎn), 但Drupal并不是只能管理文章類內(nèi)容, 它對(duì)所管理的內(nèi)容進(jìn)行了抽象, 形成了節(jié)點(diǎn)的概念. 如果我們學(xué)過面向?qū)ο蟮闹R(shí), 那我們就知道節(jié)點(diǎn)其實(shí)就是Drupal這個(gè)系統(tǒng)所管理內(nèi)容的虛基類.
Drupal的核心定義了節(jié)點(diǎn)這個(gè)對(duì)象的各種抽象行為和基本屬性, 同時(shí)它頁實(shí)現(xiàn)了基于文本方式來表達(dá)內(nèi)容的兩種節(jié)點(diǎn)類型, :Page 和 Story. 自然節(jié)點(diǎn)類型就是節(jié)點(diǎn)的具體實(shí)現(xiàn)了, 也就是節(jié)點(diǎn)的子類. 雖然Drupal的核心僅實(shí)現(xiàn)了簡單的文本描述節(jié)點(diǎn), 但它允許你可以自己擴(kuò)展更多的節(jié)點(diǎn)類型. 目前Drupal社區(qū)已經(jīng)有很多擴(kuò)展模塊實(shí)現(xiàn)了圖像或視頻內(nèi)容的管理, 同時(shí)也有大名鼎鼎的CCK模塊允許你定義更為節(jié)點(diǎn)的更多細(xì)節(jié), 這里我們略過不表, 下面為了更進(jìn)一步了解節(jié)點(diǎn)的概念, 我們到數(shù)據(jù)庫(node表)看看它的主要字段:
- 節(jié)點(diǎn)ID, 自動(dòng)增加的唯一索引;
- 版本ID, 用來追溯內(nèi)容修訂;
- 屬性 比如發(fā)布狀態(tài), 語言, 類型等等;
- 操作信息 創(chuàng)建或修改時(shí)間, 操作者等;
- 內(nèi)容 標(biāo)題部分, 內(nèi)容部分, 可能有的節(jié)點(diǎn)類型沒有此實(shí)際數(shù)據(jù);
評(píng)論(Comment)
評(píng)論雖然也是文章形式, 而且它和普通文章也很象, 但實(shí)際上它不是一種節(jié)點(diǎn)類型, 它被實(shí)現(xiàn)為一種依附于節(jié)點(diǎn)的用戶反饋機(jī)制. 它與節(jié)點(diǎn)是否存在本質(zhì)區(qū)別, 是否有必要分成兩類對(duì)象, 這個(gè)好像也一直在討論之中, 不知道在Drupal 7中會(huì)不會(huì)把它合入節(jié)點(diǎn)框架中. 但我個(gè)人認(rèn)為, 目前Drupal似乎還沒有節(jié)點(diǎn)與節(jié)點(diǎn)發(fā)生關(guān)聯(lián)的情況, 這樣把評(píng)論與節(jié)點(diǎn)分開是非常清晰的, 如果后續(xù)有此類需求, 則把評(píng)論納入節(jié)點(diǎn)管理是順理成章的事.
分類(taxonomy)
形象的說就是給節(jié)點(diǎn)分類, 它由一系列術(shù)語表組成, 每個(gè)術(shù)語表可以定義n多的術(shù)語, 這樣你可以用術(shù)語對(duì)你的內(nèi)容進(jìn)行標(biāo)記, 從而達(dá)到分門別類的作用. 當(dāng)然你的分類是否合理, 是否有效, 還得看你的術(shù)語表定義了. 比如說一篇技術(shù)文章, 你可以從其使用的技術(shù)領(lǐng)域來劃分, 也可以從其應(yīng)用的領(lǐng)域來劃分, 甚至可以從作者的性別進(jìn)行劃分. 總之, 分類就是個(gè)門綱目科屬的工作, 不過這可不是個(gè)簡單的活, 記得專門好像還有圖書管學(xué)來專門研究圖書的分類呢.
邊學(xué)習(xí)邊總結(jié), 又補(bǔ)充一個(gè)分類的概念, 因?yàn)檫@個(gè)也是Drupal核心中針對(duì)內(nèi)容的相關(guān)概念 -- xeopn
從頭學(xué)習(xí)Drupal--基本概念二
- 新手專區(qū)
- Drupal6.x
從頭學(xué)習(xí)Drupal--基本概念二
區(qū)域(Region)
這個(gè)概念其實(shí)只涉及到表現(xiàn)層, 簡單來說就是把頁面進(jìn)行劃分, 分成一塊塊獨(dú)立的空間, 比如裝修做二室一廳, 那就有廳, 廚房, 衛(wèi)生間, 主臥, 輔臥等, 當(dāng)然頁面不是毛坯房了, 一般它分為五個(gè)區(qū)域: header, footer, conten, right sidebar, left sidebar.
區(qū)塊(Block)
在Drupal的世界里, 什么東西都是圍繞節(jié)點(diǎn)(Node)展開的, 那節(jié)點(diǎn)又是為誰呢, 當(dāng)然是用戶, Drupal的用戶管理并沒有太多特別的地方, 所以我們也就不談了. 繞了半天, 到底談嘛嗎?
"談理想", "談戀愛", 錯(cuò)嘛, 我們還是談節(jié)點(diǎn). 用戶訪問你的網(wǎng)站干嘛? 想看點(diǎn)內(nèi)容嘛, 內(nèi)容是嘛嗎, 是節(jié)點(diǎn). 那光看節(jié)點(diǎn)嗎? 打比方說了, 你肚子餓了進(jìn)飯店, 你光叫2碗米飯麼? 當(dāng)然還得點(diǎn)幾個(gè)小菜, 興致到了再喝點(diǎn)小酒, 在Drupal眼里, 這些其他的就是區(qū)塊咯. 可能有較真的看官說話了, 小菜和酒也都可以看做是一種派生內(nèi)容類型(Content Type)啊, 它們也都可以看作節(jié)點(diǎn)啊. 那就借一步說話了, 飯店的招牌, 墻上的推薦菜, 你點(diǎn)菜看的菜單, 這些圍繞在你吃的主題周圍的露出和諧笑容的東東那就是區(qū)塊(Block). 某書有云: a block is a chunk of auxiliary information that is displayed on a page alongside the main page content.
放到我們經(jīng)典的文章頁面上來看: 中間大塊的是文章內(nèi)容, 而在其他區(qū)域也放著東西呢, 比如一個(gè)站點(diǎn)菜單, 最新評(píng)論列表, 日歷等等. 在Drupal中, 這些附加的輔助性的信息就是區(qū)塊.
區(qū)塊定義在數(shù)據(jù)庫表(block)中, 從表結(jié)構(gòu)可以看出, 區(qū)塊由bid標(biāo)識(shí), 與模塊(Module)和主題(Theme)都是強(qiáng)關(guān)聯(lián), 甚至Drupal已經(jīng)為block表建立了tmd(theme module delta)唯一索引. 其實(shí)block也是一種輔助的內(nèi)容形式, 所以它由模塊定義實(shí)現(xiàn), 而block只能算是頁面上的可選元素, 所以在展現(xiàn)上, 它必須與主題掛鉤, 以決定是否在該主題中被顯示. 同時(shí)區(qū)塊還與角色勾三搭四, 以便于頁面顯示信息與用戶掛鉤.
菜單(Menu)
從實(shí)質(zhì)上說, 菜單就是一個(gè)區(qū)塊(Block), 當(dāng)然菜單擴(kuò)展了很多屬性和行為, 使得它成為Drupal中一個(gè)非常強(qiáng)大的導(dǎo)航系統(tǒng). 可以說當(dāng)一個(gè)區(qū)塊成為菜單后, 它就不是一個(gè)人在戰(zhàn)斗了... 這個(gè)暫時(shí)霧里看花, 先不深究.
從頭學(xué)習(xí)Drupal--基本架構(gòu)一
- 新手專區(qū)
- Drupal6.x
前面學(xué)習(xí)了Drupal的一些基本概念, 其實(shí)我們?cè)跇?gòu)建一個(gè)系統(tǒng)的時(shí)候, 一般都需要從兩個(gè)方面來考慮問題:
- 業(yè)務(wù)模型
也就是領(lǐng)域模型, 是面向我們所要解決的問題域所構(gòu)建的模型, 前面我們說的關(guān)于內(nèi)容描述方面的幾個(gè)概念, 其實(shí)就是對(duì)領(lǐng)域內(nèi)概念,元素進(jìn)行概括,抽象得出的業(yè)務(wù)模型基類. 構(gòu)建良好的業(yè)務(wù)模型, 能有效地將問題域中的對(duì)象進(jìn)行分類,綜合, 理清他們間的關(guān)聯(lián), 闡明他們相互間的協(xié)作, 并為最終形成系統(tǒng)的對(duì)象數(shù)據(jù)模型打下基礎(chǔ). 我們所說的面向?qū)ο?OO), 其實(shí)主要就是一個(gè)建模的思想.
- 系統(tǒng)架構(gòu)
它是從系統(tǒng)的實(shí)現(xiàn)角度出發(fā)的, 涉及的概念更多, 它主要是用來解決系統(tǒng)如何構(gòu)建, 以實(shí)現(xiàn)業(yè)務(wù)的需求, 它還涉及系統(tǒng)的健壯性, 性能, 可擴(kuò)展性, 可操作性, 可獲得性等一些其他質(zhì)量屬性. 比如經(jīng)典的MVC架構(gòu), WEB的二層, 三層, 四層架構(gòu), 這些都是架構(gòu)實(shí)現(xiàn)的一種形式.
這兩方面相輔相成, 任何一方面設(shè)計(jì)不好都將極大的影響系統(tǒng)的質(zhì)量(Quality). 很多人在系統(tǒng)設(shè)計(jì)時(shí)出于某種主觀或客觀原因要么從單方面考慮, 要么是把兩者混淆起來考慮, 這都不是好的系統(tǒng)設(shè)計(jì)方法, 都有很大的局限性.
說了這么些沒人感興趣的東西, 還是回到我們的主題, Drupal的架構(gòu). 其實(shí)我目前還是粗略看了Drupal, 主要是爬爬洋文, 大概看了一下bootstrap的代碼; 所以下面的描述主要關(guān)注Drupal的主體框架, 對(duì)其內(nèi)部不進(jìn)行深入描述(能力問題, 象國足看齊); 而且因?yàn)槲冶旧淼亩嗾Z言支持(Internationalization)實(shí)現(xiàn)的并不太好, 這里記錄下來的就是僅我自己的理解, 供你們參考和指正.
什么是Drupal的架構(gòu)?
簡單的說, Drupal是一個(gè)基于B/S架構(gòu)的內(nèi)容管理系統(tǒng)(CMS), 它用PHP語言實(shí)現(xiàn), 并以關(guān)系數(shù)據(jù)庫為存儲(chǔ)機(jī)制. 與其說它是一個(gè)CMS, 不如說它是一個(gè)CMS框架更好. 單純做博客(Blog), 它不如WordPress簡單快速; 直接當(dāng)CMS, 它不如Joomla美觀方便, 甚至不如某些國產(chǎn), 但其實(shí)經(jīng)過擴(kuò)展, Drupal能夠做得與它們一樣好, 甚至更好, 這就取決于Drupal幽雅的架構(gòu)設(shè)計(jì). 這里我為啥用幽雅不用優(yōu)雅呢? 其實(shí)就在于Drupal的具體實(shí)現(xiàn), PHP本身是支持面向?qū)ο?OO)的, 但Drupal卻為了兼容老版本并沒有使用, 而是通過一系列的約定俗成的編碼約定(Convention)來達(dá)到類似的效果. (期待Drupal 7的到來...)
好了, 下面是一個(gè)我簡單畫的Drupal的系統(tǒng)架構(gòu)圖.
我們看到, Drupal主要是一個(gè)三層結(jié)構(gòu): 表現(xiàn)層, 邏輯層和數(shù)據(jù)持久層. 顧名思義, 數(shù)據(jù)持久層主要是處理數(shù)據(jù)的持久化, 它是領(lǐng)域模型在具體數(shù)據(jù)庫中的實(shí)現(xiàn); 而邏輯層則基于領(lǐng)域模型進(jìn)行數(shù)據(jù)的業(yè)務(wù)邏輯處理, 它是整個(gè)結(jié)構(gòu)的核心; 表現(xiàn)層則側(cè)重于領(lǐng)域數(shù)據(jù)的呈現(xiàn)和工作流在用戶側(cè)的控制表現(xiàn), 它主要基于以用戶為中心來設(shè)計(jì)(UCD).
邏輯層, 包括兩部分:Drupal的核心庫和模塊組(Modules).
核心庫主要包含Druapl的請(qǐng)求流程(Bootstrap)和一系列常用的公共支撐庫, 比如數(shù)據(jù)庫抽象接口, 多語言支持, 郵件處理, 圖像優(yōu)化等. 當(dāng)然還有最關(guān)鍵的鉤子(hook)框架, 鉤子是貫穿Drupal核心的一個(gè)重要特性, 它使得Drupal能高效靈活地協(xié)調(diào)模塊們的工作. 這里把它叫做核心庫確實(shí)不妥當(dāng), 以為它不僅僅是一個(gè)庫, 更是一個(gè)公共框架.
模塊就是Drupal的功能組件, 它處理具體的業(yè)務(wù)邏輯, 模塊如何劃分, 取決于你的業(yè)務(wù)劃分, 你的工作流, 你的設(shè)計(jì)思想.Drupal安裝包里包涵了10多個(gè)模塊, 但它最核心的只有5個(gè)模塊: Block, Filter, Node, System, User. 如果說核心庫是劉備的話, 那這五個(gè)就是他的五虎上將了. 看看他們的功能吧, System使得系統(tǒng)具備了系統(tǒng)管理的能力, User使得系統(tǒng)具備了安全管理的能力, Node+Block+Filter使得系統(tǒng)具備了基本內(nèi)容管理的能力.
天哪, Drupal難嗎, 真的不難, 這就是一個(gè)系統(tǒng)的完整原型, 這架構(gòu)就是多少人心目中的完美架構(gòu)啊! 從這里出發(fā), 你就能實(shí)現(xiàn)任何你想要的了, 想要什么就實(shí)現(xiàn)個(gè)什么模塊, 什么自己做不了, 怕什么, 社區(qū)里有的是人在做, 拿來主義就行啊.
表現(xiàn)層, 有多少人是沖著Drupa的l外觀來的, 應(yīng)該不多吧, 你要真沖這個(gè)來, 還真得勸你去選個(gè)別的CMS, 沒必要和自己驕矜.
但是,對(duì)一個(gè)CMS系統(tǒng)來說, 可定制的外觀是必須提供的能力的. 因此, Drupal提供了相當(dāng)強(qiáng)大的內(nèi)容表現(xiàn)擴(kuò)展機(jī)制--主題(Theme)系統(tǒng), 真的是很黃很暴力, 它包含主題引擎和主題兩個(gè)子層, 允許開發(fā)者全方位控制內(nèi)容的表現(xiàn). 系統(tǒng)對(duì)最終用戶的輸出, 你可以從主題層輸出, 也可以從主題引擎層輸出, 還可以直接從邏輯層里的模塊層輸出; 什么, 你不想實(shí)現(xiàn)表現(xiàn)層? OK, 完成一個(gè)機(jī)機(jī)接口的純后臺(tái)系統(tǒng)也是你的選擇. 不過太靈活并不一定是好事, 特別在一個(gè)具體的項(xiàng)目開發(fā)過程中, 記住, 制定必要的開發(fā)規(guī)約是保證項(xiàng)目質(zhì)量和進(jìn)度的有效手段.
還是回到正題, 雖然Drupal的整個(gè)主題機(jī)制強(qiáng)大復(fù)雜, 但在機(jī)制的最頂層--主題, 卻并不復(fù)雜. 它簡單到由一系列的模板文件, CSS文件, JS文件和圖片即可定義出美侖美奐的外觀.
持久層, 支持關(guān)系型數(shù)據(jù)庫, 模塊一般通過核心的數(shù)據(jù)庫API訪問, 你想直接訪問數(shù)據(jù)庫也支持, 但最好還是通過API, 這樣便于遷移和擴(kuò)展.
從頭學(xué)習(xí)Drupal--基本架構(gòu)二
- 新手專區(qū)
- Drupal6.x
前面說了, Drupal的邏輯層由一個(gè)核心框架和一系列的功能模塊(Module,可以看成插件)構(gòu)成, 框架與模塊間的協(xié)調(diào)就是通過鉤子機(jī)制來實(shí)現(xiàn), 所以鉤子機(jī)制是Drupal模塊化系統(tǒng)的關(guān)鍵。什么是鉤子機(jī)制, 它與面向?qū)ο蟮慕涌?Interface)類似, 就是為規(guī)范定義了兩個(gè)實(shí)體間的功能界面, 使得實(shí)現(xiàn)了該界面的實(shí)體能進(jìn)行交互. 在Drupal里, 鉤子就是Drupal框架與模塊間進(jìn)行交互的接口, 但由于Drupal沒有面向?qū)ο蟮臋C(jī)制, 所以它采用編程規(guī)約來討巧地實(shí)現(xiàn).
在Drupal里, 鉤子就是一系列需要實(shí)現(xiàn)特定功能的函數(shù), 它們約定好了輸入?yún)?shù)和返回類型, 同時(shí)約定以xxx_yyy() 的形式來命名, 其中xxx是要實(shí)現(xiàn)功能的模塊名稱,而yyy則是具體的鉤子名稱 . 舉個(gè)例子, 你就更清楚了. 例如我有個(gè)模塊叫myexamplemodule, 現(xiàn)在我想在footer中添加一些Javascript代碼, 于是我在我的模塊代碼中實(shí)現(xiàn)一個(gè)叫myexamplemodule_footer()的函數(shù), 在此函數(shù)中我實(shí)現(xiàn)了我想要功能; 于是用戶請(qǐng)求頁面時(shí), Drupal的框架會(huì)檢測(cè)到我的模塊有myexamplemodule_footer()函數(shù), 并且它會(huì)自動(dòng)調(diào)用它, 是不是很簡單明了呢! Drupal核心框架的這種調(diào)度機(jī)制, 屏蔽了用戶自定義模塊與框架間的實(shí)際交互, 簡化了的開發(fā), 因?yàn)槟阒灰獙?shí)現(xiàn)一個(gè)函數(shù)即可, 別的事情系統(tǒng)已經(jīng)替你完成了. 更多的hook請(qǐng)查看Drupal的文檔庫.
Hook機(jī)制主要在模塊管理(includes/module.inc)中實(shí)現(xiàn), 主要有的四個(gè)主要函數(shù), 非常簡單.
- module_hook($module, $hook)
- 判斷某模塊是否實(shí)現(xiàn)某鉤子
- module_implements($hook, $sort = FALSE, $refresh = FALSE)
- 判斷哪些模塊實(shí)現(xiàn)某鉤子, 返回模塊名數(shù)組
- module_invoke()
- 調(diào)用具體模塊的具體鉤子, 變長參數(shù), 參數(shù)包括模塊名, 鉤子名, 還有鉤子函數(shù)的參數(shù)
- module_invoke_all()
- 調(diào)用所有模塊的具體鉤子, 變長參數(shù), 參數(shù)包括鉤子名, 鉤子函數(shù)的參數(shù)
下面看一下module_invoke_all()函數(shù)的具體實(shí)現(xiàn), 該函數(shù)會(huì)在Bootstrap過程中被框架調(diào)用.
<?php
function module_invoke_all() {
$args = func_get_args();
$hook = $args[0];
unset($args[0]);
$return = array();
foreach (module_implements($hook) as $module) {
$function = $module .'_'. $hook;
$result = call_user_func_array($function, $args);
if (isset($result) && is_array($result)) {
$return = array_merge_recursive($return, $result);
}
else if (isset($result)) {
$return[] = $result;
}
}
return $return;
}
?>
Drupal的鉤子實(shí)現(xiàn)起來也比較靈活, 不想實(shí)現(xiàn)某鉤子, 不寫那個(gè)函數(shù)即可, 這樣可以減少PHP文件的代碼, 提高效率. 不過看起來還是有些龐大的感覺, 因?yàn)橹灰獙?shí)現(xiàn)了該鉤子函數(shù)的模塊, 就會(huì)被調(diào)用, 這樣應(yīng)該會(huì)導(dǎo)致在輸出某內(nèi)容時(shí), 系統(tǒng)還會(huì)加載并執(zhí)行其他無關(guān)的模塊. 總之, 粗淺一看, 這里應(yīng)該是個(gè)性能瓶頸.
從頭學(xué)習(xí)Drupal--基本架構(gòu)三
- 新手專區(qū)
- Drupal6.x
菜單(Menu)
前面曾經(jīng)簡單提到過Drupal的菜單, 今天稍微深入來探討一下. 菜單能用來顯示導(dǎo)航信息, 我們安裝的系統(tǒng), 默認(rèn)安裝有3個(gè)菜單, 讓我們查看一下數(shù)據(jù)庫吧, 以menu_開頭的總共有三張表: menu_custom, menu_links, menu_router. 其中menu_custom表存放菜單定義信息, 但想知道他們都是由哪個(gè)模塊定義的麼? 別忘記了菜單如果要顯示就是區(qū)塊哦, 打開區(qū)塊表(blocks)看看吧. Here it is! 用戶模塊(User Module)定義了Navigation菜單(沒看數(shù)據(jù)庫我以為是系統(tǒng)模塊(System Module)定義的呢), 菜單模塊(Menu Module)定義了Primary links和Secondary links兩個(gè)空菜單. 所以從表現(xiàn)層來看, 一個(gè)菜單就對(duì)應(yīng)一個(gè)區(qū)塊(Block), 它被放置在頁面的某個(gè)區(qū)域(Region)來顯示給用戶進(jìn)行導(dǎo)航.
其實(shí)Drupal的菜單機(jī)制不僅要能把導(dǎo)航顯示給用戶, 更重要的是在用戶點(diǎn)擊這些導(dǎo)航的時(shí)候, 能夠準(zhǔn)確快速定位到相應(yīng)的業(yè)務(wù)邏輯. 有人會(huì)問, 難道這也是個(gè)問題嗎? 要知道導(dǎo)航其實(shí)都對(duì)應(yīng)他們具體的URI, 而傳統(tǒng)的URI的定位是先按目錄結(jié)構(gòu)找處理文件, 然后根據(jù)Request參數(shù)對(duì)應(yīng)業(yè)務(wù)邏輯,同時(shí)還要在業(yè)務(wù)邏輯中判斷用戶權(quán)限; 而Drupal有一套自己的內(nèi)部路徑, 它是基于模塊化構(gòu)建的, 與目錄結(jié)構(gòu)一點(diǎn)關(guān)系也沒有了, 所以必須要有一套機(jī)制能在URI和業(yè)務(wù)邏輯間進(jìn)行映射, 而Drupal的菜單機(jī)制就是完成這項(xiàng)工作的, 用戶點(diǎn)擊菜單項(xiàng)鏈接時(shí), Drupal解析出內(nèi)部路徑, 并根據(jù)內(nèi)部路徑找到對(duì)應(yīng)的業(yè)務(wù)邏輯, 并再完成判斷權(quán)限后轉(zhuǎn)交給業(yè)務(wù)邏輯進(jìn)行處理, 這個(gè)過程Drupal稱之為分發(fā).
Drupal核心框架中的菜單api(includes/menu.inc文件)實(shí)現(xiàn)了上述功能, 它成功地解決了動(dòng)態(tài)URL路徑到具體執(zhí)行函數(shù)間映射, 對(duì)用戶屏蔽了系統(tǒng)預(yù)定義的Request參數(shù)的復(fù)雜處理, 在路徑和功能建立了必由之路. 啥也別說了, 看看分發(fā)函數(shù)的實(shí)現(xiàn):
<?php
>
function menu_execute_active_handler($path = NULL) {
if (_menu_site_is_offline()) {
return MENU_SITE_OFFLINE;
}
if (variable_get('menu_rebuild_needed', FALSE)) {
menu_rebuild();
}
if ($router_item = menu_get_item($path)) {
if ($router_item['access']) {
if ($router_item['file']) {
require_once($router_item['file']);
}
return <strong>call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);</strong>
}
else {
return MENU_ACCESS_DENIED;
}
}
return MENU_NOT_FOUND;
}
?>
用戶URL請(qǐng)求到達(dá)后, Drupal先進(jìn)行Bootstrap初始化, 然后調(diào)用分發(fā)函數(shù)menu_execute_active_handler, 該函數(shù)根據(jù)解析出的內(nèi)部路徑, 在系統(tǒng)構(gòu)建出的菜單路由表中查找, 如果找到則判斷可訪問權(quán)限, 然后調(diào)用路由表中對(duì)應(yīng)路徑注冊(cè)的Pange_callback回調(diào)函數(shù), 這樣就完成一個(gè)URL請(qǐng)求到具體頁面邏輯的過程. 流程非常簡單清晰, 學(xué)過計(jì)算機(jī)原理, 熟悉中斷調(diào)用的對(duì)這流程應(yīng)該都非常熟悉.
菜單路由(Menu Router)
Drupal系統(tǒng)主要依據(jù)menu_router表構(gòu)建系統(tǒng)菜單路由, 而menu_router表的內(nèi)容則是基于各模塊的hook_menu鉤子來獲得, 這個(gè)鉤子較少被調(diào)用, 一般都在模塊初始化或其他菜單需要重建的情況. 下面我們選一段Book模塊的menu鉤子代碼來看看:
<?php
function book_menu() {
$items = array();
$items['admin/content/book/%node'] = array(
'title' => 'Re-order book pages and change titles',
'page callback' => 'drupal_get_form',
'page arguments' => array('book_admin_edit', 3),
'access callback' => '_book_outline_access',
'access arguments' => array(3),
'type' => MENU_CALLBACK,
'file' => 'book.admin.inc',
);
}
?>
book模塊所定義的所有菜單路由表由一個(gè)二維數(shù)組表示, 其中每一項(xiàng)為一個(gè)菜單路由, 下標(biāo)即為該路由的入口路徑, 這里為'admin/content/book/%node'. 菜單路由項(xiàng)的各屬性看命名已經(jīng)比較清晰了, 想了解可以參考Drupal.
我們看上面用的路徑中包含一段'%node', 對(duì)了這是使用了通配符, 比如你訪問admin/content/book/7的時(shí)候, 會(huì)自動(dòng)把node7裝載進(jìn)來, 太多細(xì)節(jié), 就此打住.
菜單項(xiàng)(Menu Item)
保存在menu _links表中, 定義了每個(gè)條目的名字, 條目間父子關(guān)系, 對(duì)應(yīng)路徑, 所屬模塊等等很多屬性, 它應(yīng)不像菜單路由項(xiàng)一樣隱藏在背后干活, 它是可見的; 同時(shí)由于有通配符的存在, 它與菜單路由項(xiàng)并不是一一對(duì)應(yīng)關(guān)系. (比較奇怪的是默認(rèn)的Navigation菜單是用戶模塊創(chuàng)建的, 但它里面的所有菜單項(xiàng)卻是系統(tǒng)模塊定義的.) 既然router表的數(shù)據(jù)從鉤子函數(shù)而來, 那link表是否也有對(duì)應(yīng)的鉤子呢, 實(shí)際上菜單項(xiàng)是由菜單模塊(Menu Moudle)進(jìn)行管理, 通過GUI界面直接配置, 當(dāng)然菜單API也有對(duì)應(yīng)接口,比如menu_link_save(). ( 實(shí)在不行你直接寫數(shù)據(jù)庫也行, 那不就是hack菜單模塊了麼)
Drupal6.x增加了兩個(gè)alter鉤子函數(shù)對(duì)應(yīng)這兩張表, 它們是hook_menu_alter()<--->menu_router, hook_menu_link_alter()<--->menu_links, 它們主要處理內(nèi)容變化時(shí)的處理邏輯, 由Drupal_alter()函數(shù)調(diào)用, 看代碼注釋說這個(gè)函數(shù)非常Ugly, 要在7中把它解決掉. 頭暈了一天, 今天也沒有心思再看下去了.
總結(jié):
現(xiàn)在我們有點(diǎn)明白Drupal的菜單機(jī)制了吧, 它主要由菜單api和菜單模塊組成, 提供一種框架, 使得其他功能模塊能過注冊(cè)菜單路由項(xiàng), 并在分發(fā)過程中, 通過該菜單路由表完成用戶頁面請(qǐng)求(具體URL)到功能模塊業(yè)務(wù)邏輯的映射. 當(dāng)然Drupal的菜單機(jī)制還有很多復(fù)雜特性, 來日方長, 有空繼續(xù)鉆研.
另:有一點(diǎn)不明白的是menu_router為啥要用鉤子函數(shù), 不能直接用初始數(shù)據(jù)庫腳本麼, 不過我也沒研究過安裝過程, 似乎好像沒有一個(gè)地方用了數(shù)據(jù)庫腳本, 有人清楚這一塊麼?
從頭學(xué)習(xí)Drupal--基本架構(gòu)四
- 新手專區(qū)
- Drupal6.x
主題(Theme)
主題是什么呢? 其實(shí)這個(gè)詞已經(jīng)被用的很泛了, 所有涉及外觀定制的地方都充斥著這個(gè)詞, 比如我們最常見到的windows桌面主題, QQ的界面皮膚等. 說白了主題就是外觀, 可定制主題就是允許用戶自定義應(yīng)用的外觀.
Drupal的外觀也是由其主題(Theme)來表現(xiàn)的, 一個(gè)CMS只有強(qiáng)大的業(yè)務(wù)邏輯處理和擴(kuò)展能力, 而沒有好的外表, 一樣會(huì)流失大量的用戶. 所幸Drupal的外觀表現(xiàn)機(jī)制同樣十分強(qiáng)大, 它允許網(wǎng)站開發(fā)人員為其網(wǎng)站重新設(shè)計(jì)開發(fā)個(gè)性化主題, 同時(shí)Drupal社區(qū)還有大量共享的主題, 下載下來后, 解壓到站點(diǎn)對(duì)應(yīng)的主題目錄(sites/all/themes,或sites/指定站點(diǎn)/themes)下即完成安裝, 在管理界面直接熱插拔應(yīng)用主題, 非常方便.
主題機(jī)制(Theme System)
為了支持這么靈活,方便又強(qiáng)大的可插拔主題, Drupal有一整套設(shè)計(jì)實(shí)現(xiàn), 我們叫它主題機(jī)制(Theme System), 它被設(shè)計(jì)用來分離界面元素(比如HTML, CSS等)與核心業(yè)務(wù)邏輯. 通過這種分離, 有效的減少界面元素對(duì)核心代碼的影響, 從而能使核心代碼盡快穩(wěn)定; 同時(shí)更換新的界面也不需要去動(dòng)復(fù)雜的業(yè)務(wù)邏輯, 便于分配給專業(yè)的界面設(shè)計(jì)人員去開發(fā), 從而降低用戶界面這種需求易變性模塊的開發(fā)復(fù)雜性和依賴性. 下面我們就到Drupal的主題機(jī)制內(nèi)部去探索一番.
Drupal的主題機(jī)制(Theme System)有由三大部分組成: 主題(Themes), 主題引擎(Theme Engines)和主題api(includes/theme.inc).
主題(Themes)主要包含一組文件, 系統(tǒng)可以利用這些文件能展示對(duì)應(yīng)的外觀, 以獲得不同的用戶感受。一個(gè)主題主要由以下內(nèi)容組成:模板文件, 樣式表(CSS), 圖像(images), Javascript文件等; 對(duì)于一個(gè)web設(shè)計(jì)者來說, 樣式表什么的應(yīng)該都比較熟悉, 但模板文件是什么呢? 模板就是一個(gè)HTML片斷模子, 我們可以用它來生成有具體含義的HTML片斷. 舉個(gè)例子, 就好像一張空的賀卡, 你填上"xx生日快樂"就成了生日賀卡, 你寫上"情人節(jié)一起happy吧"那就成了節(jié)日祝福賀卡. 因?yàn)橐话闳硕急容^聰明, 所以空的賀卡大家也知道哪該寫姓名, 哪該寫祝福語; 萬一碰到個(gè)比較傻的要寫怎么辦, 于是聰明人可以先用鉛筆在該寫的作些提示標(biāo)記, 這樣傻子雖然不聰明但在有提示的地方把原來的鉛筆標(biāo)記替換成他自己的話還是能做到的. OK, 這個(gè)帶有鉛筆標(biāo)記的賀卡我們就可以稱之為一張賀卡模板.
Drupal的主題模板文件也是同樣道理, 它是一種帶有標(biāo)記(Tags)的HTML模板, 系統(tǒng)能夠識(shí)別標(biāo)記, 并根據(jù)標(biāo)記進(jìn)行內(nèi)容替換, 生成實(shí)際的HTML頁面. 那我靠什么識(shí)別標(biāo)記? 當(dāng)然就是看標(biāo)記所用的語言了. 話說如果是美國傻子, 那我們就用英語寫標(biāo)記, 日本傻子則用日語. 回到Drupal世界, 寫它的模板文件中標(biāo)記的語言我們稱之為模板語言(Template Language), Drupal6.x目前支持三種模板語言: php(默認(rèn)), smarty, Xtemplate; 光有語言還不行, 還要有傻子的大腦來能識(shí)別這些語言啊, 那么系統(tǒng)中對(duì)應(yīng)解釋這些語言的工具就是主題引擎(Theme Engine).
Drupal默認(rèn)的主題引擎是phptemplate, 它使用PHP語言, 直接內(nèi)簽在Drupal中, 不存在任何外部依賴. 下面看一個(gè)phptemplate的模板例子:
<?php
// $Id: block.tpl.php,v 1.3 2007/08/07 08:39:36 goba Exp $
?>;
<div id="block-<?php print $block->module .'-'. $block->delta; ?>;" class="clear-block block block-<?php print $block->module ?>">
<?php if (!empty($block->subject)): ?>;
<h2><?php print $block->subject ?></h2>
<?php endif;?>;
<div class="content"><?php print $block->content ?></div>
</div>
因?yàn)閜hptemplate引擎使用的模板語言是PHP, 則里面php代碼部分都是標(biāo)記, 如果我們傳入blcok變量{0,xx區(qū)塊,xx區(qū)塊內(nèi)容}, 則經(jīng)過主題機(jī)制(Theme system)處理后,上面這段模板代碼將生成如下HTML片斷:
<div id="block-book-0" class="clear-block block-book">
<h2>xx區(qū)塊</h2>
<div class="content">xx區(qū)塊的內(nèi)容</div>
</div>
主題api
主題api提供的強(qiáng)大機(jī)制使得分離出去的主題層能有機(jī)地和核心協(xié)同工作, 完成內(nèi)容的表現(xiàn). 該機(jī)制又是通過鉤子(hooks)技術(shù)實(shí)現(xiàn)的, 看來hooks不僅僅用于模塊(Module)與核心的交互, 它被應(yīng)用到所有需要與核心交互的場(chǎng)景. 與普通的業(yè)務(wù)邏輯類的鉤子不同, 主題鉤子(theme hooks)具備以下的特性:
- 主題鉤子是按顯示組件(components)來定義的, 即一個(gè)顯示組件定義一個(gè)鉤子名;
- 主題鉤子不僅能靠注冊(cè)函數(shù)實(shí)現(xiàn), 還能靠模板形式實(shí)現(xiàn), 通過模板文件名的命名規(guī)約, 能實(shí)現(xiàn)與函數(shù)鉤子類似的效果
- 主題鉤子不僅是只能在模塊中實(shí)現(xiàn), 而且在表現(xiàn)層的主題和主題引擎都能實(shí)現(xiàn); 這里注意了, 前面我們只說了主題中的模板文件, 這些文件是無法實(shí)現(xiàn)鉤子函數(shù), 而表現(xiàn)層中的鉤子函數(shù)在哪里實(shí)現(xiàn)呢? 對(duì)了, 在主題目錄下的template.php文件中實(shí)現(xiàn).
- 主題鉤子必須有默認(rèn)實(shí)現(xiàn), 要么在模塊中實(shí)現(xiàn), 即模塊默認(rèn)實(shí)現(xiàn), 要么直接使用主題api中的theme_HOOK(), 它定義了核心默認(rèn)的顯示組件的外觀.
- 主題鉤子是縱向的, 是覆蓋式的, 也就是說只有最上層的能起作用, 底下的都被屏蔽了, 這種鉤子實(shí)現(xiàn)是不是更像函數(shù)重載呢
上面這張圖是從drupal.org網(wǎng)站下載的, 它清楚地描述了主題機(jī)制的核心架構(gòu). 整個(gè)網(wǎng)頁由幾部分組成, 它們的不同顏色代表從不同鉤子輸出, 其中a點(diǎn)輸出代表默認(rèn)主題實(shí)現(xiàn)(核心和模塊的默認(rèn)鉤子實(shí)現(xiàn), 對(duì)應(yīng)兩種青灰的顏色); b點(diǎn)是主題引擎的鉤子重載點(diǎn), 主題引擎鉤子實(shí)現(xiàn)的輸出為褐色; c點(diǎn)則是主題的鉤子重載點(diǎn), 它的鉤子輸出為紅色, 這三層的輸出最終形成了給終端用戶的網(wǎng)頁.
主題鉤子的注冊(cè)是在模塊的hook_theme()中實(shí)現(xiàn)的(一個(gè)業(yè)務(wù)鉤子), 而主題鉤子有兩種形式: 回調(diào)函數(shù)和模板文件, 但主題層鉤子形式必須與業(yè)務(wù)邏輯層(Core和Module)的形式保持一直, 下面我們分開進(jìn)行闡述(下面的描述都基于PHPTemplate引擎):
(1)模板文件形式
模板文件允許你僅用css和的修改預(yù)定義的模板即可變換站點(diǎn)的外觀, 非常簡介和直接, 是我們自定義外觀的主要方式. 常用的模板文件主要有以下幾個(gè):page.tpl.php; node.tpl.php; block.tpl.php; comment.tpl.php; box.tpl.php;
- page.tpl.php
- 該模板描述一個(gè)HTML頁面的主要元素, 包括, 和 元素, 它非常復(fù)雜, 大概能使用30多個(gè)Tag變量
- node.tpl.php
- 該模板負(fù)責(zé)node內(nèi)容的顯示, 它的Tag變量都與node的屬性相關(guān), 而page.tpl.php的$content變量實(shí)際就代表它
- block.tpl.php
- 該模板負(fù)責(zé)block的顯示, 它有一個(gè)變量$block
- box.tpl.php
- 該模板負(fù)責(zé)畫一個(gè)簡單的盒子, 原來好像被用作搜索結(jié)果和form, 但這個(gè)版本已經(jīng)很少被使用了, 它與block有什么關(guān)系我到目前還沒搞清楚
- comment.tpl.php
- 該模板負(fù)責(zé)comment的顯示, 其他沒啥好說的
當(dāng)處理頁面顯示請(qǐng)求時(shí), 區(qū)塊的內(nèi)容, 節(jié)點(diǎn)的內(nèi)容, 評(píng)論的內(nèi)容等等都會(huì)先被放到區(qū)域(Region)中, 然后通過page.tpl.php中的區(qū)域變量$content, $header, $left, $right, and $footer等拼接成實(shí)際頁面. 所以為了減少顯示數(shù)據(jù)的生成, 可以禁用區(qū)域內(nèi)的block而不是僅僅修改page模板.
前面說了, 模塊也可以注冊(cè)模板鉤子, 主題也可以注冊(cè)模板鉤子, 那到底哪一個(gè)鉤子生效呢? 這是由主題機(jī)制的調(diào)度函數(shù)分發(fā)的. 下圖描述了幾種關(guān)鍵模板的查順序, 它們完全依賴模板名字的特殊命名約定來實(shí)現(xiàn), 如果文件名相同, 則優(yōu)先選擇上層的模板.
更詳細(xì)的關(guān)于模板文件內(nèi)的Tag變量, 可以參考《Pro_Drupal_Development》和Drupal.org.
(2)回調(diào)函數(shù)形式
回調(diào)函數(shù)形式是一種用coding來處理自定義界面的方式, 說白了就是表現(xiàn)層沒剝離完全的那部分, 留了一個(gè)后門, 以便處理更特殊的顯示需求. 主題和主題引擎的鉤子函數(shù)都在template.php文件中實(shí)現(xiàn), 它們的命名規(guī)范是mytheme_hook()和themeengine_hook(). 盡管采用回調(diào)函數(shù), 比模板方式提高5倍的速度, 但我們?cè)诙ㄖ仆庥^的時(shí)候, 還是建議優(yōu)先考慮定制模板鉤子. 如果確實(shí)沒有模板可用, 也盡量在主題引擎層實(shí)現(xiàn)函數(shù)鉤子, 這樣子主題也可以共享該函數(shù)鉤子.
最后, 整個(gè)上面的流程, 不論是模板還是回調(diào)函數(shù), 全部都是靠主題api中的theme()函數(shù)來實(shí)現(xiàn)的, 該函數(shù)堪稱Drupal主題機(jī)制的中場(chǎng)發(fā)動(dòng)機(jī).
編后語:
我花了三天時(shí)間來看主題, 每多看一次都會(huì)對(duì)自己的否定幾次, 確實(shí)太復(fù)雜, 而且Drupal6主題變化很大, 每天都不停的修改這篇文章, 真的以為這篇文章發(fā)不出來了, 但是為了給我的學(xué)習(xí)進(jìn)程做個(gè)見證, 在我還沒有完全理解它之前, 還是post出來了, 雖然不是很系統(tǒng), 但它闡明我目前對(duì)主題機(jī)制的理解, 希望大家的指正.
從頭學(xué)習(xí)Drupal--基本架構(gòu)五
- 新手專區(qū)
- Drupal6.x
任何一個(gè)開放系統(tǒng)(Open System), 只要它與外界有接口, 就存在安全問題, 越是商業(yè)級(jí)應(yīng)用越注重安全. 安全管理涉及很廣, 大到整個(gè)網(wǎng)絡(luò)安全的設(shè)定,小到具體按鈕的訪問, 如果你的系統(tǒng)哪天出現(xiàn)安全問題, 沒準(zhǔn)追根溯源能找到機(jī)房看門老頭, 呵呵, 玩笑話略過, 今天我們主要看看Drupal的用戶權(quán)限管理, 也就是訪問控制系統(tǒng).
權(quán)限管理的要素
我認(rèn)為, 一個(gè)權(quán)限管理系統(tǒng)主要由以下四要素組成: 訪問者, 管理對(duì)象, 操作和規(guī)則.
- 訪問者: 誰干? who. 一般來說是人, 嚴(yán)格來說應(yīng)該叫主動(dòng)體, 這要看你的系統(tǒng)面向哪些用戶, 一般系統(tǒng)人機(jī)接口,機(jī)機(jī)接口都是存在的. 反正就是那些通過你系統(tǒng)開發(fā)的接口與你交互的東東.
- 管理對(duì)象: 干誰? which. 就是被管理的東西, 比如倉庫里的糧食, 博客系統(tǒng)的文章, 總之, 任何有管理要求的東西. 千萬要記住的一點(diǎn)是: 就算垃圾也是有管理要求的.
- 操作: 干什么? what. 對(duì)應(yīng)具體操作, 比如寫文章, 運(yùn)糧食, 倒垃圾...
- 規(guī)則: 怎么干? how, when, where, 定義操作實(shí)施的附加條件, 比如登陸時(shí)間等.
權(quán)限管理的系統(tǒng)功能
可以說, 自從有了安全問題, 大家就在圍繞這幾個(gè)要素傷腦筋, 針對(duì)各種不同的管理需求, 也出現(xiàn)了各種不同的權(quán)限管理的方案, 如何在安全性, 操控性, 性能以及開發(fā)復(fù)雜性間取得平衡是恒古不變的主題. 為了聚焦今天的話題, 我們主要從系統(tǒng)功能角度來窺視一下, 看看一個(gè)權(quán)限系統(tǒng)到底是如何工作的.
- 首先當(dāng)然權(quán)限的定義, 即識(shí)別出系統(tǒng)中需要進(jìn)行訪問控制的要素(管理對(duì)象, 操作, 規(guī)則), 并定義成相應(yīng)的權(quán)限, 這是整個(gè)權(quán)限系統(tǒng)的核心, 針對(duì)不同的管理粒度和管理要求, 會(huì)出現(xiàn)截然不同的實(shí)現(xiàn)方式.
- 授權(quán), 即把權(quán)限與用戶關(guān)聯(lián), 最直接的方法是給用戶直接關(guān)聯(lián), 而最常見最有效的方式是使用角色(也有叫組的)
- 鑒權(quán), 根據(jù)規(guī)則執(zhí)行權(quán)限的檢查, 以實(shí)施訪問控制, 看你的檢查點(diǎn)實(shí)現(xiàn)在哪呢, 同樣也是不同的要求有不同的實(shí)現(xiàn)
- 最后, 應(yīng)該要能監(jiān)控, 一般記日志
是不是比較清楚, 把這幾個(gè)系統(tǒng)功能考慮完全, 并實(shí)現(xiàn)好, 你的系統(tǒng)就安全了一半; 另一半是什么, 是你的安全意識(shí), 天干物燥, 防火防盜, 只有真正樹立安全意識(shí), 才能有效地去應(yīng)用各種安全措施, 防范危險(xiǎn). 不幸的是, 我們大多數(shù)人都疏予管理, 閑置, 不管不顧.
Drupal的權(quán)限管理框架
首先我們來識(shí)別系統(tǒng)中具備哪些要素: Drupal是一個(gè)基于web的CMS系統(tǒng), 所以訪問者主要局限在管理員和普通web訪問用戶(User); 而管理對(duì)象則是CMS中的核心--內(nèi)容, 在drupal中它被抽象為節(jié)點(diǎn)(Node). (應(yīng)該還會(huì)有些其他的管理對(duì)象). 操作呢? 菜單, 按鈕, 在web系統(tǒng)里是不是都對(duì)應(yīng)到頁面, 也就是內(nèi)部路徑(例如: "node/1/view"), 規(guī)則沒什么特殊的: 操作時(shí)出現(xiàn)禁止頁面, 列表中不出現(xiàn)無權(quán)限內(nèi)容等.
Drupa采用角色來關(guān)聯(lián)用戶和操作, 每個(gè)角色是從方便系統(tǒng)管理角度出發(fā)來定義的一類具備相同操作界面或行為的訪問者, 但它不是簡單的用戶或操作的分組, 而是他們的有機(jī)結(jié)合, 形象的說就是一組權(quán)力的代名詞或者叫Permission Scheme. Drupall針對(duì)操作是否涉及到管理對(duì)象, 設(shè)計(jì)了兩個(gè)不同的鑒權(quán)流程, 以滿足不同的權(quán)限管理要求.
(1)與內(nèi)容無關(guān)的操作權(quán)限
權(quán)限定義
鉤子hook_perm, 定義了每個(gè)模塊的操作權(quán)限, 用操作名描述.
<?php
/**
* Implementation of hook_perm().
*/
function book_perm() {
return array('add content to books', 'administer book outlines', 'create new books', 'access printer-friendly version');
}
?>
授權(quán)
按角色授權(quán), 權(quán)限被分配后, 存儲(chǔ)在數(shù)據(jù)庫表{permission}中.
鑒權(quán)
由函數(shù)user_access進(jìn)行實(shí)際的鑒權(quán)工作, 它的參數(shù)是賬號(hào)信息與操作權(quán)限名, 返回ture或false. 你可以在任何需要的地方調(diào)用該函數(shù)進(jìn)行鑒權(quán), 但系統(tǒng)提供了一套默認(rèn)的回調(diào)機(jī)制, 使得鑒權(quán)點(diǎn)實(shí)現(xiàn)簡單一致. 這就是菜單路由注冊(cè)函數(shù)中的access_callback參數(shù), 該參數(shù)標(biāo)明了此菜單路由需要進(jìn)行訪問控制, 只有訪問回調(diào)函數(shù)驗(yàn)證通過, 才會(huì)被正確路由到對(duì)應(yīng)頁面.
<?php
function forum_menu() {
$items['forum'] = array(
'title' => 'Forums',
'page callback' => 'forum_page',
'access callback' => '_example_test_access', //這里指定訪問驗(yàn)證回調(diào)函數(shù), 默認(rèn)為hook_access()鉤子,
'access arguments' => array('access content'),
'type' => MENU_SUGGESTED_ITEM,
'file' => 'forum.pages.inc',
);
?>
鑒權(quán)鉤子, 模塊可以處理一些特殊的規(guī)則
<?php
/**
* Implementation of hook_access().
*/
function forum_access($op, $node, $account) {
switch ($op) {
case 'create':
return user_access('create forum topics', $account);
case 'update':
return user_access('edit any forum topic', $account) || (user_access('edit own forum topics', $account) && ($account->uid == $node->uid));
case 'delete':
return user_access('delete any forum topic', $account) || (user_access('delete own forum topics', $account) && ($account->uid == $node->uid));
}
}
?>
(2)節(jié)點(diǎn)訪問機(jī)制(Node Access System)
drupal還提供對(duì)管理對(duì)象的訪問控制--節(jié)點(diǎn)訪問機(jī)制(Node Access System), 這是一套復(fù)雜的機(jī)制, 我還沒完全摸清. 它主要是在權(quán)限定義方面進(jìn)行了增強(qiáng), 它通過定義用戶, 操作與節(jié)點(diǎn)的綁定, 來建立一個(gè)節(jié)點(diǎn)訪問表, 這樣當(dāng)需要進(jìn)行管理對(duì)象關(guān)聯(lián)鑒權(quán)時(shí), 系統(tǒng)會(huì)執(zhí)行node_access函數(shù), 該函數(shù)會(huì)恰當(dāng)?shù)夭樵児?jié)點(diǎn)訪問表獲得用戶的權(quán)限, 以完成鑒權(quán).
我們?cè)賮砜纯催@張節(jié)點(diǎn)訪問表, 用戶信息, 操作信息, 節(jié)點(diǎn)信息, OMG! m*n*P=? 如果還是按以前方式來定義, 那性能的低下可想而知, 所以綜合一般的權(quán)限控制需求, Drupal僅定義了三種的原始操作: view, update, delete, 而對(duì)于用戶則僅定義了一個(gè)抽象的二元組(realm, grant), 它與實(shí)際用戶間的映射由你自定義的節(jié)點(diǎn)訪問控制模塊行來決定, 這樣達(dá)到對(duì)用戶歸納的效果, 減小節(jié)點(diǎn)訪問表紀(jì)錄的數(shù)量級(jí).
這套機(jī)制主要通過節(jié)點(diǎn)模塊(Node Module)提供的一系列api和hook_node_grants鉤子和hook_node_access_records鉤子來實(shí)現(xiàn). 我們這次知道有這套東西即可, 不鋪開敘述.
Drupal的權(quán)限管理方法
1, 基本權(quán)限管理
盡管Drupal的權(quán)限管理機(jī)制是強(qiáng)大復(fù)雜的, 但其默認(rèn)的基本權(quán)限管理卻非常簡單, 基于角色(role)和操作權(quán)限, 把操作賦予角色, 而把角色賦予用戶, 這樣用戶就能使用相應(yīng)的權(quán)限. 基本權(quán)限管理粒度較粗, 只能滿足一般的安全需求.
2, 按內(nèi)容類型鑒權(quán)
如果我們對(duì)管理對(duì)象有更精細(xì)的管理要求, 比如我想讓A角色能訪問page, B角色只能訪問story, 咋辦? 基本權(quán)限管理做不到了, 那我們就擴(kuò)展模塊. 內(nèi)容訪問模塊(Content Access )允許你對(duì)內(nèi)容類型按角色設(shè)置權(quán)限(查看, 編輯, 刪除). 其實(shí)Drupal6.2基本權(quán)限管理里也能設(shè)置按內(nèi)容類型進(jìn)行鑒權(quán), 因?yàn)閐rupal把所有節(jié)點(diǎn)類型的幾個(gè)基本操作都注冊(cè)了, 看下面這個(gè)丑陋的循環(huán), 呵呵, 這幾個(gè)也是漢化不到位的地方.
<?php
function node_perm() {
$perms = array('administer content types', 'administer nodes', 'access content', 'view revisions', 'revert revisions', 'delete revisions');
foreach (node_get_types() as $type) {
if ($type->module == 'node') {
$name = check_plain($type->type);
$perms[] = 'create '. $name .' content';
$perms[] = 'delete own '. $name .' content';
$perms[] = 'delete any '. $name .' content';
$perms[] = 'edit own '. $name .' content';
$perms[] = 'edit any '. $name .' content';
}
}
return $perms;
}
?>
3, 按組鑒權(quán)
如果是個(gè)大公司, 有很多部門, 相互間都有安全需求, 比如:
1. 能按不同的部門創(chuàng)建不同的組, 它們都能管理其私有內(nèi)容
2. 組成員擁有組內(nèi)的權(quán)限
3. 跨組間允許指定某些特定的權(quán)限共享
4. 匿名用戶只能訪問標(biāo)識(shí)為"public"的內(nèi)容, 注冊(cè)用戶能訪問public和Restricted, 僅組成員能訪問private等
看到這么多需求, 則我們需要一個(gè)更復(fù)雜的權(quán)限管理, drupal目前有兩個(gè)擴(kuò)展模塊都能提供類似的功能:
(a) taxonomy_access modules
使用drupal的分類模塊的基本功能, 完成以上的權(quán)限控制, 這里有英文的教程, 步驟描述較清楚.
i, 定義一個(gè)詞匯表(Groups), 用來定義組(即公司部門); 把它應(yīng)用到所有內(nèi)容類型, 再添加2個(gè)條目(比如財(cái)務(wù), 研發(fā))
ii, 再定義一個(gè)詞匯表(Access), 用來定義訪問級(jí)別; 同樣應(yīng)用到所有內(nèi)容類型, 同時(shí)還要設(shè)置"必須"的選項(xiàng), 這樣保證創(chuàng)建內(nèi)容時(shí)必須選一個(gè)該
詞匯表中的條目. 加三個(gè)條目(public, Restricted, Private)
iii, 按基本權(quán)限管理的方法創(chuàng)建2個(gè)角色(財(cái)務(wù)人員, 開發(fā)人員), 再創(chuàng)建幾個(gè)用戶, 并分辨賦予對(duì)應(yīng)角色(張三->財(cái)務(wù), 李四->開發(fā))
iv, 前面都是基本管理,沒涉及到擴(kuò)展模塊, 現(xiàn)在打開"administer > user management > taxonomy access: permissions", 按照步驟開始設(shè)吧, 一個(gè)組鑒權(quán)系統(tǒng)完成, 祝你好運(yùn).
(b) 著名的OG
Organic Groups功能太強(qiáng)了, 上面的需求全部能滿足, 組或圈的概念是大型社區(qū)不可缺少的, 別猶豫了, 能用就用吧.
總之, drupal的權(quán)限管理機(jī)制非常靈活, 可簡可繁, 每個(gè)系統(tǒng)都安全的需求都是不一樣的, 你們的權(quán)限管理有哪些特殊的好實(shí)現(xiàn), 拿出來show繡把.