YII中的DAO(數(shù)據(jù)庫訪問對象)是建立在PHP的PDO之上的,所以你開發(fā)的應(yīng)用可以很容易的在不同的數(shù)據(jù)庫系統(tǒng)平臺之間進(jìn)行切換,而只需要修改少量代碼。YII采用ORM(Object-Relational Mapping)的設(shè)計(jì)模式進(jìn)行數(shù)據(jù)庫編程,簡化了一些繁瑣的的數(shù)據(jù)庫操作。
在YII中的DAO的相關(guān)類主要存放在/yii_dev/yii/framework/db和/yii_dev/yii/framework/web,通常名稱帶有DB或者Data。
在YII中操作數(shù)據(jù)庫我們主要是使用CActiveRecord,它繼承CModel。用CActiveRecord可以完成對數(shù)據(jù)CURD操作的大部分任務(wù)。 但是對于有復(fù)雜邏輯的數(shù)據(jù)庫查詢操作,用CActiveRecord就力不從心了,后續(xù)將會講解YII如何處理復(fù)雜的數(shù)據(jù)庫查詢操作。
在ORM中通常用Object(對象)來表示一個(gè)Relation(關(guān)系),可以理解為一個(gè)類對應(yīng)一個(gè)數(shù)據(jù)表或者視圖。類的屬性可以認(rèn)為是和數(shù)據(jù)表的列一一對應(yīng)的,類中的方法是用于對數(shù)據(jù)庫操作的方法例如CURD。
這里講一下CActiveRecord如何使用。
一般如果是基本的操作我們可以用yiic自動(dòng)生產(chǎn)curd系列的操作。這里在不多說明。主要說明如果手寫代碼,我們的程序要遵循的基本規(guī)則。
1.設(shè)計(jì)表
開始之前我們先來定義我們要操作的表。這里使用mysql,數(shù)據(jù)庫是testdrive,使用的表結(jié)構(gòu)如下:
2.配置數(shù)據(jù)庫鏈接
在/testwebap/protected/config/main.php配置文件
要繼承CActiveRecord ,其實(shí)經(jīng)過前面章節(jié)的說明,這里的代碼完全可以自動(dòng)生成,這里定義基本的類,做說明。基本代碼如下:
在/yii_dev/testwebap/protected/modules/testmod/controllers/DefaultController.php定義DefaultController。具體結(jié)構(gòu)如下:
如果不出異常,會打印如下類似的信息,表示你的操作類可以正常使用
5.使用:插入一行數(shù)據(jù)。
如果打印的是bool(true),查看一下數(shù)據(jù)庫可以看到,我們的數(shù)據(jù)已經(jīng)存入到數(shù)據(jù)庫中。
這里TblUser中雖然沒有明確的指定數(shù)據(jù)表的列的名稱,但是我們還是可以直接使用。這都是yii悄悄為我們做的。這樣的操作豈不是很爽。還有TblUser是繼承的CActiveRecord,也繼承與CModel當(dāng)然也是CComponent,所以他們的方法我們都可以使用。修改,刪除,查找,比較,你想要的函數(shù)應(yīng)有盡有,這里不再詳細(xì)做講解,自己慢慢分析代碼,才能更好的掌握這些方法的使用。
下的時(shí)間交給官方文檔,看看官方文檔講CActiveRecord的常見方法。
具體網(wǎng)址是:http://www.yiiframework.com/doc/guide/1.1/zh_cn/database.ar
//詳細(xì)內(nèi)容如下://///////////////
雖然 Yii DAO 可以處理幾乎任何數(shù)據(jù)庫相關(guān)的任務(wù), 但很可能我們會花費(fèi) 90% 的時(shí)間以編寫一些執(zhí)行普通 CRUD(create, read, update 和 delete)操作的 SQL 語句。 而且我們的代碼中混雜了SQL語句時(shí)也會變得難以維護(hù)。要解決這些問題,我們可以使用 Active Record。
Active Record (AR) 是一個(gè)流行的 對象-關(guān)系映射 (ORM) 技術(shù)。 每個(gè) AR 類代表一個(gè)數(shù)據(jù)表(或視圖),數(shù)據(jù)表(或視圖)的列在 AR 類中體現(xiàn)為類的屬性,一個(gè) AR 實(shí)例則表示表中的一行。 常見的 CRUD 操作作為 AR 的方法實(shí)現(xiàn)。因此,我們可以以一種更加面向?qū)ο蟮姆绞皆L問數(shù)據(jù)。 例如,我們可以使用以下代碼向 tbl_post
表中插入一個(gè)新行。
$post=new Post;$post->title='sample post';$post->content='post body content';$post->save();
下面我們講解怎樣設(shè)置 AR 并通過它執(zhí)行 CRUD 操作。我們將在下一節(jié)中展示怎樣使用 AR 處理數(shù)據(jù)庫關(guān)系。 為簡單起見,我們使用下面的數(shù)據(jù)表作為此節(jié)中的例子。注意,如果你使用 MySQL 數(shù)據(jù)庫,你應(yīng)該將下面的 SQL 中的 AUTOINCREMENT
替換為 AUTO_INCREMENT
。
CREATE TABLE tbl_post ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, title VARCHAR(128) NOT NULL, content TEXT NOT NULL, create_time INTEGER NOT NULL);
注意: AR 并非要解決所有數(shù)據(jù)庫相關(guān)的任務(wù)。它的最佳應(yīng)用是模型化數(shù)據(jù)表為 PHP 結(jié)構(gòu)和執(zhí)行不包含復(fù)雜 SQL 語句的查詢。 對于復(fù)雜查詢的場景,應(yīng)使用 Yii DAO。
AR 依靠一個(gè)數(shù)據(jù)庫連接以執(zhí)行數(shù)據(jù)庫相關(guān)的操作。默認(rèn)情況下, 它假定 db
應(yīng)用組件提供了所需的CDbConnection 數(shù)據(jù)庫連接實(shí)例。如下應(yīng)用配置提供了一個(gè)例子:
return array( 'components'=>array( 'db'=>array( 'class'=>'system.db.CDbConnection', 'connectionString'=>'sqlite:path/to/dbfile', // 開啟表結(jié)構(gòu)緩存(schema caching)提高性能 // 'schemaCachingDuration'=>3600, ), ),);
提示: 由于 Active Record 依靠表的元數(shù)據(jù)(metadata)測定列的信息,讀取元數(shù)據(jù)并解析需要時(shí)間。 如果你數(shù)據(jù)庫的表結(jié)構(gòu)很少改動(dòng),你應(yīng)該通過配置 CDbConnection::schemaCachingDuration 屬性的值為一個(gè)大于零的值開啟表結(jié)構(gòu)緩存。
對 AR 的支持受 DBMS 的限制,當(dāng)前只支持下列幾種 DBMS:
注意: 1.0.4 版開始支持 Microsoft SQL Server;1.0.5 版開始支持 Oracle。
如果你想使用一個(gè)不是 db
的應(yīng)用組件,或者如果你想使用 AR 處理多個(gè)數(shù)據(jù)庫,你應(yīng)該覆蓋CActiveRecord::getDbConnection()。 CActiveRecord 類是所有 AR 類的基類。
提示: 通過 AR 使用多個(gè)數(shù)據(jù)庫有兩種方式。如果數(shù)據(jù)庫的結(jié)構(gòu)不同,你可以創(chuàng)建不同的 AR 基類實(shí)現(xiàn)不同的 getDbConnection()。否則,動(dòng)態(tài)改變靜態(tài)變量 CActiveRecord::db 是一個(gè)好主意。
要訪問一個(gè)數(shù)據(jù)表,我們首先需要通過集成 CActiveRecord 定義一個(gè) AR 類。 每個(gè) AR 類代表一個(gè)單獨(dú)的數(shù)據(jù)表,一個(gè) AR 實(shí)例則代表那個(gè)表中的一行。 如下例子演示了代表 tbl_post
表的 AR 類的最簡代碼:
class Post extends CActiveRecord{ public static function model($className=__CLASS__) { return parent::model($className); } public function tableName() { return 'tbl_post'; }}
提示: 由于 AR 類經(jīng)常在多處被引用,我們可以導(dǎo)入包含 AR 類的整個(gè)目錄,而不是一個(gè)個(gè)導(dǎo)入。 例如,如果我們所有的 AR 類文件都在
protected/models
目錄中,我們可以配置應(yīng)用如下:return array( 'import'=>array( 'application.models.*', ),);
默認(rèn)情況下,AR 類的名字和數(shù)據(jù)表的名字相同。如果不同,請覆蓋 tableName() 方法。 model() 方法為每個(gè) AR 類聲明為如此(稍后解釋)。
信息: 要使用 1.1.0 版本中引入的 表前綴功能 AR 類的 tableName() 方法可以通過如下方式覆蓋
public function tableName(){ return '{{post}}';}這就是說,我們將返回通過雙大括號括起來的沒有前綴的表名,而不是完整的表的名字。
數(shù)據(jù)表行中列的值可以作為相應(yīng) AR 實(shí)例的屬性訪問。例如,如下代碼設(shè)置了 title
列 (屬性):
$post=new Post;$post->title='a sample post';
雖然我們從未在 Post
類中顯式定義屬性 title
,我們還是可以通過上述代碼訪問。 這是因?yàn)?nbsp;title
是tbl_post
表中的一個(gè)列,CActiveRecord 通過PHP的 __get()
魔術(shù)方法使其成為一個(gè)可訪問的屬性。 如果我們嘗試以同樣的方式訪問一個(gè)不存在的列,將會拋出一個(gè)異常。
信息: 此指南中,我們在表名和列名中均使用了小寫字母。 這是因?yàn)椴煌?DBMS 處理大小寫的方式不同。 例如,PostgreSQL 默認(rèn)情況下對列的名字大小寫不敏感,而且我們必須在一個(gè)查詢條件中用引號將大小寫混合的列名引起來。 使用小寫字母可以幫助我們避免此問題。
AR 依靠表中良好定義的主鍵。如果一個(gè)表沒有主鍵,則必須在相應(yīng)的 AR 類中通過如下方式覆蓋 primaryKey()
方法指定哪一列或哪幾列作為主鍵。
public function primaryKey(){ return 'id'; // 對于復(fù)合主鍵,要返回一個(gè)類似如下的數(shù)組 // return array('pk1', 'pk2');}
要向數(shù)據(jù)表中插入新行,我們要?jiǎng)?chuàng)建一個(gè)相應(yīng) AR 類的實(shí)例,設(shè)置其與表的列相關(guān)的屬性,然后調(diào)用 save() 方法完成插入:
$post=new Post;$post->title='sample post';$post->content='content for the sample post';$post->create_time=time();$post->save();
如果表的主鍵是自增的,在插入完成后,AR 實(shí)例將包含一個(gè)更新的主鍵。在上面的例子中, id
屬性將反映出新插入帖子的主鍵值,即使我們從未顯式地改變它。
如果一個(gè)列在表結(jié)構(gòu)中使用了靜態(tài)默認(rèn)值(例如一個(gè)字符串,一個(gè)數(shù)字)定義。則 AR 實(shí)例中相應(yīng)的屬性將在此實(shí)例創(chuàng)建時(shí)自動(dòng)含有此默認(rèn)值。改變此默認(rèn)值的一個(gè)方式就是在 AR 類中顯示定義此屬性:
class Post extends CActiveRecord{ public $title='please enter a title'; ......} $post=new Post;echo $post->title; // 這兒將顯示: please enter a title
從版本 1.0.2 起,記錄在保存(插入或更新)到數(shù)據(jù)庫之前,其屬性可以賦值為 CDbExpression 類型。 例如,為保存一個(gè)由 MySQL 的 NOW()
函數(shù)返回的時(shí)間戳,我們可以使用如下代碼:
$post=new Post;$post->create_time=new CDbExpression('NOW()');// $post->create_time='NOW()'; 不會起作用,因?yàn)?/span>// 'NOW()' 將會被作為一個(gè)字符串處理。$post->save();
提示: 由于 AR 允許我們無需寫一大堆 SQL 語句就能執(zhí)行數(shù)據(jù)庫操作, 我們經(jīng)常會想知道 AR 在背后到底執(zhí)行了什么 SQL 語句。這可以通過開啟 Yii 的 日志功能 實(shí)現(xiàn)。例如,我們在應(yīng)用配置中開啟了CWebLogRoute ,我們將會在每個(gè)網(wǎng)頁的最后看到執(zhí)行過的 SQL 語句。 從 1.0.5 版本起,我們可以在應(yīng)用配置中設(shè)置 CDbConnection::enableParamLogging 為 true ,這樣綁定在 SQL 語句中的參數(shù)值也會被記錄。
要讀取數(shù)據(jù)表中的數(shù)據(jù),我們可以通過如下方式調(diào)用 find
系列方法中的一種:
// 查找滿足指定條件的結(jié)果中的第一行$post=Post::model()->find($condition,$params);// 查找具有指定主鍵值的那一行$post=Post::model()->findByPk($postID,$condition,$params);// 查找具有指定屬性值的行$post=Post::model()->findByAttributes($attributes,$condition,$params);// 通過指定的 SQL 語句查找結(jié)果中的第一行$post=Post::model()->findBySql($sql,$params);
如上所示,我們通過 Post::model()
調(diào)用 find
方法。 請記住,靜態(tài)方法 model()
是每個(gè) AR 類所必須的。 此方法返回在對象上下文中的一個(gè)用于訪問類級別方法(類似于靜態(tài)類方法的東西)的 AR 實(shí)例。
如果 find
方法找到了一個(gè)滿足查詢條件的行,它將返回一個(gè) Post
實(shí)例,實(shí)例的屬性含有數(shù)據(jù)表行中相應(yīng)列的值。 然后我們就可以像讀取普通對象的屬性那樣讀取載入的值,例如 echo $post->title;
。
如果使用給定的查詢條件在數(shù)據(jù)庫中沒有找到任何東西, find
方法將返回 null 。
調(diào)用 find
時(shí),我們使用 $condition
和 $params
指定查詢條件。此處 $condition
可以是 SQL 語句中的WHERE
字符串,$params
則是一個(gè)參數(shù)數(shù)組,其中的值應(yīng)綁定到 $condation
中的占位符。例如:
// 查找 postID=10 的那一行$post=Post::model()->find('postID=:postID', array(':postID'=>10));
注意: 在上面的例子中,我們可能需要在特定的 DBMS 中將
postID
列的引用進(jìn)行轉(zhuǎn)義。 例如,如果我們使用 PostgreSQL,我們必須將此表達(dá)式寫為"postID"=:postID
,因?yàn)?PostgreSQL 在默認(rèn)情況下對列名大小寫不敏感。
我們也可以使用 $condition
指定更復(fù)雜的查詢條件。 不使用字符串,我們可以讓 $condition
成為一個(gè)CDbCriteria 的實(shí)例,它允許我們指定不限于 WHERE
的條件。 例如:
$criteria=new CDbCriteria;$criteria->select='title'; // 只選擇 'title' 列$criteria->condition='postID=:postID';$criteria->params=array(':postID'=>10);$post=Post::model()->find($criteria); // $params 不需要了
注意,當(dāng)使用 CDbCriteria 作為查詢條件時(shí),$params
參數(shù)不再需要了,因?yàn)樗梢栽?nbsp;CDbCriteria 中指定,就像上面那樣。
一種替代 CDbCriteria 的方法是給 find
方法傳遞一個(gè)數(shù)組。 數(shù)組的鍵和值各自對應(yīng)標(biāo)準(zhǔn)(criterion)的屬性名和值,上面的例子可以重寫為如下:
$post=Post::model()->find(array( 'select'=>'title', 'condition'=>'postID=:postID', 'params'=>array(':postID'=>10),));
信息: 當(dāng)一個(gè)查詢條件是關(guān)于按指定的值匹配幾個(gè)列時(shí),我們可以使用 findByAttributes()。我們使
$attributes
參數(shù)是一個(gè)以列名做索引的值的數(shù)組。在一些框架中,此任務(wù)可以通過調(diào)用類似findByNameAndTitle
的方法實(shí)現(xiàn)。雖然此方法看起來很誘人, 但它常常引起混淆,沖突和比如列名大小寫敏感的問題。
當(dāng)有多行數(shù)據(jù)匹配指定的查詢條件時(shí),我們可以通過下面的 findAll
方法將他們?nèi)繋Щ亍?每個(gè)都有其各自的find
方法,就像我們已經(jīng)講過的那樣。
// 查找滿足指定條件的所有行$posts=Post::model()->findAll($condition,$params);// 查找?guī)в兄付ㄖ麈I的所有行$posts=Post::model()->findAllByPk($postIDs,$condition,$params);// 查找?guī)в兄付▽傩灾档乃行?/span>$posts=Post::model()->findAllByAttributes($attributes,$condition,$params);// 通過指定的SQL語句查找所有行$posts=Post::model()->findAllBySql($sql,$params);
如果沒有任何東西符合查詢條件,findAll
將返回一個(gè)空數(shù)組。這跟 find
不同,find
會在沒有找到什么東西時(shí)返回 null。
除了上面講述的 find
和 findAll
方法,為了方便,(Yii)還提供了如下方法:
// 獲取滿足指定條件的行數(shù)$n=Post::model()->count($condition,$params);// 通過指定的 SQL 獲取結(jié)果行數(shù)$n=Post::model()->countBySql($sql,$params);// 檢查是否至少有一行復(fù)合指定的條件$exists=Post::model()->exists($condition,$params);
在 AR 實(shí)例填充了列的值之后,我們可以改變它們并把它們存回?cái)?shù)據(jù)表。
$post=Post::model()->findByPk(10);$post->title='new post title';$post->save(); // 將更改保存到數(shù)據(jù)庫
正如我們可以看到的,我們使用同樣的 save() 方法執(zhí)行插入和更新操作。 如果一個(gè) AR 實(shí)例是使用 new
操作符創(chuàng)建的,調(diào)用 save() 將會向數(shù)據(jù)表中插入一行新數(shù)據(jù); 如果 AR 實(shí)例是某個(gè) find
或 findAll
方法的結(jié)果,調(diào)用save() 將更新表中現(xiàn)有的行。 實(shí)際上,我們是使用 CActiveRecord::isNewRecord 說明一個(gè) AR 實(shí)例是不是新的。
直接更新數(shù)據(jù)表中的一行或多行而不首先載入也是可行的。 AR 提供了如下方便的類級別方法實(shí)現(xiàn)此目的:
// 更新符合指定條件的行Post::model()->updateAll($attributes,$condition,$params);// 更新符合指定條件和主鍵的行Post::model()->updateByPk($pk,$attributes,$condition,$params);// 更新滿足指定條件的行的計(jì)數(shù)列Post::model()->updateCounters($counters,$condition,$params);
在上面的代碼中, $attributes
是一個(gè)含有以 列名作索引的列值的數(shù)組; $counters
是一個(gè)由列名索引的可增加的值的數(shù)組;$condition
和 $params
在前面的段落中已有描述。
如果一個(gè) AR 實(shí)例被一行數(shù)據(jù)填充,我們也可以刪除此行數(shù)據(jù)。
$post=Post::model()->findByPk(10); // 假設(shè)有一個(gè)帖子,其 ID 為 10$post->delete(); // 從數(shù)據(jù)表中刪除此行
注意,刪除之后, AR 實(shí)例仍然不變,但數(shù)據(jù)表中相應(yīng)的行已經(jīng)沒了。
使用下面的類級別代碼,可以無需首先加載行就可以刪除它。
// 刪除符合指定條件的行Post::model()->deleteAll($condition,$params);// 刪除符合指定條件和主鍵的行Post::model()->deleteByPk($pk,$condition,$params);
當(dāng)插入或更新一行時(shí),我們常常需要檢查列的值是否符合相應(yīng)的規(guī)則。 如果列的值是由最終用戶提供的,這一點(diǎn)就更加重要??傮w來說,我們永遠(yuǎn)不能相信任何來自客戶端的數(shù)據(jù)。
當(dāng)調(diào)用 save() 時(shí), AR 會自動(dòng)執(zhí)行數(shù)據(jù)驗(yàn)證。 驗(yàn)證是基于在 AR 類的 rules() 方法中指定的規(guī)則進(jìn)行的。 關(guān)于驗(yàn)證規(guī)則的更多詳情,請參考 聲明驗(yàn)證規(guī)則 一節(jié)。 下面是保存記錄時(shí)所需的典型的工作流。
if($post->save()){ // 數(shù)據(jù)有效且成功插入/更新}else{ // 數(shù)據(jù)無效,調(diào)用 getErrors() 提取錯(cuò)誤信息}
當(dāng)要插入或更新的數(shù)據(jù)由最終用戶在一個(gè) HTML 表單中提交時(shí),我們需要將其賦給相應(yīng)的 AR 屬性。 我們可以通過類似如下的方式實(shí)現(xiàn):
$post->title=$_POST['title'];$post->content=$_POST['content'];$post->save();
如果有很多列,我們可以看到一個(gè)用于這種復(fù)制的很長的列表。 這可以通過使用如下所示的 attributes 屬性簡化操作。 更多信息可以在 安全的特性賦值 一節(jié)和 創(chuàng)建動(dòng)作 一節(jié)找到。
// 假設(shè) $_POST['Post'] 是一個(gè)以列名索引列值為值的數(shù)組$post->attributes=$_POST['Post'];$post->save();
類似于表記錄,AR 實(shí)例由其主鍵值來識別。 因此,要對比兩個(gè) AR 實(shí)例,假設(shè)它們屬于相同的 AR 類, 我們只需要對比它們的主鍵值。 然而,一個(gè)更簡單的方式是調(diào)用 CActiveRecord::equals()。
信息: 不同于 AR 在其他框架的執(zhí)行, Yii 在其 AR 中支持多個(gè)主鍵. 一個(gè)復(fù)合主鍵由兩個(gè)或更多字段構(gòu)成。相應(yīng)地, 主鍵值在 Yii 中表現(xiàn)為一個(gè)數(shù)組. primaryKey 屬性給出了一個(gè) AR 實(shí)例的主鍵值。
CActiveRecord 提供了幾個(gè)占位符方法,它們可以在子類中被覆蓋以自定義其工作流。
beforeSave 和 afterSave: 這兩個(gè)將在保存 AR 實(shí)例之前和之后被調(diào)用。
beforeDelete 和 afterDelete: 這兩個(gè)將在一個(gè) AR 實(shí)例被刪除之前和之后被調(diào)用。
afterConstruct: 這個(gè)將在每個(gè)使用 new
操作符創(chuàng)建 AR 實(shí)例后被調(diào)用。
beforeFind: 這個(gè)將在一個(gè) AR 查找器被用于執(zhí)行查詢(例如 find()
, findAll()
)之前被調(diào)用。 1.0.9 版本開始可用。
afterFind: 這個(gè)將在每個(gè) AR 實(shí)例作為一個(gè)查詢結(jié)果創(chuàng)建時(shí)被調(diào)用。
每個(gè) AR 實(shí)例都含有一個(gè)屬性名叫 dbConnection ,是一個(gè) CDbConnection 的實(shí)例,這樣我們可以在需要時(shí)配合 AR 使用由 Yii DAO 提供的 事務(wù) 功能:
$model=Post::model();$transaction=$model->dbConnection->beginTransaction();try{ // 查找和保存是可能由另一個(gè)請求干預(yù)的兩個(gè)步驟 // 這樣我們使用一個(gè)事務(wù)以確保其一致性和完整性 $post=$model->findByPk(10); $post->title='new post title'; $post->save(); $transaction->commit();}catch(Exception $e){ $transaction->rollBack();}
Note: 對命名范圍的支持從版本 1.0.5 開始。 命名范圍的最初想法來源于 Ruby on Rails.
命名范圍(named scope) 表示一個(gè) 命名的(named) 查詢規(guī)則,它可以和其他命名范圍聯(lián)合使用并應(yīng)用于 Active Record 查詢。
命名范圍主要是在 CActiveRecord::scopes() 方法中以名字-規(guī)則對的方式聲明。 如下代碼在 Post
模型類中聲明了兩個(gè)命名范圍, published
和 recently
。
class Post extends CActiveRecord{ ...... public function scopes() { return array( 'published'=>array( 'condition'=>'status=1', ), 'recently'=>array( 'order'=>'create_time DESC', 'limit'=>5, ), ); }}
每個(gè)命名范圍聲明為一個(gè)可用于初始化 CDbCriteria 實(shí)例的數(shù)組。 例如,recently
命名范圍指定 order
屬性為create_time DESC
, limit
屬性為 5。他們翻譯為查詢規(guī)則后就會返回最近的5篇帖子。
命名范圍多用作 find
方法調(diào)用的修改器。 幾個(gè)命名范圍可以鏈到一起形成一個(gè)更有約束性的查詢結(jié)果集。例如, 要找到最近發(fā)布的帖子, 我們可以使用如下代碼:
$posts=Post::model()->published()->recently()->findAll();
總體來說,命名范圍必須出現(xiàn)在一個(gè) find
方法調(diào)用的左邊。 它們中的每一個(gè)都提供一個(gè)查詢規(guī)則,并聯(lián)合到其他規(guī)則, 包括傳遞給 find
方法調(diào)用的那一個(gè)。 最終結(jié)果就像給一個(gè)查詢添加了一系列過濾器。
從版本 1.0.6 開始,命名范圍也可用于 update
和 delete
方法。 例如,如下代碼將刪除所有最近發(fā)布的帖子:
Post::model()->published()->recently()->delete();
注意: 命名范圍只能用于類級別方法。也就是說,此方法必須使用
ClassName::model()
調(diào)用。
命名范圍可以參數(shù)化。例如, 我們想自定義 recently
命名范圍中指定的帖子數(shù)量,要實(shí)現(xiàn)此目的,不是在CActiveRecord::scopes 方法中聲明命名范圍, 而是需要定義一個(gè)名字和此命名范圍的名字相同的方法:
public function recently($limit=5){ $this->getDbCriteria()->mergeWith(array( 'order'=>'create_time DESC', 'limit'=>$limit, )); return $this;}
然后,我們就可以使用如下語句獲取3條最近發(fā)布的帖子。
$posts=Post::model()->published()->recently(3)->findAll();
上面的代碼中,如果我們沒有提供參數(shù) 3,我們將默認(rèn)獲取 5 條最近發(fā)布的帖子。
模型類可以有一個(gè)默認(rèn)命名范圍,它將應(yīng)用于所有 (包括相關(guān)的那些) 關(guān)于此模型的查詢。例如,一個(gè)支持多種語言的網(wǎng)站可能只想顯示當(dāng)前用戶所指定的語言的內(nèi)容。 因?yàn)榭赡軙泻芏嚓P(guān)于此網(wǎng)站內(nèi)容的查詢, 我們可以定義一個(gè)默認(rèn)的命名范圍以解決此問題。 為實(shí)現(xiàn)此目的,我們覆蓋 CActiveRecord::defaultScope 方法如下:
class Content extends CActiveRecord{ public function defaultScope() { return array( 'condition'=>"language='".Yii::app()->language."'", ); }}
現(xiàn)在,如果下面的方法被調(diào)用,將會自動(dòng)使用上面定義的查詢規(guī)則:
$contents=Content::model()->findAll();
注意,默認(rèn)的命名范圍只會應(yīng)用于 SELECT
查詢。INSERT
, UPDATE
和 DELETE
查詢將被忽略。