From 60b38a1a33d8c29d48e4bfb23183dbe0f10e4e6d Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 21 Jun 2014 21:04:30 -0400 Subject: [PATCH] Finished filter section [skip ci] --- docs/guide/concept-behaviors.md | 16 +- docs/guide/concept-events.md | 12 ++ docs/guide/structure-controllers.md | 11 +- docs/guide/structure-filters.md | 288 ++++++++++++++++++++++++--- docs/internals/translation-status.md | 2 +- framework/filters/HttpCache.php | 6 +- framework/filters/PageCache.php | 7 +- 7 files changed, 305 insertions(+), 37 deletions(-) diff --git a/docs/guide/concept-behaviors.md b/docs/guide/concept-behaviors.md index 69e7270d97..2f1c9a5dde 100644 --- a/docs/guide/concept-behaviors.md +++ b/docs/guide/concept-behaviors.md @@ -136,8 +136,20 @@ $component->attachBehaviors([ ]); ``` -You may also attach behaviors through [configurations](concept-configurations.md). For more details, please -refer to the [Configurations](concept-configurations.md#configuration-format) section. +You may also attach behaviors through [configurations](concept-configurations.md) like the following. For more details, +please refer to the [Configurations](concept-configurations.md#configuration-format) section. + +```php +[ + 'as myBehavior2' => MyBehavior::className(), + + 'as myBehavior3' => [ + 'class' => MyBehavior::className(), + 'prop1' => 'value1', + 'prop2' => 'value2', + ], +] +``` Detaching Behaviors diff --git a/docs/guide/concept-events.md b/docs/guide/concept-events.md index 674b0c2364..26b4c88250 100644 --- a/docs/guide/concept-events.md +++ b/docs/guide/concept-events.md @@ -162,6 +162,18 @@ $foo->on(Foo::EVENT_HELLO, function ($event) { }, $data, false); ``` +Besides calling the `on()` method, you may also attach event handlers in [configurations](concept-configurations.md) +like the following. For more details, please refer to the [Configurations](concept-configurations.md#configuration-format) +section. + +```php +[ + 'on hello' => function ($event) { + echo 'hello event is triggered'; + } +] +``` + Detaching Event Handlers ------------------------ diff --git a/docs/guide/structure-controllers.md b/docs/guide/structure-controllers.md index 77061b3101..5c2a44624f 100644 --- a/docs/guide/structure-controllers.md +++ b/docs/guide/structure-controllers.md @@ -2,10 +2,13 @@ Controllers =========== Controllers are part of the [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) architecture. -They are objects responsible for processing requests and generating responses. In particular, after -taking over the control from [applications](structure-applications.md), controllers will analyze incoming request data, -pass them to [models](structure-models.md), inject model results into [views](structure-views.md), -and finally generate outgoing responses. +They are objects of classes extending from [[yii\base\Controller]] and are responsible for processing requests and +generating responses. In particular, after taking over the control from [applications](structure-applications.md), +controllers will analyze incoming request data, pass them to [models](structure-models.md), inject model results +into [views](structure-views.md), and finally generate outgoing responses. + + +## Actions Controllers are composed by *actions* which are the most basic units that end users can address and request for execution. A controller can have one or multiple actions. diff --git a/docs/guide/structure-filters.md b/docs/guide/structure-filters.md index e5bbaa6381..8721046a22 100644 --- a/docs/guide/structure-filters.md +++ b/docs/guide/structure-filters.md @@ -1,22 +1,215 @@ Filters ======= -> Note: This section is under development. +Filters are objects that run before and/or after [controller actions](structure-controllers.md#actions). For example, +an access control filter may run before actions to ensure that they are allowed to be accessed by particular end users; +a content compression filter may run after actions to compress the response content before sending them out to end users. -You may apply some action filters to controller actions to accomplish tasks such as determining -who can access the current action, decorating the result of the action, etc. +A filter may consist of a pre-filter (filtering logic applied *before* actions) and/or a post-filter (logic applied +*after* actions). -An action filter is an instance of a class extending [[yii\base\ActionFilter]]. -To use an action filter, attach it as a behavior to a controller or a module. The following -example shows how to enable HTTP caching for the `index` action: +## Using Filters + +Filters are essentially a special kind of [behaviors](concept-behaviors.md). Therefore, using filters is the same +as [using behaviors](concept-behaviors.md#attaching-behaviors). You can declare filters in a controller class +by overriding its [[yii\base\Controller::behaviors()|behaviors()]] method like the following: ```php public function behaviors() { return [ - 'httpCache' => [ - 'class' => \yii\filters\HttpCache::className(), + [ + 'class' => 'yii\filters\HttpCache', + 'only' => ['index', 'view'], + 'lastModified' => function ($action, $params) { + $q = new \yii\db\Query(); + return $q->from('user')->max('updated_at'); + }, + ], + ]; +} +``` + +By default, filters declared in a controller class will be applied to *all* actions in that controller. You can, +however, explicitly specify which actions the filter should be applied to by configuring the +[[yii\base\ActionFilter::only|only]] property. In the above example, the `HttpCache` filter only applies to the +`index` and `view` actions. You can also configure the [[yii\base\ActionFilter::except|except]] property to blacklist +some actions from being filtered. + +Besides controllers, you can also declare filters in a [module](structure-modules.md) or [application](structure-applications.md). +When you do so, the filters will be applied to *all* controller actions belonging to that module or application, +unless you configure the filters' [[yii\base\ActionFilter::only|only]] and [[yii\base\ActionFilter::except|except]] +properties like described above. + +> Note: When declaring filters in modules or applications, you should use [routes](structure-controllers.md#routes) + instead of action IDs in the [[yii\base\ActionFilter::only|only]] and [[yii\base\ActionFilter::except|except]] properties. + This is because action IDs alone cannot fully specify actions within the scope of a module or application. + +When multiple filters are configured for a single action, they are applied according to the rules described below, + +* Pre-filtering + - Apply filters declared in the application in the order they are listed in `behaviors()`. + - Apply filters declared in the module in the order they are listed in `behaviors()`. + - Apply filters declared in the controller in the order they are listed in `behaviors()`. + - If any of the filters cancel the action execution, the filters (both pre-filters and post-filters) after it will + not be applied. +* Running the action if it passes the pre-filtering. +* Post-filtering + - Apply filters declared in the controller in the reverse order they are listed in `behaviors()`. + - Apply filters declared in the module in the reverse order they are listed in `behaviors()`. + - Apply filters declared in the application in the reverse order they are listed in `behaviors()`. + + +## Creating Filters + +To create a new action filter, extend from [[yii\base\ActionFilter]] and override the +[[yii\base\ActionFilter::beforeAction()|beforeAction()]] and/or [[yii\base\ActionFilter::afterAction()|afterAction()]] +methods. The former will be executed before an action runs while the latter after an action runs. +The return value of [[yii\base\ActionFilter::beforeAction()|beforeAction()]] determines whether an action should +be executed or not. If it is false, the filters after this one will be skipped and the action will not be executed. + +The following example shows a filter that logs the action execution time: + +```php +namespace app\components; + +use Yii; +use yii\base\ActionFilter; + +class ActionTimeFilter extends ActionFilter +{ + private $_startTime; + + public function beforeAction($action) + { + $this->_startTime = microtime(true); + return parent::beforeAction($action); + } + + public function afterAction($action, $result) + { + $time = microtime(true) - $this->_startTime; + Yii::trace("Action '{$action->uniqueId}' spent $time second."); + return parent::afterAction($action, $result); + } +} +``` + + +## Core Filters + +Yii provides a set of commonly used filters, found primarily under the `yii\filters` namespace. In the following, +we will briefly introduce these filters. + + +### [[yii\filters\AccessControl|AccessControl]] + +AccessControl provides simple access control based on a set of [[yii\filters\AccessControl::rules|rules]]. +In particular, before an action is executed, AccessControl will examine the listed rules and find the first one +that matches the current context variables (such as user IP address, user login status, etc.) The matching +rule will dictate whether to allow or deny the execution of the requested action. If no rule matches, the access +will be denied. + +The following example shows how to allow authenticated users to access the `create` and `update` actions +while denying all other users from accessing these two actions. + +```php +use yii\filters\AccessControl; + +public function behaviors() +{ + return [ + 'access' => [ + 'class' => AccessControl::className(), + 'only' => ['create', 'update'], + 'rules' => [ + // allow authenticated users + [ + 'allow' => true, + 'roles' => ['@'], + ], + // everything else is denied by default + ], + ], + ]; +} +``` + +For more details about access control in general, please refer to the [Authorization](security-authorization.md) section. + + +### [[yii\filters\ContentNegotiator|ContentNegotiator]] + +ContentNegotiator supports response format negotiation and application language negotiation. It will try to +determine the response format and/or language by examining `GET` parameters and `Accept` HTTP header. + +In the following example, ContentNegotiator is configured to support JSON and XML response formats, and +English (United States) and German languages. + +```php +use yii\filters\ContentNegotiator; +use yii\web\Response; + +public function behaviors() +{ + return [ + [ + 'class' => ContentNegotiator::className(), + 'formats' => [ + 'application/json' => Response::FORMAT_JSON, + 'application/xml' => Response::FORMAT_XML, + ], + 'languages' => [ + 'en-US', + 'de', + ], + ], + ]; +} +``` + +Response formats and languages often need to be determined much earlier during +the [application lifecycle](structure-applications.md#application-lifecycle). For this reason, ContentNegotiator +is designed in a way such that it can also be used as a [bootstrap component](structure-applications.md#bootstrap) +besides filter. For example, you may configure it in the [application configuration](structure-applications.md#application-configurations) +like the following: + +```php +use yii\filters\ContentNegotiator; +use yii\web\Response; + +[ + 'bootstrap' => [ + [ + 'class' => ContentNegotiator::className(), + 'formats' => [ + 'application/json' => Response::FORMAT_JSON, + 'application/xml' => Response::FORMAT_XML, + ], + 'languages' => [ + 'en-US', + 'de', + ], + ], + ], +]; +``` + + +### [[yii\filters\HttpCache|HttpCache]] + +HttpCache implements client-side caching by utilizing the `Last-Modified` and `Etag` HTTP headers. +For example, + +```php +use yii\filters\HttpCache; + +public function behaviors() +{ + return [ + [ + 'class' => HttpCache::className(), 'only' => ['index'], 'lastModified' => function ($action, $params) { $q = new \yii\db\Query(); @@ -27,21 +220,70 @@ public function behaviors() } ``` -You may use multiple action filters at the same time. These filters will be applied in the -order they are declared in `behaviors()`. If any of the filter cancels the action execution, -the filters after it will be skipped. +Please refer to the [HTTP Caching](caching-http.md) section for more details about using HttpCache. -When you attach a filter to a controller, it can be applied to all actions of that controller; -If you attach a filter to a module (or application), it can be applied to the actions of any controller -within that module (or application). -To create a new action filter, extend from [[yii\base\ActionFilter]] and override the -[[yii\base\ActionFilter::beforeAction()|beforeAction()]] and [[yii\base\ActionFilter::afterAction()|afterAction()]] -methods. The former will be executed before an action runs while the latter after an action runs. -The return value of [[yii\base\ActionFilter::beforeAction()|beforeAction()]] determines whether -an action should be executed or not. If `beforeAction()` of a filter returns false, the filters after this one -will be skipped and the action will not be executed. +### [[yii\filters\PageCache|PageCache]] -The [authorization](authorization.md) section of this guide shows how to use the [[yii\filters\AccessControl]] filter, -and the [caching](caching.md) section gives more details about the [[yii\filters\PageCache]] and [[yii\filters\HttpCache]] filters. -These built-in filters are also good references when you learn to create your own filters. +PageCache implements server-side caching of whole pages. In the following example, PageCache is applied +to the `index` action to cache the whole page for maximum 60 seconds or until the count of entries in the `post` +table changes. It also stores different versions of the page depending on the chosen application language. + +```php +use yii\filters\PageCache; +use yii\caching\DbDependency; + +public function behaviors() +{ + return [ + 'pageCache' => [ + 'class' => PageCache::className(), + 'only' => ['index'], + 'duration' => 60, + 'dependency' => [ + 'class' => DbDependency::className(), + 'sql' => 'SELECT COUNT(*) FROM post', + ], + 'variations' => [ + \Yii::$app->language, + ] + ], + ]; +} +``` + +Please refer to the [Page Caching](caching-page.md) section for more details about using PageCache. + + +### [[yii\filters\RateLimiter|RateLimiter]] + +RateLimiter implements a rate limiting algorithm based on the [leaky bucket algorithm](http://en.wikipedia.org/wiki/Leaky_bucket). +It is primarily used in implementing RESTful APIs. Please refer to the [Rate Limiting](rest-rate-limiting.md) section +for details about using this filter. + + +### [[yii\filters\VerbFilter|VerbFilter]] + +VerbFilter checks if the HTTP request methods are allowed by the requested actions. If not allowed, it will +throw an HTTP 405 exception. In the following example, VerbFilter is declared to specify a typical set of allowed +request methods for CRUD actions. + +```php +use yii\filters\VerbFilter; + +public function behaviors() +{ + return [ + 'verbs' => [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'index' => ['get'], + 'view' => ['get'], + 'create' => ['get', 'post'], + 'update' => ['get', 'put', 'post'], + 'delete' => ['post', 'delete'], + ], + ], + ]; +} +``` diff --git a/docs/internals/translation-status.md b/docs/internals/translation-status.md index ced9e5acab..fc434ef4dc 100644 --- a/docs/internals/translation-status.md +++ b/docs/internals/translation-status.md @@ -21,7 +21,7 @@ structure-controllers.md | Yes structure-views.md | Yes structure-models.md | Yes structure-modules.md | Yes -structure-filters.md | +structure-filters.md | Yes structure-widgets.md | structure-assets.md | structure-extensions.md | diff --git a/framework/filters/HttpCache.php b/framework/filters/HttpCache.php index 1304df8757..e5829611f3 100644 --- a/framework/filters/HttpCache.php +++ b/framework/filters/HttpCache.php @@ -12,11 +12,11 @@ use yii\base\ActionFilter; use yii\base\Action; /** - * The HttpCache provides functionality for caching via HTTP Last-Modified and Etag headers. + * HttpCache implements client-side caching by utilizing the `Last-Modified` and `Etag` HTTP headers. * * It is an action filter that can be added to a controller and handles the `beforeAction` event. * - * To use AccessControl, declare it in the `behaviors()` method of your controller class. + * To use HttpCache, declare it in the `behaviors()` method of your controller class. * In the following example the filter will be applied to the `list`-action and * the Last-Modified header will contain the date of the last update to the user table in the database. * @@ -24,7 +24,7 @@ use yii\base\Action; * public function behaviors() * { * return [ - * 'httpCache' => [ + * [ * 'class' => 'yii\filters\HttpCache', * 'only' => ['index'], * 'lastModified' => function ($action, $params) { diff --git a/framework/filters/PageCache.php b/framework/filters/PageCache.php index 84e1a9340c..7eec61272c 100644 --- a/framework/filters/PageCache.php +++ b/framework/filters/PageCache.php @@ -13,15 +13,14 @@ use yii\base\Action; use yii\caching\Dependency; /** - * The PageCache provides functionality for whole page caching + * PageCache implements server-side caching of whole pages. * * It is an action filter that can be added to a controller and handles the `beforeAction` event. * * To use PageCache, declare it in the `behaviors()` method of your controller class. - * In the following example the filter will be applied to the `list`-action and + * In the following example the filter will be applied to the `index` action and * cache the whole page for maximum 60 seconds or until the count of entries in the post table changes. - * It also stores different versions of the page depended on the route ([[varyByRoute]] is true by default), - * the application language and user id. + * It also stores different versions of the page depending on the application language. * * ~~~ * public function behaviors()