組件
組件是在多個控制器中共享的邏輯包。如果你發現自己想要在控制器間複製粘貼某些東西時,你就應該考慮將一些功能包裝在一個組件中了。
CakePHP 還配備了一套漂亮的、對你有用的核心組件:
- Security(安全)
- Sessions(會話)
- Access control lists(訪問控制列表)
- Emails(電子郵件)
- Cookies
- Authentication(權限校驗)
- Request handling(請求處理)
- Pagination(分頁)
這些組件的詳細信息都在各自的章節中。 現在,我們將向你展示如何建立你自己的組件。 創建組件可以保持控制器代碼整潔,並且允許你在多個項目中重用代碼。
配置組件
一些核心組件需要配置。需要配置的組件有 授權、 Cookie 和 電子郵件組件 等。 對於一般的組件,通常在$components 數組或者控制器的 beforeFilter 方法中進行配置:
class PostsController extends AppController {
public $components = array(
'Auth' => array(
'authorize' => array('controller'),
'loginAction' => array('controller' => 'users', 'action' => 'login')
),
'Cookie' => array('name' => 'CookieMonster')
);
這是使用 $components 數組配置組件的例子。所有的核心組件都允許使用這種方式進行配置。此外,你也可以在控制器的 beforeFilter() 方法中配置組件。 這種方式通常用在你需要將一個函數的結果賦與一個組件屬性的情況下。上面的例子還可以表示成:
public function beforeFilter() {
$this->Auth->authorize = array('controller');
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Cookie->name = 'CookieMonster';
}
然而,也有這種可能:一個組件的特定配置選項要在控制器的 beforeFilter() 運行前設置。 最後,一些組件允許在$components 數組中設置配置選項:
public $components = array(
'DebugKit.Toolbar' => array('panels' => array('history', 'session'))
);
通過查閱相關文檔可以確定每個組件都提供哪些配置選項。
className 是一個公用的設置選項,你可以藉此給組件起個別名。當你想要用自定義的實現替換 $this->Auth 或者其它公用組件時,這個選項非常有用。
// app/Controller/PostsController.php
class PostsController extends AppController {
public $components = array(
'Auth' => array(
'className' => 'MyAuth'
)
);
}
// app/Controller/Component/MyAuthComponent.php
App::uses('AuthComponent', 'Controller/Component');
class MyAuthComponent extends AuthComponent {
// Add your code to override the core AuthComponent
}
上例的控制器中 $this->Auth 的別名爲 MyAuthComponent 。
註解
在任何用到有別名的組件時,都要使用別名,包括在其它組件內引用。
使用組件
一旦你已經在控制器中包含了一些組件,用起來是非常簡單的。在控制器中每個元件都以屬性的方式使用。如果你已經在控制器中加載了 SessionComponent 和 the CookieComponent ,你就可以像下面這樣訪問它們:
class PostsController extends AppController {
public $components = array('Session', 'Cookie');
public function delete() {
if ($this->Post->delete($this->request->data('Post.id')) {
$this->Session->setFlash('Post deleted.');
$this->redirect(array('action' => 'index'));
}
}
註解
由於以屬性身份加入到控制器中的模型和組件共享相同的 ‘命名空間’,你需要確保不給組件和模型相同的命名。
運行中加載組件
你也許不需要所有的組件在每個控制器方法中都可用。 這種情況下,你可以在運行時使用 Component Collection 加載一個組件。 在控制器內部,你可以按如下方式進行:
$this->OneTimer = $this->Components->load('OneTimer');
$this->OneTimer->getTime();
組件回調
組件也提供一些請求生命週期回調,以允許它們延伸請求週期。 有關組件提供的回調的更詳細信息,請參閱 組件 API。
創建組件
假定我們的線上應用程序需要在其不同部分運行一個複雜的數學操作。我們可以創建一個組件包裝這個用在幾個不同控制器中的共享邏輯。
第一步是新的組件文件和類。創建的文件爲 /app/Controller/Component/MathComponent.php。其基本結構如下:
App::uses('Component', 'Controller');
class MathComponent extends Component {
public function doComplexOperation($amount1, $amount2) {
return $amount1 + $amount2;
}
}
註解
所有的組件必須繼承 Component。否則就會引發一個異常。
在控制器中包含組件
一旦組件完成,就可以通過將組件名稱放進控制器的 $components 數組的方式在應用程序控制器中使用它了(參見 “組件” 部分)。控制器將自動提供一個用組件命名的新屬性,通過這個屬性我們可以訪問組件的實例:
/* 生成一個新的組件變量 $this->Math
和一個標準的 $this->Session */
public $components = array('Math', 'Session');
定義在 AppController 中的組件將與其它控制器中的組件合併。因此不需要二次定義相同的組件。
在控制器中包含組件時,你還可以定義一組參數傳遞給組件的構造函數。這些參數隨後將被組件處理:
public $components = array(
'Math' => array(
'precision' => 2,
'randomGenerator' => 'srand'
),
'Session', 'Auth'
);
這段代碼將包含了 precision 和 randomGenerator 的數組作爲第二個參數傳遞給了 MathComponent::__construct()。根據約定,任何在組件上被傳遞的公共屬性也將擁有基於此設置的值。
在組件中使用其它組件
有時一個組件還需要使用其它組件。在這種情況下,你可以使用與在控制器中包含組件相同的方式,在一個組件中包含另一個組件 - 使用 ``$components` 變量:
// app/Controller/Component/CustomComponent.php
App::uses('Component', 'Controller');
class CustomComponent extends Component {
// the other component your component uses
public $components = array('Existing');
public function initialize(Controller $controller) {
$this->Existing->foo();
}
public function bar() {
// ...
}
}
// app/Controller/Component/ExistingComponent.php
App::uses('Component', 'Controller');
class ExistingComponent extends Component {
public function foo() {
// ...
}
}
組件 API
- class Component
-
組件基類爲通過 ComponentCollection 延遲加載其它組件以及處理公共設置提供了幾個方法。它還爲所有的組件回調提供了屬性。
- Component::__construct(ComponentCollection $collection, $settings = array())
-
組件基類構造函數。作爲公共屬性的所有 $settings 也將有與 settings 內設置的值匹配的值。
回調
- Component::initialize(Controller $controller)
-
initialize 方法在控制器的 beforeFilter 方法之前被調用。
- Component::startup(Controller $controller)
-
startup 方法在控制器的 beforeFilter 之後但在控制器執行當前動作處理之前被調用。
- Component::beforeRender(Controller $controller)
-
beforeRender 方法在執行請求動作邏輯之後,控制器渲染視圖和佈局之前被調用。
- Component::shutdown(Controller $controller)
-
shutdown 方法在輸出傳送給瀏覽器之前被調用。
- Component::beforeRedirect(Controller $controller, $url, $status=null, $exit=true)
-
beforeRedirect 方法在控制器跳轉方法被調用之後,所有其它方法調用之前被調用。如果這個方法返回假,將不再繼續完成請求的轉向。$url、$status 和 $exit 變量對於控制器方法的意義相同。你還能返回一個字符串,作爲轉向的 url,或者返回帶有鍵 ‘url’ 的關聯數組,此數組的 ‘status’ 和 ‘exit’ 元素是可選的。