RedBeanPHP——介紹一個ORM框架

今天工育,無意中從CI論壇的一篇文章里輾轉(zhuǎn)找到了RedBeanPHP——一個簡潔輕巧但功能并不弱的ORM框架:零配置、可以自動創(chuàng)建數(shù)據(jù)庫schema搓彻。核心只有一個300多K的文件如绸,直接在腳本中引用即可使用,還有一些比較獨(dú)特的功能值的開發(fā)人員使用旭贬。

  • 當(dāng)前版本4.3.2怔接,需求
  • GNU/Linux, BSD, Windows
  • PHP 5.3.0 or higher (PHP 5.3.4+ recommended)
  • PDO plus driver for your database
  • Multibyte String Support
    下面是我對其文檔中教程的一個翻譯:

威士忌品嘗記錄教程

在本教程里,我們將通過編寫一個小程序來演示RedBeanPHP的一些基本功能稀轨。讓那些Todo之類的大路貨一邊去扼脐,我們要做的是一個威士忌品嘗記錄(whisky tasting notes)的管理程序。我把它稱之為“一小口(dram)”——意為“一小杯威士忌”奋刽。如果因?yàn)檎軐W(xué)或者宗教原因瓦侮,你反對酒精消費(fèi)的話,你可以把這里的"whisky"換成"tea"佣谐。如同威士忌一樣肚吏,一杯茶帶來的美妙回味同樣深長復(fù)雜,所以這個程序同樣適用于對茶的品鑒狭魂。如果不是反對飲酒而只是單純的不喜歡威士忌的話罚攀,那么就假設(shè)我們是在創(chuàng)建品鑒紅酒党觅、雪茄,或者其他什么——只要你喜歡就行——的程序吧斋泄。

開發(fā)環(huán)境

我們將創(chuàng)建一個CLI(譯:command line interface 命令行接口)程序杯瞻,在命令行模式下運(yùn)行這就意味著不需要創(chuàng)建圖形界面。這允許我們把注意力放在編寫代碼上是己,而不是糾結(jié)在HTML模板之類的東東上煌茴。我們預(yù)設(shè)的操作系統(tǒng)是UNIX或者GNU/Linux巴粪。(譯:有些命令在windows下略有出入

步驟1: 初始化

首先,我們需要下載并安裝RedBeanPHP包刚照。幸運(yùn)的是宙地,這非常簡單摔认。RedBeanPHP只有一個文件,所以我們只需從網(wǎng)上把它下來就行了宅粥,就像這樣:

url=http://www.redbeanphp.com/downloadredbean.php
wget $url --output-document="redbeanphp.tar.gz"
tar xvf redbeanphp.tar.gz

windows下直接從這下載好了参袱,戳我下載。下載的壓縮包解壓縮后只有一個文件

rb.php

在本程序中秽梅,我們使用了一個臨時數(shù)據(jù)庫抹蚀,所以在重啟系統(tǒng)之后,數(shù)據(jù)會丟失企垦。
  雖然在現(xiàn)實(shí)生活中不是很實(shí)用环壤,這也可算是測試和熟悉RedBeanPHP的一個方法。所以钞诡,讓我們創(chuàng)建程序:dram.php:

touch dram.php

然后用編輯器(我的最愛)打開并編輯:

vim dram.php

譯注:這兩處的命令在windows下可以用:echo > dram.phpnotepad.exe dram.php替換郑现。notepad可以替換成你喜歡的編輯器,只要在系統(tǒng)環(huán)境變量PATH中有聲明即可荧降。其實(shí)接箫,windows并不以命令行操作見長:(

雖然我喜歡使用VIM,但具體使用什么編輯器沒啥關(guān)系朵诫,即使是普通的文本編輯器也能工作的很好辛友。下面我們把RedBeanPHP庫包含進(jìn)來并設(shè)置數(shù)據(jù)庫連接:

require 'rb.php';
R::setup();

譯注:這里我在windows下運(yùn)行報錯,提示"Unsupported database()"剪返。新建tmp子目錄废累,然后修改為R::setup('sqlite:./tmp/red.db')之后正常。也可以用R::setup('sqlite:memory');建立臨時內(nèi)存數(shù)據(jù)庫也可随夸。

步驟2: 來一瓶威士忌

在使用RedBeanPHP時九默,重要的一點(diǎn)就是首先創(chuàng)建數(shù)據(jù)記錄。那么宾毒,我們先編寫向數(shù)據(jù)庫中添加數(shù)據(jù)的邏輯驼修。盡管有些人喜歡先創(chuàng)建顯示表中記錄的頁面殿遂,但數(shù)據(jù)庫里起碼得有一些數(shù)據(jù)吧?
  RedBeanPHP能替我們完成那些繁重的活——包括創(chuàng)建表乙各、字段等——自動的墨礁,最好還是反過來吧。So耳峦,從你的"add"邏輯開始吧恩静。

$opts = getopt( '', [ 'add:', 'list' ] );

這里我們使用了PHP的getopt()函數(shù)來從命令行讀取命令。此處蹲坷,我們偵聽兩個命令:addlist∈磺現(xiàn)在,讓我們看看怎么把一瓶威士忌添加到收藏中:

if (isset($opts['add'])) {
    $w = R::dispense('whisky');
    $w->name = $opts['add'];
    $id = R::store($w);
    die("OK.\n");
}

這一段代碼非常簡單:它從命令行中獲取add命令的參數(shù)值循签,然后創(chuàng)建一個新的威士忌類型bean级乐。然后把文本賦值給bean的name屬性并保持它。為了讓用戶能看到威士忌的清單县匠,我們也實(shí)現(xiàn)了list功能:

if(isset($opts['list'])){
$bottles = R::find('whisky');
if(!count($bottles)) die("The cellar is empty!\n");
foreach($bottles as $b){
    echo "* #{$b->id}: {$b->name} \n";
}
exit;
}

接下來风科,我們就可以使用程序了:

php dram.php --add="Bowmore 12yo"
OK.
php dram.php --add="Lagavulin 16yo"
OK.

這樣了了幾行代碼的程序就可以很好的工作了,但我們可以做的更多乞旦。

geek@beans$ sqlite3 /tmp/red.db
SQLite version 3.7.13 2005-06-11 02:05:32
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .tables
whisky

我們看到whisky表已經(jīng)創(chuàng)建了贼穆,要求的字段也都已經(jīng)就位:

sqlite> .schema
CREATE TALBE `whisky` (
id INTEGER PRIMARY KEY AUTOINCREMENT,
`name` TEXT
);

RedBeanPHP自動創(chuàng)建了必須的(字段),數(shù)據(jù)庫的列類型依賴于你要存入的數(shù)據(jù)。RedBeanPHP掃描要存入的數(shù)據(jù)兰粉,確認(rèn)該列的類型能正確容納你的數(shù)據(jù)故痊。當(dāng)然,你也可以手工調(diào)整數(shù)據(jù)庫結(jié)構(gòu)(schema)亲桦。

步驟3:扔掉幾瓶

接下來崖蜜,我們要添加一個新功能“delete”。是的客峭,這個命令將從數(shù)據(jù)庫中清除指定的記錄豫领。首先我們向getopts添加“delete”命令,目前的命令結(jié)構(gòu)如下:

$opts=getopt('',['add:','list','delete:']);

然后舔琅,寫小一段代碼來執(zhí)行實(shí)際的刪除:

if(iiset($opts['delete'])){
    R::trash('whisky',$opts['delete']);
    die("Threw the bootle away!\n");
}

好極了等恐,現(xiàn)在我們可以添加、顯示和刪除威士忌了备蚓。試一下:

php dram.php --add="daluaine 16yo"
 OK.
 php dram.php --list
* #1: Bowmore 12yo
* #3: Daluaine 16yo

靠课蔬!輸錯了。應(yīng)該是Dailuaine而不是Daluaine郊尝。順便說一句:的確很美味二跋。感謝新添加的delete功能,我們可以移除錯誤的記錄并修正這一低級錯誤:

php dram.php --delete=3
Threw the bottle away!
php dram.php --list
* #1: Bowmaore 12yo
php dram.php --add="Dailuaine 16yo"

現(xiàn)在就非常完美了流昏,不過記錄在哪里呢扎即?畢竟跟我們計(jì)劃是做一個管理品嘗記錄的程序巴袒瘛!別急谚鄙,在肉餡羊肚冷掉前各拷,我們就可以添加記錄了。

步驟4:添加品嘗記錄

首先闷营,要考慮一下一條記錄一瓶威士忌之間的關(guān)系烤黍。一瓶威士忌會有次被品嘗的記錄,對吧傻盟?那么反過來又是怎么樣呢速蕊?條品嘗記錄會跟瓶威士忌有關(guān)嗎?甚至不太可能一瓶酒只有一次品嘗(當(dāng)然啦莫杈,那些非常非常廉價的貨色要除外)互例。
  這就意味著我們需要一個一對多的關(guān)系。
  瓶威士忌有條記錄筝闹,而每一條記錄只屬于瓶威士忌。這種關(guān)系有時候也被表示為1-N⌒裙猓現(xiàn)在关顷,如果我們對一瓶威士忌不感興趣了將其扔掉,我們還需要保留對應(yīng)的品嘗記錄嗎武福?當(dāng)然不需要啦议双!它們本身沒有任何價值,只是用來描述與之相關(guān)的威士忌的捉片。這就意味著我們必須使用專屬列表(exclusive own list): xownNoteList平痰。我們這樣來關(guān)聯(lián)記錄和威士忌:

$n=R::dispense('note');
$n->note=$text;
$whisky->xownNoteList[]=$n;
R::store($whisky);

注意,list的名稱中包含了我們要保存的bean的類型伍纫。這是一個約定宗雇。list的格式是:

<x> own <BEAN TYPE NAME>List

所以如果我們要在book中保存pages,就得使用ownPageList莹规。因?yàn)槲覀兿MS著瓶子一起扔掉所有記錄赔蒲,所以我們使用了專屬(exclusive)列表。因此良漱,我們用'x'作為list名稱的開頭舞虱。一旦定義了一個專屬列表,就無路可退了母市。如果你確實(shí)要留下記錄矾兜,那你只能使用數(shù)據(jù)庫管理工具(如phpmyadmin)打開數(shù)據(jù)庫,修改外鍵設(shè)置患久。
  現(xiàn)在椅寺,添加給用戶顯示指定威士忌的記錄列表的功能吧:

$note=$whisky->xownNoteList;
foreach($note as $note) echo $note->note;

步驟5:包裝一下

現(xiàn)在讓我們看看整個程序浑槽,這是我的版本:

require 'rb.php';
R::setup();
$opts = getopt( '', [
  'add:',
  'delete:',
  'attach-to:',
  'note:',
  'notes:',
  'remove-note:',
  'list' ] );
if ( isset( $opts [ 'add' ] ) ) {
  $w = R::dispense( 'whisky' );
  $w->name = $opts['add'];
  $id = R::store( $w );
  die( "OK.\n" );
}
if ( isset( $opts['delete'] ) ) {
  R::trash( 'whisky', $opts['delete'] );
  die( "Threw the bottle away!\n" );
}
if ( isset( $opts['note'] ) && isset( $opts['attach-to'] ) ) {
  $w = R::load( 'whisky', $opts['attach-to'] );
  if (!$w->id) die( "No such bottle.\n" );
  $n = R::dispense( 'note' );
  $n->note = $opts['note'];
  $w->xownNoteList[] = $n;
  R::store( $w );
  die( "Added note to whisky.\n" );
}
if ( isset( $opts['notes'] ) ) {
  $w = R::load( 'whisky', $opts['notes'] );
  foreach( $w->xownNoteList as $note ) {
    echo "* #{$note->id}: {$note->note}\n";
  }
  exit;
}
if ( isset( $opts['remove-note'] ) ) {
  R::trash( 'note', $opts['remove-note'] );
  die( "Removed note.\n" );    
}
if ( isset( $opts['list'] ) ) {
  $bottles = R::find( 'whisky' );
  if ( !count( $bottles ) ) die( "The cellar is empty!\n" );
  foreach( $bottles as $b ) {
    echo "* #{$b->id}: {$b->name}\n";
  }
  exit;
}

下面是在命令行中的具體使用:

php dram.php --add="Dailuaine 16yo"
OK.
php dram.php --list
* #1: Bowmore 12yo
* #4: Dailuaine 16yo
php dram.php --attach-to=4 --note="vanilla, buttered cream"
Added note to whisky.
php dram.php --attach-to=4 --note="apple, pear"
Added note to whisky.
php dram.php --notes=4
* #4: vanilla, buttered cream
* #5: apple, pear 

步驟6:玩玩Models

只是出于好玩,我們要添加一個model配并。很多web程序使用MVC架構(gòu)括荡,模型(M)被用來封裝業(yè)務(wù)邏輯。現(xiàn)在溉旋,然我們假設(shè)我們不接受少于四個字符的品嘗記錄畸冲。這就是喝酒業(yè)務(wù)中的業(yè)務(wù)邏輯|規(guī)則:)。為了添加這一規(guī)則的驗(yàn)證观腊,我們需要有一個模型(model)邑闲。在大部分對象關(guān)系映射(object relational mappers--ORM)中,這也是必須首先創(chuàng)建一個完整的類的原因梧油。我很高興的是苫耸,在RedBeanPHP中,事情有一點(diǎn)不同儡陨。我們沒有模型(no model)褪子,記得嗎?只有beans骗村。那么嫌褪,如何從一個bean轉(zhuǎn)到一個model呢?簡單胚股!我們只需要添加一個model笼痛,RedBeanPHP就會自動檢測到其存在±虐瑁基于命名約定缨伊,它將把模型連接到bean。開始吧:

class Model_Note extends RedBean_SimpleModel {
    public function update() {
        if (strlen($this->bean->note )<4)
            die("Note is too short!\n");
    }
}

在note模型中进宝,我們可以這樣引用bean:

$this->bean;

一旦我們試圖保存刻坊,bean就會調(diào)用update()方法。雖然沒有辦法停止這一流程即彪,但為了阻止RedBeanPHP保存bean我們必須拋出一個異常紧唱,或者執(zhí)行die()指令操作。讓我們測試一下:

php dram.php --attach-to=4 --note="ap"
Note is too short! 

棒極了隶校!工作的很好漏益。看到了嗎深胳?我們不需要更改代碼绰疤,只是簡單的添加一個模型,隨時都行舞终。不需要拿著全部代碼把它們?nèi)揭粋€類里或著東一頭轻庆,西一頭地添加驗(yàn)證規(guī)則癣猾。不需要!只是添加一個模型余爆,然后所有動作就突然全部改從它中間通過了纷宇。除了update()外,我們還可以使用其他各種鉤子(hook)來完成各種模型的工作蛾方。

步驟7:凍結(jié)

在我們發(fā)布程序之前像捶,我們需要確認(rèn)一下數(shù)據(jù)庫并凍結(jié)它(`譯注:以后的操作就不會在改動數(shù)據(jù)庫結(jié)構(gòu)了`)。我們只需要簡單地調(diào)用freeze()即可桩砰,在代碼頂端拓春,位于setup這一行下面:

R::setup();
R::freeze(TRUE);

完工,我們的威士忌程序亚隅!
  當(dāng)然啦硼莽,RedBeanPHP還有比CRUD一對多關(guān)系更多的內(nèi)容,但對一個小教程來說煮纵,想全部覆蓋到那簡直就是一個不可能完成的任務(wù)吖:(
  接下來懂鸵,你可以自由的擴(kuò)展這個小程序,添加標(biāo)簽tags行疏,分類categories以及其他概念來熟悉RedBeanPHP提供的各種功能矾瑰。
  希望你喜歡!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末隘擎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子凉夯,更是在濱河造成了極大的恐慌货葬,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劲够,死亡現(xiàn)場離奇詭異震桶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)征绎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門蹲姐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人人柿,你說我怎么就攤上這事柴墩。” “怎么了凫岖?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵江咳,是天一觀的道長。 經(jīng)常有香客問我哥放,道長歼指,這世上最難降的妖魔是什么爹土? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮踩身,結(jié)果婚禮上胀茵,老公的妹妹穿的比我還像新娘。我一直安慰自己挟阻,他們只是感情好琼娘,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赁濒,像睡著了一般轨奄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拒炎,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天挪拟,我揣著相機(jī)與錄音,去河邊找鬼击你。 笑死玉组,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的丁侄。 我是一名探鬼主播惯雳,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鸿摇!你這毒婦竟也來了石景?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤拙吉,失蹤者是張志新(化名)和其女友劉穎潮孽,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體筷黔,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡往史,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了佛舱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片椎例。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖请祖,靈堂內(nèi)的尸體忽然破棺而出订歪,到底是詐尸還是另有隱情,我是刑警寧澤损拢,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布陌粹,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏掏秩。R本人自食惡果不足惜或舞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蒙幻。 院中可真熱鬧映凳,春花似錦、人聲如沸邮破。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抒和。三九已至矫渔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間摧莽,已是汗流浹背庙洼。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留镊辕,地道東北人油够。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像征懈,于是被迫代替她去往敵國和親石咬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容