对于actions来说,过滤器可以使controllers运行共享的pre并且布置处理代码。在将要执行的action之前,这些过滤器可以用来作authentication,caching,或者auditing 。或者在action执行之后,用来定位或输出压缩。
过滤器访问request,response,和在链中的其他过滤器或者action(in the case of after filters)中的所有实例化的变量。另外,使前处理beforeFilter能够停止处理过程,
在执行将要执行的action时,通过执行返回错误值或者执行redirect或者render。
这个对于像authentication等特别有用,如果proper credentials没有在队列中,你也不用关心允许那个action运行。
Controller遗传了分级结构,共享了下面的filters,但是子类也可以添加新的filters,并不会影响父类。For example:
class BankController extends AkActionController { function __construct() { $this->beforeFilter('_audit'); } function _audit(&$controller) { // record the action and parameters in an audit log } } class VaultController extends BankController { function __construct() { $this->beforeFilter('_verifyCredentials'); } function _verifyCredentials(&$controller) { // make sure the user is allowed into the vault } }
现在在BankController中的任何一个actions执行之前,将会调用audit method。在VaultController中, 首先audit method被调用, is called,然后是_verifyCredentials method。如果_audit method返回值为false,那么 _verifyCredentials和intended action将永远不会被执行。
filter能采用三种类型的一个: method reference, external class,或者inline method。第一个是最常见的,通过引用一个方法使之工作,在controller的遗传等级中通过使用方法的名字。 . 在上面的例子中,BankController和VaultController都使用了这个类型。
使用外部类可以更容易的重用一般的filters,例如output compression。外部的filter classes在任何类上,通过一个静态的filter方法来执行。然后从这个类去filter method。 Example:
class OutputCompressionFilter { function filter(&$controller) { $controller->response->body = compress($controller->response->body); } } class NewspaperController extends AkActionController { function __construct() { $this->afterFilter(new OutputCompressionFilter()); } }
这个filter method通过之后,controller的实例并且能够访问controller的各个方面,并且能够操作他们。
使用beforeFilter和afterFilter在已存在的链中添加指定的filters。一般来说这不错,但是有些时候你必须注意执行filters的顺序。当那个情形时,你可以使用 prependBeforeFilter和prependAfterFilter。这些Filters会被追加到各自的链的开始,在rest之前执行他们。 For example:
class ShoppingController extends AkActionController { function __construct() { $this->beforeFilter('verifyOpenShop'); } } class CheckoutController extends AkActionController { function __construct() { $this->prependBeforeFilter('ensureItemsInCart', 'ensureItemsInStock'); } }
CheckoutController的filter链现在是'ensureItemsInCart, ensureItemsInStock,
verifyOpenShop''。所以任何一个filters返回值为false,如果商店没有开门,我们永远不能去四周转转。
你也许通过了每个类型复合的filter参数。
除了个别的before和after filters的之外,对于指定的对象来说也应该能够处理before and after调用。当你需要before and after之间保持状态的有效性的时候,这是特别有用的。 such as the example of a benchmark filter below:
class WeblogController extends AkActionController { function __construct() { $this->aroundFilter(new BenchmarkingFilter()); } // Before this action is performed, BenchmarkingFilter->before($controller) is executed function index() { } // After this action has been performed, BenchmarkingFilter->after($controller) is executed } class BenchmarkingFilter { function before(&$controller) { start_timer(); } function after(&$controller) { stop_timer(); report_result(); } }
有些时候在父类中指定一个filter chain是非常方便的,他将会为大多数的子类保持真值, 但是不是所有的都需要。子类在意外情况下表现的很好,他们可以指定他们喜欢的filters来释放。 Examples
class ApplicationController extends AkActionController { function __construct() { $this->beforeFilter('authenticate'); } } class WeblogController extends ApplicationController { // will run the authenticate filter } class SignupController extends AkActionController { function __construct() { $this->skipBeforeFilter('authenticate'); } // will not run the authenticate filter }
Filters可以被限制在特定的actions中运行。在执行filter时可以通过监听被除外的actions和被包括的actions来清楚的说明。 可用的conditions是only or except, 他们两个both可以接受参考方法的任何数。 For example:
class Journal extends AkActionController { function __construct() { // only require authentication if the current action is edit or delete $this->beforeFilter(array('_authorize'=>array('only'=>array('edit','delete'))); } function _authorize(&$controller) { // redirect to login unless authenticated } }