1.1 擴展Yii
擴展Yii在開發過程中是很常見的。例如,當你編寫一個新的控制器,你從Yii繼承CController類;當你寫一個新的小工具widget,你繼承於CWidget或者是另外的一個widget。我們這些擴展代碼可以被第三方使用,我們稱之爲yii的擴展。
一個擴展一般只提供單一功能。在Yii裏,可以分爲以下幾類:
●應用組件 application component
●行爲 behavior
●小工具 widget
●控制器 controller
●動作 action
●過濾器 filter
●控制命令 console command
●驗證器 validator
●幫助類 helper
●模塊 module
擴展也可以是一個組件,不屬於以上的分類。實際上,yii非常小心的設計每段代碼,讓每個人可以自己擴展或者是自定義組件。
1.2 使用擴展
使用一個擴展包括以下幾個步驟:
1、從官網地址http://www.yiiframework.com/extensions/ 下載要使用的擴展。
2、在項目的子目錄extensions/xyz下,解壓該擴展。(xyz代表擴展的名稱)
3、導入,配置擴展,然後就可以調用了。
每個擴展都有一個唯一的名稱。假設我們要用的擴展名稱爲xyz,那麼我們一直都可以用路徑別名ext.xyz來訪問擴展的目錄。該目錄下包含了該擴展的所有文件。
不同的擴展有不同的導入要求,配置,以及使用方法。下面,我們按照之前的分類,總結一些常見的擴展使用場景。
1.2.1 Zii擴展
在我們開始介紹使用第三方擴展之前,我們想先介紹以下Zii這個擴展。這個擴展是Yii開發小組開發的,在每個yii的髮型版本中都自帶有的。
當要使用Zii擴展時,你必須在當前類中調用路徑別名zii.path.to.ClassName。這裏的跟目錄別名zii是在Yii裏已經預先定義好的,他指向Zii庫的根目錄。例如,要使用CGridView,我們就在視圖腳本語句中調用以下語句:
- $this->widget('zii.widgets.grid.CGridView', array(
- 'dataProvider'=>$dataProvider,
- ));
1.2.2 應用組件
要使用一個應用組件,我們要在項目的配置文件中的components字段中,加入一個新的選項,如下:
- return array(
- // 'preload'=>array('xyz',...),
- 'components'=>array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other component configurations
- ),
- );
然後,我們就可以在任何地方調用Yii::app()->xyz。組件會滯後創建(也就是,在第一次訪問的時候再生成),除非,我們在預裝載的屬性列表中指定該組件的裝載屬性。
1.2.3 行爲
行爲可以被用於任何類型的組件。他的使用包括2個步驟。第一步,一個行爲要綁定到一個指定的組件。第二步,通過這個目標組件來調用這個行爲。例如:
- // $name uniquely identifies the behavior in the component
- $component->attachBehavior($name,$behavior);
- // test() is a method of $behavior
- $component->test();
更多情況下,我們是通過配置的方式來綁定一個行爲到目標組件上,而不是調用attachBehavior的方法。例如,要綁定一個行爲到應用組件中,我們可以配置項目工程如下:
- return array(
- 'components'=>array(
- 'db'=>array(
- 'class'=>'CDbConnection',
- 'behaviors'=>array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzBehavior',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- ),
- ),
- //....
- ),
- );
上面的代碼中,把xyz的行爲綁定到了一個數據庫組件中。我們之所以可以這麼做,是因爲CApplicationComponent定義了一個叫做behaviors的屬性。通過設置這個屬性爲一個行爲配置列表,當這個組件初始化的時候,會綁定這些行爲。
對於CController, CFormModel 和 CActiveRecord這些經常被用於擴展的類,可以通過重載他們的behaviors的方法來綁定。這些類會在初始化的時候,自動加載這個方法裏的所有行爲:
- public function behaviors()
- {
- return array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzBehavior',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- );
- }
1.2.4 小工具Widget
widget一般用於視圖。假設一個widget類XyzClass屬於xyz擴展,我們可以在視圖中這樣使用:
- // widget that does not need body content
- <?php $this->widget('ext.xyz.XyzClass', array(
- 'property1'=>'value1',
- 'property2'=>'value2')); ?>
- // widget that can contain body content
- <?php $this->beginWidget('ext.xyz.XyzClass', array(
- 'property1'=>'value1',
- 'property2'=>'value2')); ?>
- ...body content of the widget...
- <?php $this->endWidget(); ?>
1.2.5 動作
動作是一個控制器用來相應特定的用戶請求的。假設一個動作類XyzClass屬於xyz這個擴展,我們可以在控制器中重載CController::actions的方法來使用:
- class TestController extends CController
- {
- public function actions()
- {
- return array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other actions
- );
- }
- }
這樣,這個動作就可以就可以通過路由test/xyz來訪問了。
1.2.6 過濾器
過濾器跟動作一樣,也是用於控制器的。他們一般是在一個動作捕獲到用戶時,預先處理,或者是最後處理。假設一個過濾器類XyzClass屬於xyz擴展,我們可以通過重載CController::filters的方法來使用:
- class TestController extends CController
- {
- public function filters()
- {
- return array(
- array(
- 'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other filters
- );
- }
- }
在上例中,我們可以在第一個元素組中,用+號或者是減號來限制過濾器只作用於哪些指定的動作。更多詳情請參見控制器說明。
1.2.7 控制器
一個控制器提供了一些能被用戶請求的動作。要用控制器擴展,我們要在項目的配置文件中配置CWebApplication::controllerMap:
- return array(
- 'controllerMap'=>array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other controllers
- ),
- );
這樣,控制器中的方法a,我們就可以通過路由xyz/a來訪問了。
1.2.8 校驗器
一個校驗器主要用於模型類(不管是繼承於CFormModel 或CActiveRecord的都可以)。假設一個校驗器類XyzClass屬於擴展xyz的,我們可以在模型類中重載CModel::rules():
- class MyModel extends CActiveRecord // or CFormModel
- {
- public function rules()
- {
- return array(
- array(
- 'attr1, attr2',
- 'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other validation rules
- );
- }
- }
1.2.9 控制檯命令
一個控制檯命令擴展一般用於加強yiic功能。假設一個控制檯命令類屬於xyz擴展,我們可以爲該控制檯配置如下:
- return array(
- 'commandMap'=>array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other commands
- ),
- );
然後,我們就能使用配備了額外命令 xyz
的 yiic
工具了。
注意:一個控制檯程序的配置文件使用方法,一般跟web工程的是不同的。如果工程是通過yiic webapp命令創建的,那麼控制檯配置文件就是protected/config/console.php,web工程的配置文件是protected/config/main.php。
1.2.10 模塊
參考模塊的使用說明
1.2.11 通用組件
要使用一個通用組件, 我們首先要導入他的類:
- Yii::import('application.extensions.xyz.XyzClass');
然後我們可以創建這個類的實例,配置屬性,然後調用他的方法。我們也可以用他創建子類。
1.3 新建擴展
由於擴展是要提供給第三方開發者使用,所以在創建的時候需要額外的工作。以下是一些常規指引:
●擴展最好是隻關自身的。也就是,擴展最好不要對外有關聯。如果說一個擴展,需要另外的安裝包,類,或者是資源,對於開發者來說會很頭疼。
●擴展有關的文件都必須放在以該擴展命名的目錄下
●類名必須有自己的前綴,避免跟其他擴展的類重名。
●擴展必須有完整的安裝說明以及API說明。這樣其他開發者在使用的時候就可以節約很多時間。
●一個擴展要有一個合適的許可。如果你想你的擴展應用於開源或者是閉源項目,你可以使用諸如BSD,MIT等許可。GPL只許可用於開源項目。
接下來,我們來看看如何創建一個擴展。之前關於擴展的描述,同樣適用於你自己的工程。
1.3.1 應用組件
一個應用組件應該實現接口{IApplicationComponent}或者是繼承於IApplicationComponent。主要要實現的方法是IApplicationComponent::init,這個方法裏,組件主要完成初始化工作。這個方法在組件創建以後被調用。
默認情況下,應用組件只有在第一次被請求使用的時候纔會創建。如果想要一個應用組件在項目運行後就創建,那麼必須在CApplication::preload 的屬性中列出。
1.3.2 行爲
要創建一個行爲,必須實現[IBehavior]的接口。爲了簡便,Yii提供了一個基類CBehavior,他已經實現了這個接口,另外還提供了一些簡便的方法。子類主要實現他所想要實現的額外方法。
當爲CModel 和CActiveRecord開發行爲的是時候,也可以繼承於CModelBehavior and CActiveRecordBehavior。這些基類提供了額外的元件,專門爲CModel 和CActiveRecord定做的。例如,CActiveRecordBehavior類實現了一組方法,用來相應ActiveRecord對象的生命週期。子類可以重載這些方法,自定義那些AR生命週期中的代碼。
下面的例子中演示了AR行爲。當這個行爲綁定到一個AR對象中,當AR對象調用save方法時,會自動用當前時間設定create_time 和update_time的屬性值。
- class TimestampBehavior extends CActiveRecordBehavior
- {
- public function beforeSave($event)
- {
- if($this->owner->isNewRecord)
- $this->owner->create time=time();
- else
- $this->owner->update time=time();
- }
- }
1.3.3 小工具
一個widget可以繼承於CWidget或者是他的子類。
一個創建小工具的最簡單的方法,就是繼承於現有的小工具,重寫他的方法或者是設置他的屬性。例如,你要給CTableView用一個更好的css樣式,你可以在使用小工具的時候,設置他的CTabView::cssFile屬性。你也可以繼承於CTableView,這樣在使用這個widget時就不要配置他的屬性了:
- class MyTabView extends CTabView
- {
- public function init()
- {
- if($this->cssFile===null)
- {
- $file=dirname(__FILE__).DIRECTORY SEPARATOR.'tabview.css';
- $this->cssFile=Yii::app()->getAssetManager()->publish($file);
- }
- parent::init();
- }
- }
上例中,我們重載了CWidget::init方法,然後如果是沒有指定cssFile的屬性,我們就指定爲特定的文件。由於css文件是web不能直接訪問的,所以我們必須作爲一個asset來發布。
咳,精力實在不足了,先暫停到此。