Yii快速入門(五)擴展

在開發中擴展Yii是一個很常見的行為.例如,當你寫一個新的控制器時,你通過繼承 CController 類擴展了 Yii;當你編寫一個新的組件時,你正在繼承 CWidget 或者一個已存在的組件類.如果擴展代碼是由第三方開發者為了復用而設計的,我們則稱之為 extension(擴展)。
一個擴展通常是為了一個單一的目的服務的.在 Yii 中,他可以按照如下分類:

 * 應用的部件
 * 組件
 * 控制器
 * 動作
 * 過濾器
 * 控制臺命令
 * 校驗器: 校驗器是一個繼承自 CValidator 類的部件。
 * 輔助器: 輔助器是一個只具有靜態方法的類.它類似于使用類名作為命名空間的全局函數。
 * 模塊: 模塊是一個有著若干個類文件和相應特長文件的包.一個模塊通常更高級,比一個單一的部件具備更先進的功能.
         例如我們可以擁有一個具備整套用戶管理功能的模塊。

擴展也可以是不屬于上述分類中的任何一個的部件。事實上,Yii 是設計得很謹慎的,以至于幾乎它的每段代碼都可以被擴展和訂制以適用于特定需求。

一、使用擴展

使用擴展通常包含了以下三步:

  1. 從 Yii 的 擴展庫 下載擴展。
  2. 解壓到 應用程序的基目錄 的子目錄 extensions/xyz 下,這里的 xyz 是擴展的名稱。
  3. 導入, 配置和使用擴展。
    每個擴展都有一個所有擴展中唯一的名稱標識。把一個擴展命名為 xyz ,我們也可以使用路徑別名定位到包含了 xyz 所有文件的基目錄。
    不同的擴展有著不同的導入,配置,使用要求.以下是我們通常會用到擴展的場景,按照他們在 概述 中的描述分類。

1、應用的部件

使用 應用的部件, 首先我們需要添加一個新條目到 應用配置 的 components 屬性, 如下所示:

return array(
    // 'preload'=>array('xyz',...),
    'components'=>array(
        'xyz'=>array(
            'class'=>'application.extensions.xyz.XyzClass',
            'property1'=>'value1',
            'property2'=>'value2',
        ),
        // 其他部件配置
    ),
);

然后,我們可以在任何地方通過使用 Yii::app()->xyz 來訪問部件.部件將會被 惰性創建(就是,僅當它第一次被訪問時創建.) , 除非我們把它配置到 preload 屬性里。

2、組件

組件 主要用在 視圖 里.假設組件類 XyzClass 屬于 xyz 擴展,我們可以如下在視圖中使用它:

// 組件不需要主體內容
<?php $this->widget('application.extensions.xyz.XyzClass', array(
    'property1'=>'value1',
    'property2'=>'value2')); ?>
// 組件可以包含主體內容
<?php $this->beginWidget('application.extensions.xyz.XyzClass', array(
    'property1'=>'value1',
    'property2'=>'value2')); ?>
...組件的主體內容...
<?php $this->endWidget(); ?>

3、動作

動作 被 控制器 用于響應指定的用戶請求.假設動作的類 XyzClass 屬于 xyz 擴展,我們可以在我們的控制器類里重寫 CController::actions 方法來使用它:

class TestController extends CController
{
    public function actions()
    {
        return array(
            'xyz'=>array(
                'class'=>'application.extensions.xyz.XyzClass',
                'property1'=>'value1',
                'property2'=>'value2',
            ),
            // 其他動作
        );
    }
}

然后,我們可以通過 路由 test/xyz 來訪問。

4、過濾器

過濾器 也被 控制器 使用。過濾器主要用于當其被 動作 掛起時預處理,提交處理用戶請求。假設過濾器的類 XyzClass 屬于 xyz 擴展,我們可以在我們的控制器類里重寫 CController::filters 方法來使用它:

class TestController extends CController
{
    public function filters()
    {
        return array(
            array(
                'application.extensions.xyz.XyzClass',
                'property1'=>'value1',
                'property2'=>'value2',
            ),
            // 其他過濾器
        );
    }
}

在上述代碼中,我們可以在數組的第一個元素離使用加號或者減號操作符來限定過濾器只在那些動作中生效。更多信息,請參照文檔的 CController

5、控制器

控制器 提供了一套可以被用戶請求的動作。我們需要在 應用配置 里設置 CWebApplication::controllerMap 屬性,才能在控制器里使用擴展:

return array(
    'controllerMap'=>array(
        'xyz'=>array(
            'class'=>'application.extensions.xyz.XyzClass',
            'property1'=>'value1',
            'property2'=>'value2',
        ),
        // 其他控制器
    ),
);

然后, 一個在控制里的 a 行為就可以通過 路由 xyz/a 來訪問了。

6、校驗器

校驗器主要用在 模型類 (繼承自 CFormModel 或者 CActiveRecord) 中.假設校驗器類 XyzClass 屬于 xyz 擴展,我們可以在我們的模型類中通過 CModel::rules 重寫 CModel::rules 來使用它:

class MyModel extends CActiveRecord // or CFormModel
{
    public function rules()
    {
        return array(
            array(
                'attr1, attr2',
                'application.extensions.xyz.XyzClass',
                'property1'=>'value1',
                'property2'=>'value2',
            ),
            // 其他校驗規則
        );
    }
}

7、控制臺命令

控制臺命令擴展通常使用一個額外的命令來增強 yiic 的功能.假設命令控制臺 XyzClass 屬于 xyz 擴展,我們可以通過設定控制臺應用的配置來使用它:

return array(
    'commandMap'=>array(
        'xyz'=>array(
            'class'=>'application.extensions.xyz.XyzClass',
            'property1'=>'value1',
            'property2'=>'value2',
        ),
        // 其他命令
    ),
);

然后,我們就能使用配備了額外命令 xyz 的 yiic 工具了。
注意: 控制臺應用通常使用了一個不同于 Web 應用的配置文件.如果使用了 yiic webapp 命令創建了一個應用,這樣的話,控制臺應用的 protected/yiic 的配置文件就是 protected/config/console.php 了,而Web應用的配置文件 則是 protected/config/main.php。

8、模塊

模塊通常由多個類文件組成,且往往綜合上述擴展類型。因此,你應該按照和以下一致的指令來使用模塊。

9、通用部件

使用一個通用 部件, 我們首先需要通過使用
Yii::import('application.extensions.xyz.XyzClass');
來包含它的類文件。然后,我們既可以創建一個類的實例,配置它的屬性,也可以調用它的方法。我們還可以創建一個新的子類來擴展它。

二、創建擴展

由于擴展意味著是第三方開發者使用,需要一些額外的努力去創建它。以下是一些一般性的指導原則:

*擴展最好是自己自足。也就是說,其外部的依賴應是最少的。如果用戶的擴展需要安裝額外的軟件包,類或資源檔案,
 這將是一個頭疼的問題。
*文件屬于同一個擴展的,應組織在同一目錄下,目錄名用擴展名稱。
*擴展里面的類應使用一些單詞字母前綴,以避免與其他擴展命名沖突。
*擴展應該提供詳細的安裝和API文檔。這將減少其他開發員使用擴展時花費的時間和精力。
*擴展應該用適當的許可。如果您想您的擴展能在開源和閉源項目中使用,你可以考慮使用許可證,
 如BSD的,麻省理工學院等,但不是GPL的,因為它要求其衍生的代碼是開源的。

在下面,我們根據 overview中所描述的分類,描述如何創建一個新的擴展。當您要創建一個主要用于在您自己項目的component部件,這些描述也適用。

1、Application Component(應用部件)

一個application component應實現接口IApplicationComponent或繼承CApplicationComponent。主要需要實現的方法是 IApplicationComponent::init,部件在此執行一些初始化工作。此方法在部件創建和屬性值(在application configuration里指定的 )被賦值后調用。
默認情況下,一個應用程序部件創建和初始化,只有當它首次訪問期間要求處理。如果一個應用程序部件需要在應用程序實例被創建后創建,它應要求用戶在CApplication::preload 的屬性中列出他的編號。

2、Widget(小工具)

widget應繼承CWidget或其子類。 A widget should extend from CWidget or its child classes.
最簡單的方式建立一個新的小工具是繼承一個現成的小工具和重載它的方法或改變其默認的屬性值。例如,如果您想為CTabView使用更好的CSS樣式,您可以配置其CTabView::cssFile屬性,當使用的小工具時。您還可以繼承CTabView如下,讓您在使用小工具時,不再需要配置屬性。

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方法和指定CTabView::cssFile的 URL到我們的新的默認CSS樣式如果此屬性未設置時。我們把新的CSS樣式文件和MyTabView類文件放在相同的目錄下,以便他們能夠封裝成擴展。由于CSS樣式文件不是通過Web訪問,我們需要發布作為一項asset資源。
要從零開始創建一個新的小工具,我們主要是需要實現兩個方法:CWidget::initCWidget::run。第一種方法是當我們在視圖中使用 $this->beginWidget 插入一個小工具時被調用,第二種方法在$this->endWidget被調用時調用。如果我們想在這兩個方法調用之間捕捉和處理顯示的內容,我們可以開始output bufferingCWidget::init 和在CWidget::run中回收緩沖輸出作進一步處理。 If we want to capture and process the content displayed between these two method invocations, we can start output buffering in CWidget::init and retrieve the buffered output in CWidget::run for further processing.
在網頁中使用的小工具,小工具往往包括CSS,Javascript或其他資源文件。我們叫這些文件assets,因為他們和小工具類在一起,而且通常Web用戶無法訪問。為了使這些檔案通過Web訪問,我們需要用CWebApplication::assetManager發布他們,例如上述代碼段所示。此外,如果我們想包括CSS或JavaScript文件在當前的網頁,我們需要使用CClientScript注冊 :

class MyWidget extends CWidget
{
    protected function registerClientScript()
    {
        // ...publish CSS or JavaScript file here...
        $cs=Yii::app()->clientScript;
        $cs->registerCssFile($cssFile);
        $cs->registerScriptFile($jsFile);
    }
}

小工具也可能有自己的視圖文件。如果是這樣,創建一個目錄命名views在包括小工具類文件的目錄下,并把所有的視圖文件放里面。在小工具類中使用$this->render('ViewName') 來render渲染小工具視圖,類似于我們在控制器里做。

3、Action(動作)

action應繼承CAction或者其子類。action要實現的主要方法是IAction::run 。

4、Filter(過濾器)

filter應繼承CFilter 或者其子類。filter要實現的主要方法是CFilter::preFilterCFilter::postFilter。前者是在action之前被執行,而后者是在之后。

class MyFilter extends CFilter
{
    protected function preFilter($filterChain)
    {
        // logic being applied before the action is executed
        return true; // false if the action should not be executed
    }
    protected function postFilter($filterChain)
    {
        // logic being applied after the action is executed
    }
}

參數$filterChain的類型是CFilterChain,其包含當前被filter的action的相關信息。

5、Controller(控制器)

controller要作為擴展需繼承CExtController,而不是 CController。主要的原因是因為CController 認定控制器視圖文件位于application.views.ControllerID 下,而CExtController認定視圖文件在views目錄下,也是包含控制器類目錄的一個子目錄。因此,很容易重新分配控制器,因為它的視圖文件和控制類是在一起的。

6、Validator(驗證)

Validator需繼承CValidator和實現CValidator::validateAttribute方法。

class MyValidator extends CValidator
{
    protected function validateAttribute($model,$attribute)
    {
        $value=$model->$attribute;
        if($value has error)
            $model->addError($attribute,$errorMessage);
    }
}

7、Console Command(控制臺命令)

console command 應繼承CConsoleCommand和實現CConsoleCommand::run方法。 或者,我們可以重載CConsoleCommand::getHelp來提供一些更好的有關幫助命令。

class MyCommand extends CConsoleCommand
{
    public function run($args)
    {
        // $args gives an array of the command-line arguments for this command
    }
 
    public function getHelp()
    {
        return 'Usage: how to use this command';
    }
}

8、Module(模塊)

請參閱modules一節中關于就如何創建一個模塊。
一般準則制訂一個模塊,它應該是獨立的。模塊所使用的資源文件(如CSS , JavaScript ,圖片),應該和模塊一起分發。還有模塊應發布它們,以便可以Web訪問它們 。

9、Generic Component(通用組件)

開發一個通用組件擴展類似寫一個類。還有,該組件還應該自足,以便它可以很容易地被其他開發者使用。

三、使用第三方庫

Yii是精心設計的,使第三方庫可易于集成,進一步擴大Yii的功能。 當在一個項目中使用第三方庫,程序員往往遇到關于類命名和文件包含的問題。 因為所有Yii類以C字母開頭,這就減少可能會出現的類命名問題;而且因為Yii依賴SPL autoload執行類文件包含,如果他們使用相同的自動加載功能或PHP包含路徑包含類文件,它可以很好地結合。
下面我們用一個例子來說明如何在一個Yii application從Zend framework使用Zend_Search_Lucene部件。
首先,假設protected是application base directory,我們提取Zend Framework的發布文件到protected/vendors目錄 。 確認protected/vendors/Zend/Search/Lucene.php文件存在。
第二,在一個controller類文件的開始,加入以下行:

Yii::import('application.vendors.*');
require_once('Zend/Search/Lucene.php');

上述代碼包含類文件Lucene.php。因為我們使用的是相對路徑,我們需要改變PHP的包含路徑,以使文件可以正確定位。這是通過在require_once之前調用Yii::import做到。
一旦上述設立準備就緒后,我們可以在controller action里使用Lucene類,類似如下:

$lucene=new Zend_Search_Lucene($pathOfIndex);
$hits=$lucene->find(strtolower($keyword));
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,048評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,414評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,169評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,722評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,465評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,823評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,813評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,000評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,554評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,295評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,513評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,722評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,125評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,430評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,237評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,482評論 2 379

推薦閱讀更多精彩內容

  • 一、入口文件 入口文件內容:一般格式如下: 二、主配置文件 保存位置:你的應用/protected/config/...
    layjoy閱讀 1,210評論 4 14
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,728評論 25 708
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,825評論 18 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,733評論 18 399
  • 任何創作藝術作品的人,只需擁有1000名鐵桿粉絲,也就是無論你創造出什么作品,他/她都愿意付費購買的粉絲,便能糊口...
    托爸閱讀 227評論 0 0