控制器

控制器是什麼?

控制器是可透過 URL 到達,並打理處理請求的類別。 控制器呼叫模型和其他類別來取回資訊。最後, 它將傳遞所有東西到檢視來輸出。如果像 www.yoursite.com/example/index 的 URL 被請求, 第一分段 ("example") 將會是被呼叫的控制器, 而第二分段 ("index") 將會是控制器被呼叫的方法。

建立控制器

在 FuelPHP,控制器被置於 fuel/app/classes/controller 目錄, 並以 "Controller_" 前綴。(選擇性)它們應該為了完整的功能集擴充 Controller 類別。 下面是一個控制器 "example" 的範例:

class Controller_Example extends Controller
{

	public function action_index()
	{
		$data['css'] = Asset::css(array('reset.css','960.css','main.css'));
		return Response::forge(View::forge('welcome/index'));
	}
}

可以透過 URL 被請求的方法有 "action_" 前綴。This means 這意味著你可能使用的名稱(例如:方法 "list" 不被允許,"action_list" 就沒問題) 不會被 PHP 的結構限制。但這也意味著, 你可以讓你的控制器公開方法能從其他類別被使用但不能路由。

HTTP 方法前綴動作。

路由到 HTTP 方法前綴的動作是可能的,這裡有個範例:

class Controller_Example extends Controller
{
	public function get_index()
	{
		// 當 HTTP 方法是 GET 時將被呼叫。
	}

	public function post_index()
	{
		// 當 HTTP 方法是 POST 時將被呼叫。
	}
}

在子目錄的控制器

你也可以將控制器放進子目錄中,像 fuel/app/classes/controller/subdir/test.php。在該情況, 控制器必須在類別名稱中包含目錄名稱,像這樣:Controller_Subdir_Test

支援無限巢狀的子目錄,所以 fuel/app/classes/controller/subdir1/subdir2/subdir3/test.php 會有一個 Controller_Subdir1_Subdir2_Subdir3_Test 的類別名稱。

控制器的命名空間方式

參閱 命名空間 頁面來了解你能如何給你控制器的命名空間

從 URL 使用更多參數

現在,我們在我們的 Controller_Example 也有以下方法:

public function action_name_to_upper($name_1, $name_2)
{
	$data['name_1'] = strtoupper($name_1);
	$data['name_2'] = strtoupper($name_2);
	return View::forge('test/name_to_upper', $data);
}

如果我們使用 www.yoursite.com/example/name_to_upper/fuel/php 呼叫此方法, 它將回傳 test/name_to_upper 檢視。"FUEL" 以及 "PHP" 將被傳遞做為 $data 陣列中的 $name_1$name_2 的值。

回傳結果

理想情況下,一個控制器動作必須回傳一個 Response 物件。你可以選擇性的指定特別的 HTTP 表頭, 或一個自訂的 HTTP 狀態碼("200 OK" 以外的)。如果你沒回傳一個 Response 物件,預設 after() 方法會為你包裹動作的回傳值在一個 Response 物件中。

如果你的控制器擴充了基礎控制器,你的動作也可以回傳任何可被轉換為字串的任何值, 例如像一個 View 物件。基礎控制器的 after() 方法將為你把它轉換為一個 Response 物件。

如果你的控制器不擴充基礎控制器,而且你想要使用此功能, 你的控制器必須包含它自己的 after() 方法,該方法將接受動作回傳的值, 並把它包成一個必須回傳的 Reponse 物件。

特殊控制器方法

不要覆寫類別建構式 __construct(),使用 before() 替代。 除非你已經先從 Core 研究基礎控制器, 並了解它應該如何被擴充而不破壞 Fuel。

action_index()

這個方法將在呼叫控制器如果沒帶第二參數的時候被呼叫。 在以上範例 www.yoursite.com/example/index 將與 www.yoursite.com/example 一樣。

before()

before() 方法被用來當作一個通用方法的前預備方法,來執行在每個控制器方法呼叫時所須的程式碼。 這個方法將在來自 URL 的方法在你控制器呼叫之前被執行。 它將不會被呼叫如果該方法不存在。 你不應該使用這方法來作路由決策,如果需要的話,使用 router 方法替代。

after($response)

這個方法將在來自 URL 的方法成功呼叫之後被執行, 這將不會被呼叫如果該方法不存在。$response 參數是必要的。 after() 方法必須回傳一個 Response 物件。

如果 after() 方法必須建構一個 Response 物件,它可以使用控制器的 response_status 特性來設定回傳的 HTTP 狀態碼。 預設情況下,此特性包含 "200" (OK)。

router($method, $params)

這個方法將接管內部的控制器路由。一旦控制器被載入, router() 方法將被呼叫並且使用被傳入的 $method, 代替預設的方法。它也會傳入 $params,以一個陣列, 到該 $method。before() 和 after() 方法仍會如預期運作。

擴充其他控制器

幸好有自動載入器,你可以擴充其他控制器,除了該類別所定義的名稱, 不用寫更多:

class Controller_Example extends Controller_Welcome
{

	// 你的方法

}

這剛開始聽起來可能很奇怪, 但擴充控制器能讓你分享方法並很輕鬆地建立基礎控制器。

建立基礎控制器

基礎控制器是一個共享控制器,像 Controller_PublicController_Admin 是用來分享控制器群組之間的邏輯。 例如,Controller_Admin 控制器可能包含你的 login/logout 動作也許還有一個儀表板,但它也可能包含一個檢查使用者是否登入做為一個管理者的 before() 方法。 那麼所有在你的管理控制台中其他的控制器將擴充它並且自動被保護。

class Controller_Admin extends Controller
{

	public function before()
	{
		// 檢查管理者
	}

	// 你的方法

	public function action_index()
	{
		// 載入儀表板
	}

	public function action_login()
	{
		// 登入使用者
	}
}

該程式碼將會在 fuel/app/classes/controller/admin.php, 並且你所有其他的控制器應該在 fuel/app/classes/controller/admin/,像這樣:

class Controller_Admin_User extends Controller_Admin
{

	public function action_index()
	{
		// 以使用者 index 列表覆蓋儀表板
	}

	public function action_edit($id)
	{
		// 編輯使用者
	}
}