首頁  >  文章  >  php教程  >  Yii快速入門 (二)

Yii快速入門 (二)

黄舟
黄舟原創
2016-12-20 11:08:401046瀏覽

三、控制器(Controller)
控制器 是 CController類別的子類別的實例。它在當用戶請求時由應用程式創建。當一個控制器運行時,它執行所要求的動作(控制器類別方法),動作通常會引入所需的模型並渲染相應的視圖。動作,就是一個名字以action 開頭的控制器類別方法(action+大寫首字母的動作名稱)。
控制器類別檔案保存位置protected/controllers/
控制器和動作以 ID 識別。
控制器ID 是一種'父目錄/子目錄/控制器名稱' 的格式,對應對應的控制器類別檔案protected/controllers/父目錄/子目錄/大寫首字母的控制器名稱Controller.php;
動作ID 是除去action 前綴的動作方法名稱。
1、路由
使用者以路由的形式請求特定的控制器和動作。路由是由控制器 ID 和動作 ID 連接起來的,兩者以斜線分割。
例如,路由 post/edit 代表 PostController 及其 edit

動作。預設情況下,URL http://hostname/index.php?r=post/edit即請求此控制器和動作。
注意: 預設情況下,路由是大小寫敏感的。可以透過設定應用程式配置中的CUrlManager::caseSensitive 為 false使路由對大小寫不敏感。當在大小寫不敏感模式中時,要確保你遵循了相應的規則約定,即:包含控制器類別文件的目錄名小寫,且控制器映射 和動作映射 中使用的鍵為小寫。
路由的格式:控制器ID/動作ID 或模組ID/控制器ID/動作ID(如果是嵌套模組,模組ID就是父模組ID/子模組ID)
2、控制器實例化
應用將使用下列規則決定控制器的類別以及類別檔案的位置:
1、如果指定了CWebApplication::catchAllRequest , 控制器將基於此屬性創建,而使用者指定的控制器ID將被忽略。這通常用於將應用程式設定為維護狀態並顯示靜態提示頁面。
2、如果在 CWebApplication::controllerMap 中找到了 ID,相應的控制器配置將被用於建立控制器實例。
3、如果 ID 為 'path/to/xyz'的格式,控制器類別的名稱將判斷為 XyzController,對應的類別檔案則為protected/controllers/path/to/XyzController.php。如果類別檔案不存在,將觸發一個 404CHttpException 異常。
在使用了模組的情況下,應用程式將檢查此 ID是否代表一個模組中的控制器。如果是的話,模組實例將首先創建,然後創建模組中的控制器實例。
3、動作(action)
動作 就是被定義為一個以 action單字作為前綴命名的方法。而更進階的方式是定義一個動作類別並讓控制器在收到請求時將其實例化。這使得動作可以重複使用,提高了可重複使用度。
1、定義一個動作類,基本格式如下:
class UpdateAction extends CAction
{
publicfunction run()
{
// place the action logic here
}
}
2、使用動作類別:為了讓控制器注意到這個動作,我們要用以下方式覆寫控制器類別的actions() 方法:
class PostController extends CController
{
publicfunction actions()
{
return array(
'edit'=>'appli.controllerspost. UpdateAction',//使用「應用程式資料夾/controllers/post/UpdateAction.php」檔案中的類別來處理edit動作
);
}
}
如上所示,我們使用了路徑別名「application.controllers. post.UpdateAction」指定動作類別檔案為「protected/controllers/post/UpdateAction.php」。
透過編寫基於類別的動作,我們可以將應用程式組織為模組的風格。例如,以下目錄結構可用於組織控制器相關程式碼:
protected/
controllers/
PostController.php
UserController.php
post/
CreateAction.php
ReadAction.php
UpdateAction.
CreateAction.php
ReadAction.php
UpdateAction. ListAction.php
ProfileAction.php
UpdateAction.php
四、過濾器(filter)
過濾器是一段程式碼,可被設定在控制器動作執行之前或之後執行。
一個動作可以有多個過濾器。如有多個過濾器,則按照它們出現在過濾器清單中的順序依序執行。過濾器可以阻止動作及後面其他過濾器的執行。
過濾器可以定義為一個控制器類別的方法。過濾器方法名稱必須以 filter 開頭。例如,現有的 filterAccessControl方法定義了一個名為 accessControl 的過濾器。過濾器方法必須為以下結構:
public function filterAccessControl($filterChain)
{
// 呼叫$filterChain->run() 以繼續後續過濾器與動作的執行。
}
$filterChain (過濾器鏈)是一個 CFilterChain 的實例,代表與所請求動作相關的過濾器清單。在過濾器方法中,我們可以呼叫$filterChain->run() 以繼續執行後續過濾器和動作。
如 動作 一樣,過濾器也可以是一個對象,它是 CFilter 或其子類別的實例。以下程式碼定義了一個新的過濾器類別:
class PerformanceFilter extends CFilter
{
protectedfunction preFilter($filterChain)
{
// 動作執行先前套用的邏輯
return true;這裡回傳false
}

protectedfunction postFilter($filterChain)
{
// 動作執行之後所應用的邏輯
}
}

要對動作套用過濾器,我們需要覆寫CController::H)。此方法應傳回一個過濾器配置數組。例如:
class PostController extends CController
{
......
publicfunction filters()
{
return array(
'postOnly + edit, create',//將postOnly過濾器應用於eded是基於方法的過濾器)
array( //使用了數組來配置過濾器
'application.filters.PerformanceFilter - edit, create',//將application.filters.PerformanceFilter過濾器應用於除了edit和create之外的所有動作(這是基於對象的過濾器)
'unit'=>'second ', //初始化過濾器物件中的unit屬性值為second
),
);
}
}
上述程式碼指定了兩個過濾器: postOnly 和PerformanceFilter。 postOnly過濾器是基於方法的(相應的過濾器方法已在 CController 中定義);而performanceFilter 過濾器是基於物件的。路徑別名application.filters.PerformanceFilter 指定過濾器類別檔案是protected/filters/PerformanceFilter。我們使用一個陣列來配置 PerformanceFilter,這樣它就可被用來初始化過濾器物件的屬性值。此處 PerformanceFilter 的 unit屬性值將會初始為 second。

使用加減號,我們可指定哪些動作應該或不應該套用過濾器。在上述程式碼中, postOnly 應只被應用於 edit 和 create動作,而 PerformanceFilter 應被應用於 除了 edit 和 create之外的動作。如果過濾器配置中沒有使用加減號,則此過濾器將被應用於所有動作。

五、模型(Model)
模型是 CModel或其子類別的實例。模型用於保持資料以及與其相關的業務邏輯。
模型是單獨的資料對象。它可以是資料表中的一行,或是一個使用者輸入的表單。
資料物件的每個欄位對應模型中的一個屬性。每個屬性都有一個標籤(label),並且可以透過一系列規則進行驗證。
Yii 實作了兩種類型的模型:表單模型和 Active Record。二者均繼承於相同的基底類別 CModel。
表單模型是 CFormModel 的實例。表單模型用於保持從使用者的輸入獲取的資料。這些數據經常被獲取,使用,然後丟棄。例如,在一個登入頁面中,我們可以使用表單模型來表示由最終使用者提供的使用者名稱和密碼資訊。
Active Record (AR) 是一種用於透過物件導向的風格抽象資料庫存取的設計模式。每個 AR 物件是一個CActiveRecord 或其子類別的實例。代表資料表中的一行。行中的欄位對應 AR物件中的屬性。

六、視圖
視圖是一個包含了主要的使用者互動元素的PHP腳本.
視圖有一個名字,當渲染(render)時,名字會被用於識別視圖腳本檔。視圖的名稱與其視圖腳本名稱是一樣的。例如:視圖edit 的名稱出自一個名為 edit.php 的腳本檔。要渲染時,需透過傳遞視圖的名稱呼叫CController::render()。這個方法將在「protected/views/控制器ID」目錄下尋找對應的檢視檔。
在視圖腳本內部,我們可以透過 $this來存取控制器實例。我們可以在視圖裡以「$this->屬性名」的方式取得控制器的任何屬性。
我們也可以用以下推送的方式傳遞資料到視圖裡:
$this->render('edit', array(
'var1'=>$value1,
'var2'=>$value2,
));
在以上的方式中, render() 方法將提取數組的第二個參數到變數裡。其產生的結果是,在視圖腳本裡,我們可以直接存取變數 $var1和 $var2。
1、佈局
佈局是一種用來修飾視圖的特殊的視圖檔案。它通常包含了使用者介面中通用的一部分視圖。例如:版面可以包含h​​eader和footer的部分,然後把內容嵌入其間。

......header here......

......footer here......

其中的$content 則儲存了內容視圖的渲染結果。
當使用render()時,佈局被隱式應用。視圖腳本 protected/views/layouts/main.php是預設的佈局檔案。這可以透過改變 CWebApplication::layout 進行自訂。要渲染一個不帶佈局的視圖,則需呼叫renderPartial() 。
2、小物件
小物件是 CWidget或其子類別的實例。它是一個主要用於表現數據的組件。小物件通常內嵌於一個視圖來產生一些複雜而獨立的使用者介面。例如,一個日曆小物件可用於渲染一個複雜的日曆介面。小物件使用戶介面更加可重複使用。
我們可以如下視圖腳本來使用一個小物件:
beginWidget('小物件類別的路徑別名'[,'包含屬性初始化值的陣列']);?>
...可能會由小物件取得的內容主體...
endWidget();?>

widget('小物件類別的路徑別名'[,'包含屬性初始化值的陣列']);?>
後者用於不需要任何body 內容的元件。
小物件可透過配置來客製化它的表現。這是透過呼叫 CBaseController::beginWidget 或CBaseController::widget 設定其初始化屬性值來完成的。
我們透過傳遞一個攜帶這些屬性初始化值的陣列來實現,該數組的鍵是屬性的名稱,而數組的值則是小物件屬性所對應的值。如下圖:
$this->widget('CMaskedTextField',array(
'mask'=>'99/99/9999'
));
?>
繼承CWidget 並覆寫其init()和run()方法,可以定義一個新的小物件:
class MyWidget extends CWidget
{
publicfunction init()
{
// 此方法會被CController::beginWidget() 呼叫
}
publicfunction runler::beginWidget() 呼叫
}
( {
// 此方法會被CController::endWidget() 呼叫
}
}
小物件可以像一個控制器一樣擁有它自己的視圖。
預設,小物件的視圖檔案位於包含了小物件類別檔案目錄的 views子目錄之下(protected/components/views)。這些視圖可以透過呼叫CWidget::render()渲染,這一點和控制器很相似。唯一不同的是,小物件的視圖沒有佈局檔支援。另外,小物件視圖中的$this指向小物件實例而不是控制器實例。

3、系統視圖
系統視圖的渲染通常用於展示 Yii 的錯誤和日誌資訊。
系統視圖的命名遵從了一些規則。例如像「errorXXX」這樣的名稱就是用來渲染展示錯誤號XXX的 CHttpException的視圖。例如,如果 CHttpException 拋出一個404錯誤,那麼 error404 就會被顯示。
在 framework/views 下, Yii 提供了一系列預設的系統視圖. 他們可以透過在protected/views/system 下建立同名視圖檔案進行自訂。

七、組件
Yii 應用建立於組件之上。元件是 CComponent或其子類別的實例。使用組件主要涉及存取它的屬性以及觸發或處理它的時間。基類 CComponent 指定如何定義屬性和事件。
1、元件屬性
元件的屬性就像是物件的公共成員變數。它是可讀寫的。
要定義一個元件屬性,我們只需在元件類別中定義一個公共成員變數。
更靈活的方式是定義其getter 和setter 方法,例如:
public functiongetTextWidth() // 取得textWidth 屬性
{
return$this->_textWidth;
}
public functionsetTextWidth($value) // 屬性設定{
$this->_textWidth=$value;
}
上述程式碼定義了一個可寫的屬性名稱為textWidth(名字是大小寫的不敏感)。當讀取屬性時,getTextWidth()就會被調用,其返回值則成為屬性值;相似的,當寫入屬性時,setTextWidth() 就會被調用。如果 setter方法沒有定義,則屬性將是唯讀的,如果對其寫入則會拋出一個異常。使用 getter 和 setter方法定義一個屬性有一個好處:即當讀取或寫入屬性時,可以執行額外的邏輯(例如,執行驗證,觸發事件)。
注意: 透過 getter/setter 定義的屬性和類別成員變數之間有一個細微的差異:屬性的名字是大小寫不敏感的, 而類別成員變數是大小寫敏感的。
2、元件事件
元件事件是一些特殊的屬性,它們使用一些稱作 事件句柄(eventhandlers)的方法作為其值。分配一個方法到一個事件將會引起方法在事件被喚起處自動被呼叫。因此,一個組件的行為可能會被一種在部件開發過程中不可預見的方式修改。
元件事件以 on 開頭的命名方式定義。和屬性透過 getter/setter方法來定義的命名方式一樣,事件的名稱是大小寫不敏感的。以下程式碼定義了一個onClicked 事件:
public function onClicked($event)
{
$this->raiseEvent('onClicked', $event);
}
這裡作為事件參數的$event 是CEvent 或其子類的實例。
我們可以分配一個方法到此事件,如下所示:
$component->onClicked=$callback;
這裡的 $callback 指向了一個有效的 PHP回調。它可以是一個全域函數也可以是類別中的一個方法。如果是後者,它必須以一個陣列的方式提供:array($object,'methodName')。
事件句柄的結構如下:
function 方法名稱($event)
{
......
}
這裡的 $event 即描述事件的參數(它來自 raiseEvent() 呼叫)。 $event 參數是 CEvent 或其子類別的實例。至少,它包含了關於誰觸發了此事件的資訊。
事件句柄也可以是一個PHP 5.3以後支援的匿名函數。例如:
$component->onClicked=function($event) {
......
}
如果我們現在調用onClicked(),onClicked 事件將被觸發(在onClicked()中),附屬的事件句柄將被自動調用。
一個事件可以綁定多個句柄。當事件觸發時,這些句柄將會被依照它們綁定到事件時的順序依序執行。如果句柄決定組織後續句柄被執行,它會設定$event->handled 為 true。
3、組件行為
元件已新增了對 mixin的支持,並可以綁定一個或多個行為。行為是一個對象,其方法可以被它所綁定的部件透過收集功能的方式來實現繼承(inherited),而不是專有化繼承(即普通的類別繼承)。一個部件可以以'多重繼承'的方式實現多個行為的綁定。
行為類別必須實作 IBehavior 介面。 大多數行為可以繼承自 CBehavior 。如果一個行為需要綁定到一個模型,它也可以從專為模型實現綁定特性的 CModelBehavior 或 CActiveRecordBehavior 繼承。
要使用一個行為,它必須先透過呼叫此行為的 attach() 方法綁定到一個元件。然後我們就可以透過元件呼叫此行為方法:
// $name 在元件中實現了唯一對行為的識別
$component->attachBehavior($name,$behavior);
// test() 是行為中的方法。
$component->test();
已綁定的行為可以像一個元件中的普通屬性一樣存取。例如,如果一個名為 tree的行為綁定到了一個元件,我們就可以透過以下程式碼來獲得指向此行為的參考。
$behavior=$component->tree;
// 等於下行程式碼:
// $behavior=$component->asa('tree');
行為是可以被臨時禁止的,此時它的方法就會在組件中失效。例如:
$component->disableBehavior($name);
// 下面的程式碼會拋出一個例外
$component->test();
$component->enableBehavior($name);
///就可以使用了
$component->test();
兩個同名行為綁定到同一個元件下是有可能的。在這種情況下,先綁定的行為則擁有優先權。
當和 events,一起使用時,行為會更加強大。當行為被綁定到元件時,行為裡的一些方法就可以綁定到元件的一些事件上了。這樣一來,行為就有機觀察或改變組件的常規執行流程。
一個行為的屬性也可以透過綁定到的元件來存取。這些屬性包含公共成員變數以及透過 getters 和/或 setters方式設定的屬性。例如, 若一個行為有一個 xyz 的屬性,此行為被綁定到元件 $a,然後我們可以使用表達式$a->xyz 存取此行為的屬性。

八、模組
模組是一個獨立的軟體單元,它包含 模型, 視圖,控制器和其他支援的組件。在許多方面上,模組看起來像一個應用。主要的差別就是模組不能單獨部署,它必須存在於一個應用程式裡。使用者可以像他們存取普通應用的控制器一樣存取模組中的控制器。
模組在某些場景裡很有用。對於大型應用來說,我們可能需要把它分成幾個模組,每個模組可以單獨維護和部署。一些通用的功能,例如使用者管理,評論管理,可以以模組的形式開發,這樣他們就可以輕鬆地在以後的專案中被重複使用。
1、建立模組
模組組織在一個目錄中,目錄名即為模組的唯一ID。模組目錄的結構跟 應用基礎目錄 很相似。下面列出了一個fourm的模組的典型的目錄結構:
forum/ 模組資料夾
ForumModule.php 模組類別檔案
components/ 包含可重複使用的使用者元件
views/ 包含小物件的視圖檔案
controllers/ 包含控制器類別檔案
DefaultController.php 預設的控制器類別檔案
extensions/ 包含第三方擴充功能
models/ 包含模型類別檔案
views/ 包含控制器視圖和佈局檔案
layouts/ 包含佈局檔案
default/ 包含DefaultController 的視圖檔
index.php 首頁視圖檔

模組必須有一個繼承自CWebModule 的模組類別。類別的名字透過表達式 ucfirst($id).'Module' 決定, 其中的$id 代表模組的 ID (或者說模組的目錄名字)。模組類別是儲存模組代碼間可共享資訊的中心位置。例如,我們可以使用CWebModule::params 儲存模組參數,使用 CWebModule::components分享模組級的應用元件。
2、使用模組
要使用模組,首先將模組目錄放在應用基礎目錄的modules資料夾中。然後在應用的modules屬性中聲明模組ID。例如,為了使用上面的forum模組,我們可以使用以下應用程式配置:
return array(
......
'modules'=>array('forum',...),
..... .
);
模組也可以在配置時帶有初始屬性值。做法和配置 應用元件 很類似。例如, forum 模組可以在其模組類別中有一個名為postPerPage 的屬性,它可以在應用程式配置中配置如下:
return array(
......
'modules'=>array(
'forum' =>array(
'postPerPage'=>20,
),
),
......
);
模組的實例可透過目前活動控制器的 module 屬性存取。在模組實例中,我們可以存取在模組級中共享的資訊。例如,為存取上面的postPerPage 訊息,我們可使用以下表達式:
$postPerPage=Yii::app()->controller->module->postPerPage;
// 如如$this引用的是控制器實例,則可以使用下行語句
//$postPerPage=$this->module->postPerPage;
模組中的控制器動作可以透過路由「模組ID/控制器ID/動作ID」或「模組ID/存放控制器類檔案的子目錄名稱/控制器ID/動作ID」存取。例如,假設上面的forum 模組有一個名為 PostController 的控制器,我們就可以透過路由 forum/post/create來存取此控制器中的 create 動作。此路由對應的 URL 即http://www.example.com/index.php?r=forum/post/create。
3、嵌套的模組
模組可以無限級嵌套。這就是說,一個模組可以包含另一個模組,而這另一個模組又可以包含其他模組。我們稱前者為 父模組,後者為子模組。子模組必須定義在其父模組的 modules 屬性中,就像我們前面在應用程式配置中定義模組一樣。
要存取子模組中的控制器動作,我們應使用路由 父模組ID/子模組ID/控制器ID/動作ID。

九、路徑別名
Yii中廣泛的使用了路徑別名。路徑別名關聯於一個目錄或檔案的路徑。它以點號語法指定,類似於廣泛使用的名字空間(namespace)格式:
RootAlias.path.to.target
其中的RootAlias 是某個現存目錄的別名,透過呼叫YiiBase::setPathOfAlias(),我們可以定義新的路徑別名。為方便起見,Yii 預先定義了以下幾個根別名:
system: 表示 Yii 框架目錄;
zii: 表示 Zii 庫 目錄;
application: 表示應用的 基礎目錄;
webroot: 表示 入口腳本 文件所在的目錄。
ext: 表示包含了所有第三方 擴充功能 的目錄。
額外的,如果應用使用了 模組, (Yii) 也為每個模組ID定義了根別名,指向對應模組的跟目錄。
透過使用 YiiBase::getPathOfAlias(), 別名可以被翻譯為其對應的路徑。
使用別名可以很方便的導入類別的定義。例如,如果我們想要包含 CController 類別的定義,我們可以呼叫如下程式碼
Yii::import('system.web.CController');
import方法跟 include 和 require不同,它更有效率。導入(import)的類別定義並不會真正被包含進來,直到它第一次被引用。多次導入同樣的名字空間也會比include_once 和 require_once 快得多。
我們也可以使用以下語法匯入整個目錄,這樣此目錄下的類別檔案就會在需要時自動包含。
Yii::import('system.web.*');
除 import 外, 別名還在其他許多地方指向類別。例如,路徑別名可以傳遞給 Yii::createComponent()以建立對應類別的實例。即使類別文件在之前從未被包含。
不要將路徑別名和名字空間混淆了,名字空間是指對一些類別名稱的一個邏輯組合,這樣它們就可以相互區分開,即使有相同的名字。而路徑別名是用來指向一個類別檔案或目錄。路徑別名與名字空間並不衝突。

 以上就是轉載請註明來源:Yii快速入門 (二)的內容,更多相關內容請關注PHP中文網(www.php.cn)!



陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn