控制器

控制器是什么?

控制器是可透過 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)
	{
		// 编輯使用者
	}
}