# 快速入門(十八):多層控制器
ThinkPHP支持多層業務控制器的支持,給中大型應用提供了方便。
## 定義多層控制器
我們通常所了解的控制器其實是Controller控制器類,而且大多數也是繼承了核心的Think\Controller類,由于該類控制器是通過URL訪問請求后調用的,因此也稱之為訪問控制器,事實上,ThinkPHP可以支持更多的控制器分層,多層控制器的定義完全取決于項目的需求,例如我們可以分為業務控制器和事件控制器:
> Home\Controller\UserController //用于用戶的業務邏輯控制和調度
> Home\Event\UserEvent //用于用戶的事件響應操作
~~~
├─Controller 訪問控制器
│ ├─UserController.class.php
│ ...
├─Event 事件控制器
│ ├─UserEvent.class.php
│ ...
~~~
一個標準的訪問控制器定義如下:
~~~
namespace Home\Controller;
class UserController extend Think\Controller {
// 默認操作方法
public function index(){
//...
}
// 用戶注冊操作方法
public function register(){
//...
}
}
~~~
> 注:訪問控制器的名稱并非一定是Controller,而是通過DEFAULT_C_LAYER設置的,默認設置是Controller。
訪問控制器負責外部的交互響應,通過URL請求調用,例如:
~~~
http://serverName/Home/User/index
http://serverName/Home/User/register
~~~
而事件控制器負責內部的事件響應,并且只能在內部調用,所以是和外部隔離的。
> 確切的說,所有訪問控制器之外的分層控制器都只能內部實例化調用。
~~~
namespace Home\Event;
class UserEvent {
// 用戶登錄事件
public function login(){
echo 'login event';
}
// 用戶登出事件
public function logout(){
echo 'logout event';
}
}
~~~
> 如果是定義其他的控制器層,則不一定必須要繼承系統的Controller類或其子類,通常需要輸出模版的時候才需要繼承Controller類。
## 調用多層控制器
訪問控制器是通過URL請求調用,訪問控制器之外的分層控制器都只能內部調用,調用多層控制器可以通過兩種方式:
### 直接實例化
~~~
namespace Home\Controller;
class UserController extend Think\Controller {
// 默認操作方法
public function index(){
// 觸發事件
$event = new \Home\Event\UserEvent();
$event->login();
}
}
~~~
### A函數實例化
~~~
namespace Home\Controller;
class UserController extend Think\Controller {
// 默認操作方法
public function index(){
// 觸發事件
$event = A('User','Event');
$event->login();
// 或者直接使用
// R('User/login','','Event');
}
}
~~~
## Widget實例
Widget類的實現可以作為分層控制器的另外一個典型實例。
舉個例子,我們在頁面中實現一個分類菜單的Widget,首先我們要定義一個Widget控制器層 MenuWidget,如下:
~~~
namespace Home\Widget;
class MenuWidget extends Think\Controller {
public function index(){
echo 'menuWidget';
}
}
~~~
類文件位于 `Home/Widget/MenuWidget.class.php`。
然后,我們在需要顯示分類菜單的模版中通過W方法調用這個Widget。
~~~
{~W('Menu/index')}
~~~
執行后的輸出結果是: menuWidget
如果需要在調用Widget的時候傳入參數,可以這樣定義:
~~~
namespace Home\Widget;
class MenuWidget extends Think\Controller {
public function index($id,$name){
echo $id.':'.$name;
}
}
~~~
在需要顯示分類菜單的模版中添加如下的Widget調用代碼如下:
~~~
{~W('Menu/index',array(5,'thinkphp'))}
~~~
則會輸出 5:thinkphp
來一個復雜一點的例子:
~~~
namespace Home\Widget;
class MenuWidget extends Think\Controller {
public function index(){
$menu = M('Cate')->getField('id,title');
$this->assign('menu',$menu);
$this->display('Widget/menu');
}
}
~~~
CateWiget類渲染了一個模版文件 `Home/View/Widget/menu.html`,
在menu.html模版文件中的用法:
~~~
<foreach name="menu" item="title">
{$key}:{$title}
</foreach>
~~~