mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-26 14:26:54 +08:00
Fixes #2034: Added ContentNegotiator
to support response format and language negotiation
This commit is contained in:
@ -5,7 +5,7 @@ Yii provides a whole set of tools to greatly simplify the task of implementing R
|
|||||||
In particular, Yii provides support for the following aspects regarding RESTful APIs:
|
In particular, Yii provides support for the following aspects regarding RESTful APIs:
|
||||||
|
|
||||||
* Quick prototyping with support for common APIs for ActiveRecord;
|
* Quick prototyping with support for common APIs for ActiveRecord;
|
||||||
* Response format (supporting JSON and XML by default) and API version negotiation;
|
* Response format (supporting JSON and XML by default) negotiation;
|
||||||
* Customizable object serialization with support for selectable output fields;
|
* Customizable object serialization with support for selectable output fields;
|
||||||
* Proper formatting of collection data and validation errors;
|
* Proper formatting of collection data and validation errors;
|
||||||
* Efficient routing with proper HTTP verb check;
|
* Efficient routing with proper HTTP verb check;
|
||||||
@ -187,7 +187,23 @@ Formatting Response Data
|
|||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
By default, Yii supports two response formats for RESTful APIs: JSON and XML. If you want to support
|
By default, Yii supports two response formats for RESTful APIs: JSON and XML. If you want to support
|
||||||
other formats, you should configure [[yii\rest\Controller::supportedFormats]] and also [[yii\web\Response::formatters]].
|
other formats, you should configure the `contentNegotiator` behavior in your REST controller classes as follows,
|
||||||
|
|
||||||
|
|
||||||
|
```php
|
||||||
|
use yii\helpers\ArrayHelper;
|
||||||
|
|
||||||
|
public function behaviors()
|
||||||
|
{
|
||||||
|
return ArrayHelper::merge(parent::behaviors(), [
|
||||||
|
'contentNegotiator' => [
|
||||||
|
'formats' => [
|
||||||
|
// ... other supported formats ...
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Formatting response data in general involves two steps:
|
Formatting response data in general involves two steps:
|
||||||
|
|
||||||
@ -808,8 +824,8 @@ The following list summarizes the HTTP status code that are used by the Yii REST
|
|||||||
* `500`: Internal server error. This could be caused by internal program errors.
|
* `500`: Internal server error. This could be caused by internal program errors.
|
||||||
|
|
||||||
|
|
||||||
Versioning
|
API Versioning
|
||||||
----------
|
--------------
|
||||||
|
|
||||||
Your APIs should be versioned. Unlike Web applications which you have full control on both client side and server side
|
Your APIs should be versioned. Unlike Web applications which you have full control on both client side and server side
|
||||||
code, for APIs you usually do not have control of the client code that consumes the APIs. Therefore, backward
|
code, for APIs you usually do not have control of the client code that consumes the APIs. Therefore, backward
|
||||||
@ -902,14 +918,16 @@ As a result, `http://example.com/v1/users` will return the list of users in vers
|
|||||||
Using modules, code for different major versions can be well isolated. And it is still possible
|
Using modules, code for different major versions can be well isolated. And it is still possible
|
||||||
to reuse code across modules via common base classes and other shared classes.
|
to reuse code across modules via common base classes and other shared classes.
|
||||||
|
|
||||||
To deal with minor version numbers, you may take advantage of the content type negotiation
|
To deal with minor version numbers, you may take advantage of the content negotiation
|
||||||
feature provided by [[yii\rest\Controller]]:
|
feature provided by the [[yii\filters\ContentNegotiator|contentNegotiator]] behavior. The `contentNegotiator`
|
||||||
|
behavior will set the [[yii\web\Response::acceptParams]] property when it determines which
|
||||||
|
content type to support.
|
||||||
|
|
||||||
* Specify a list of supported minor versions (within the major version of the containing module)
|
For example, if a request is sent with the HTTP header `Accept: application/json; version=v1`,
|
||||||
via [[yii\rest\Controller::supportedVersions]].
|
after content negotiation, [[yii\web\Response::acceptParams]] will contain the value `['version' => 'v1']`.
|
||||||
* Get the version number by reading [[yii\rest\Controller::version]].
|
|
||||||
* In relevant code, such as actions, resource classes, serializers, etc., write conditional
|
Based on the version information in `acceptParams`, you may write conditional code in places
|
||||||
code according to the requested minor version number.
|
such as actions, resource classes, serializers, etc.
|
||||||
|
|
||||||
Since minor versions require maintaining backward compatibility, hopefully there are not much
|
Since minor versions require maintaining backward compatibility, hopefully there are not much
|
||||||
version checks in your code. Otherwise, chances are that you may need to create a new major version.
|
version checks in your code. Otherwise, chances are that you may need to create a new major version.
|
||||||
|
@ -287,6 +287,7 @@ Yii Framework 2 Change Log
|
|||||||
- New #1393: [Codeception testing framework integration](https://github.com/yiisoft/yii2-codeception) (Ragazzo)
|
- New #1393: [Codeception testing framework integration](https://github.com/yiisoft/yii2-codeception) (Ragazzo)
|
||||||
- New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul)
|
- New #1438: [MongoDB integration](https://github.com/yiisoft/yii2-mongodb) ActiveRecord and Query (klimov-paul)
|
||||||
- New #1956: Implemented test fixture framework (qiangxue)
|
- New #1956: Implemented test fixture framework (qiangxue)
|
||||||
|
- New #2034: Added `ContentNegotiator` to support response format and language negotiation (qiangxue)
|
||||||
- New #2149: Added `yii\base\DynamicModel` to support ad-hoc data validation (qiangxue)
|
- New #2149: Added `yii\base\DynamicModel` to support ad-hoc data validation (qiangxue)
|
||||||
- New #2360: Added `AttributeBehavior` and `BlameableBehavior`, and renamed `AutoTimestamp` to `TimestampBehavior` (lucianobaraglia, qiangxue)
|
- New #2360: Added `AttributeBehavior` and `BlameableBehavior`, and renamed `AutoTimestamp` to `TimestampBehavior` (lucianobaraglia, qiangxue)
|
||||||
- New #2932: Added `yii\web\ViewAction` that allow you to render views based on GET parameter (samdark)
|
- New #2932: Added `yii\web\ViewAction` that allow you to render views based on GET parameter (samdark)
|
||||||
|
254
framework/filters/ContentNegotiator.php
Normal file
254
framework/filters/ContentNegotiator.php
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link http://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license http://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yii\filters;
|
||||||
|
|
||||||
|
use Yii;
|
||||||
|
use yii\base\ActionFilter;
|
||||||
|
use yii\base\BootstrapInterface;
|
||||||
|
use yii\base\InvalidConfigException;
|
||||||
|
use yii\web\Response;
|
||||||
|
use yii\web\Request;
|
||||||
|
use yii\web\UnsupportedMediaTypeHttpException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ContentNegotiator supports response format negotiation and application language negotiation.
|
||||||
|
*
|
||||||
|
* When the [[formats|supported formats]] property is specified, ContentNegotiator will support response format
|
||||||
|
* negotiation based on the value of the GET parameter [[formatParam]] and the `Accept` HTTP header.
|
||||||
|
* If a match is found, the [[Response::format]] property will be set as the chosen format.
|
||||||
|
* The [[Response::acceptMimeType]] as well as [[Response::acceptParams]] will also be updated accordingly.
|
||||||
|
*
|
||||||
|
* When the [[languages|supported languages]] is specified, ContentNegotiator will support application
|
||||||
|
* language negotiation based on the value of the GET parameter [[languageParam]] and the `Accept-Language` HTTP header.
|
||||||
|
* If a match is found, the [[\yii\base\Application::language]] property will be set as the chosen language.
|
||||||
|
*
|
||||||
|
* You may use ContentNegotiator as a bootstrap component as well as an action filter.
|
||||||
|
*
|
||||||
|
* The following code shows how you can use ContentNegotiator as a bootstrap component. Note that in this case,
|
||||||
|
* the content negotiation applies to the whole application.
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* // in application configuration
|
||||||
|
* use yii\web\Response;
|
||||||
|
*
|
||||||
|
* return [
|
||||||
|
* 'bootstrap' => [
|
||||||
|
* [
|
||||||
|
* 'class' => 'yii\filters\ContentNegotiator',
|
||||||
|
* 'formats' => [
|
||||||
|
* 'application/json' => Response::FORMAT_JSON,
|
||||||
|
* 'application/xml' => Response::FORMAT_XML,
|
||||||
|
* ],
|
||||||
|
* 'languages' => [
|
||||||
|
* 'en',
|
||||||
|
* 'de',
|
||||||
|
* ],
|
||||||
|
* ],
|
||||||
|
* ],
|
||||||
|
* ];
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The following code shows how you can use ContentNegotiator as an action filter in either a controller or a module.
|
||||||
|
* In this case, the content negotiation result only applies to the corresponding controller or module, or even
|
||||||
|
* specific actions if you configure the `only` or `except` property of the filter.
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* use yii\web\Response;
|
||||||
|
*
|
||||||
|
* public function behaviors()
|
||||||
|
* {
|
||||||
|
* return [
|
||||||
|
* [
|
||||||
|
* 'class' => 'yii\filters\ContentNegotiator',
|
||||||
|
* 'formats' => [
|
||||||
|
* 'application/json' => Response::FORMAT_JSON,
|
||||||
|
* 'application/xml' => Response::FORMAT_XML,
|
||||||
|
* ],
|
||||||
|
* 'languages' => [
|
||||||
|
* 'en',
|
||||||
|
* 'de',
|
||||||
|
* ],
|
||||||
|
* ],
|
||||||
|
* ];
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
|
* @since 2.0
|
||||||
|
*/
|
||||||
|
class ContentNegotiator extends ActionFilter implements BootstrapInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string the name of the GET parameter that specifies the response format.
|
||||||
|
* Note that if the specified format does not exist in [[formats]], a [[UnsupportedMediaTypeHttpException]]
|
||||||
|
* exception will be thrown. If the parameter value is empty or if this property is null,
|
||||||
|
* the response format will be determined based on the `Accept` HTTP header.
|
||||||
|
* @see formats
|
||||||
|
*/
|
||||||
|
public $formatParam = '_format';
|
||||||
|
/**
|
||||||
|
* @var string the name of the GET parameter that specifies the [[\yii\base\Application::language|application language]].
|
||||||
|
* Note that if the specified language does not match any of [[languages]], the first language in [[languages]]
|
||||||
|
* will be used. If the parameter value is empty or if this property is null,
|
||||||
|
* the application language will be determined based on the `Accept-Language` HTTP header.
|
||||||
|
* @see languages
|
||||||
|
*/
|
||||||
|
public $languageParam = '_lang';
|
||||||
|
/**
|
||||||
|
* @var array list of supported response formats. The keys are MIME types (e.g. `application/json`)
|
||||||
|
* while the values are the corresponding formats (e.g. `html`, `json`) which must be supported
|
||||||
|
* as declared in [[\yii\web\Response::formatters]].
|
||||||
|
*
|
||||||
|
* If this property is empty or not set, response format negotiation will be skipped.
|
||||||
|
*/
|
||||||
|
public $formats;
|
||||||
|
/**
|
||||||
|
* @var array a list of supported languages. The array keys are the supported language variants (e.g. `en-GB`, `en-US`),
|
||||||
|
* while the array values are the corresponding language codes (e.g. `en`, `de`) recognized by the application.
|
||||||
|
*
|
||||||
|
* Array keys are not always required. When an array value does not have a key, the matching of the requested language
|
||||||
|
* will be based on a language fallback mechanism. For example, a value of `en` will match `en`, `en_US`, `en-US`, `en-GB`, etc.
|
||||||
|
*
|
||||||
|
* If this property is empty or not set, response format negotiation will be skipped.
|
||||||
|
*/
|
||||||
|
public $languages;
|
||||||
|
/**
|
||||||
|
* @var Request the current request. If not set, the `request` application component will be used.
|
||||||
|
*/
|
||||||
|
public $request;
|
||||||
|
/**
|
||||||
|
* @var Response the response to be sent. If not set, the `response` application component will be used.
|
||||||
|
*/
|
||||||
|
public $response;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function bootstrap($app)
|
||||||
|
{
|
||||||
|
$this->negotiate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function beforeAction($action)
|
||||||
|
{
|
||||||
|
$this->negotiate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Negotiates the response format and application language.
|
||||||
|
*/
|
||||||
|
public function negotiate()
|
||||||
|
{
|
||||||
|
$request = $this->request ? : Yii::$app->getRequest();
|
||||||
|
$response = $this->response ? : Yii::$app->getResponse();
|
||||||
|
if (!empty($this->formats)) {
|
||||||
|
$this->negotiateContentType($request, $response);
|
||||||
|
}
|
||||||
|
if (!empty($languages)) {
|
||||||
|
Yii::$app->language = $this->negotiateLanguage($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Negotiates the response format.
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @throws InvalidConfigException if [[formats]] is empty
|
||||||
|
* @throws UnsupportedMediaTypeHttpException if none of the requested content types is accepted.
|
||||||
|
*/
|
||||||
|
protected function negotiateContentType($request, $response)
|
||||||
|
{
|
||||||
|
if (!empty($this->formatParam) && ($format = $request->get($this->formatParam)) !== null) {
|
||||||
|
if (in_array($format, $this->formats)) {
|
||||||
|
$response->format = $format;
|
||||||
|
$response->acceptMimeType = null;
|
||||||
|
$response->acceptParams = [];
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedMediaTypeHttpException('The requested response format is not supported: ' . $format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$types = $request->getAcceptableContentTypes();
|
||||||
|
if (empty($types)) {
|
||||||
|
$types['*/*'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($types as $type => $params) {
|
||||||
|
if (isset($this->formats[$type])) {
|
||||||
|
$response->format = $this->formats[$type];
|
||||||
|
$response->acceptMimeType = $type;
|
||||||
|
$response->acceptParams = $params;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($types['*/*'])) {
|
||||||
|
// return the first format
|
||||||
|
foreach ($this->formats as $type => $format) {
|
||||||
|
$response->format = $this->formats[$type];
|
||||||
|
$response->acceptMimeType = $type;
|
||||||
|
$response->acceptParams = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedMediaTypeHttpException('None of your requested content types is supported.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Negotiates the application language.
|
||||||
|
* @param Request $request
|
||||||
|
* @return string the chosen language
|
||||||
|
*/
|
||||||
|
protected function negotiateLanguage($request)
|
||||||
|
{
|
||||||
|
if (!empty($this->languageParam) && ($language = $request->get($this->languageParam)) !== null) {
|
||||||
|
if (isset($this->languages[$language])) {
|
||||||
|
return $this->languages[$language];
|
||||||
|
}
|
||||||
|
foreach ($this->languages as $key => $supported) {
|
||||||
|
if (is_integer($key) && $this->isLanguageSupported($language, $supported)) {
|
||||||
|
return $supported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reset($this->languages);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($request->getAcceptableLanguages() as $language) {
|
||||||
|
if (isset($this->languages[$language])) {
|
||||||
|
return $this->languages[$language];
|
||||||
|
}
|
||||||
|
foreach ($this->languages as $key => $supported) {
|
||||||
|
if (is_integer($key) && $this->isLanguageSupported($language, $supported)) {
|
||||||
|
return $supported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reset($this->languages);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a value indicating whether the requested language matches the supported language.
|
||||||
|
* @param string $requested the requested language code
|
||||||
|
* @param string $supported the supported language code
|
||||||
|
* @return boolean whether the requested language is supported
|
||||||
|
*/
|
||||||
|
protected function isLanguageSupported($requested, $supported)
|
||||||
|
{
|
||||||
|
$supported = str_replace('_', '-', strtolower($supported));
|
||||||
|
$requested = str_replace('_', '-', strtolower($requested));
|
||||||
|
return strpos($requested . '-', $supported . '-') === 0;
|
||||||
|
}
|
||||||
|
}
|
@ -41,13 +41,22 @@ class CompositeAuth extends AuthMethod
|
|||||||
/**
|
/**
|
||||||
* @var array the supported authentication methods. This property should take a list of supported
|
* @var array the supported authentication methods. This property should take a list of supported
|
||||||
* authentication methods, each represented by an authentication class or configuration.
|
* authentication methods, each represented by an authentication class or configuration.
|
||||||
* If this is not set or empty, no authentication will be performed.
|
*
|
||||||
|
* If this property is empty, no authentication will be performed.
|
||||||
*
|
*
|
||||||
* Note that an auth method class must implement the [[\yii\filters\auth\AuthInterface]] interface.
|
* Note that an auth method class must implement the [[\yii\filters\auth\AuthInterface]] interface.
|
||||||
*/
|
*/
|
||||||
public $authMethods = [];
|
public $authMethods = [];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function beforeAction($action)
|
||||||
|
{
|
||||||
|
return empty($this->authMethods) ? true : parent::beforeAction($action);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
|
@ -9,6 +9,7 @@ namespace yii\rest;
|
|||||||
|
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\filters\auth\CompositeAuth;
|
use yii\filters\auth\CompositeAuth;
|
||||||
|
use yii\filters\ContentNegotiator;
|
||||||
use yii\filters\RateLimiter;
|
use yii\filters\RateLimiter;
|
||||||
use yii\web\Response;
|
use yii\web\Response;
|
||||||
use yii\web\UnsupportedMediaTypeHttpException;
|
use yii\web\UnsupportedMediaTypeHttpException;
|
||||||
@ -20,10 +21,10 @@ use yii\web\ForbiddenHttpException;
|
|||||||
*
|
*
|
||||||
* Controller implements the following steps in a RESTful API request handling cycle:
|
* Controller implements the following steps in a RESTful API request handling cycle:
|
||||||
*
|
*
|
||||||
* 1. Resolving response format and API version number (see [[supportedFormats]], [[supportedVersions]] and [[version]]);
|
* 1. Resolving response format (see [[ContentNegotiator]]);
|
||||||
* 2. Validating request method (see [[verbs()]]).
|
* 2. Validating request method (see [[verbs()]]).
|
||||||
* 3. Authenticating user (see [[\yii\filters\auth\AuthInterface]]);
|
* 3. Authenticating user (see [[\yii\filters\auth\AuthInterface]]);
|
||||||
* 4. Rate limiting (see [[\yii\filters\RateLimiter]]);
|
* 4. Rate limiting (see [[RateLimiter]]);
|
||||||
* 5. Formatting response data (see [[serializeData()]]).
|
* 5. Formatting response data (see [[serializeData()]]).
|
||||||
*
|
*
|
||||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||||
@ -31,10 +32,6 @@ use yii\web\ForbiddenHttpException;
|
|||||||
*/
|
*/
|
||||||
class Controller extends \yii\web\Controller
|
class Controller extends \yii\web\Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var string the name of the header parameter representing the API version number.
|
|
||||||
*/
|
|
||||||
public $versionHeaderParam = 'version';
|
|
||||||
/**
|
/**
|
||||||
* @var string|array the configuration for creating the serializer that formats the response data.
|
* @var string|array the configuration for creating the serializer that formats the response data.
|
||||||
*/
|
*/
|
||||||
@ -43,26 +40,7 @@ class Controller extends \yii\web\Controller
|
|||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public $enableCsrfValidation = false;
|
public $enableCsrfValidation = false;
|
||||||
/**
|
|
||||||
* @var string the chosen API version number, or null if [[supportedVersions]] is empty.
|
|
||||||
* @see supportedVersions
|
|
||||||
*/
|
|
||||||
public $version;
|
|
||||||
/**
|
|
||||||
* @var array list of supported API version numbers. If the current request does not specify a version
|
|
||||||
* number, the first element will be used as the [[version|chosen version number]]. For this reason, you should
|
|
||||||
* put the latest version number at the first. If this property is empty, [[version]] will not be set.
|
|
||||||
*/
|
|
||||||
public $supportedVersions = [];
|
|
||||||
/**
|
|
||||||
* @var array list of supported response formats. The array keys are the requested content MIME types,
|
|
||||||
* and the array values are the corresponding response formats. The first element will be used
|
|
||||||
* as the response format if the current request does not specify a content type.
|
|
||||||
*/
|
|
||||||
public $supportedFormats = [
|
|
||||||
'application/json' => Response::FORMAT_JSON,
|
|
||||||
'application/xml' => Response::FORMAT_XML,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
@ -70,6 +48,13 @@ class Controller extends \yii\web\Controller
|
|||||||
public function behaviors()
|
public function behaviors()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
'contentNegotiator' => [
|
||||||
|
'class' => ContentNegotiator::className(),
|
||||||
|
'formats' => [
|
||||||
|
'application/json' => Response::FORMAT_JSON,
|
||||||
|
'application/xml' => Response::FORMAT_XML,
|
||||||
|
],
|
||||||
|
],
|
||||||
'verbFilter' => [
|
'verbFilter' => [
|
||||||
'class' => VerbFilter::className(),
|
'class' => VerbFilter::className(),
|
||||||
'actions' => $this->verbs(),
|
'actions' => $this->verbs(),
|
||||||
@ -83,15 +68,6 @@ class Controller extends \yii\web\Controller
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
public function init()
|
|
||||||
{
|
|
||||||
parent::init();
|
|
||||||
$this->resolveFormatAndVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
@ -101,39 +77,6 @@ class Controller extends \yii\web\Controller
|
|||||||
return $this->serializeData($result);
|
return $this->serializeData($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves the response format and the API version number.
|
|
||||||
* @throws UnsupportedMediaTypeHttpException
|
|
||||||
*/
|
|
||||||
protected function resolveFormatAndVersion()
|
|
||||||
{
|
|
||||||
$this->version = empty($this->supportedVersions) ? null : reset($this->supportedVersions);
|
|
||||||
Yii::$app->getResponse()->format = reset($this->supportedFormats);
|
|
||||||
$types = Yii::$app->getRequest()->getAcceptableContentTypes();
|
|
||||||
if (empty($types)) {
|
|
||||||
$types['*/*'] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($types as $type => $params) {
|
|
||||||
if (isset($this->supportedFormats[$type])) {
|
|
||||||
Yii::$app->getResponse()->format = $this->supportedFormats[$type];
|
|
||||||
if (isset($params[$this->versionHeaderParam])) {
|
|
||||||
if (in_array($params[$this->versionHeaderParam], $this->supportedVersions, true)) {
|
|
||||||
$this->version = $params[$this->versionHeaderParam];
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedMediaTypeHttpException('You are requesting an invalid version number.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($types['*/*'])) {
|
|
||||||
throw new UnsupportedMediaTypeHttpException('None of your requested content types is supported.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Declares the allowed HTTP verbs.
|
* Declares the allowed HTTP verbs.
|
||||||
* Please refer to [[VerbFilter::actions]] on how to declare the allowed verbs.
|
* Please refer to [[VerbFilter::actions]] on how to declare the allowed verbs.
|
||||||
|
@ -102,23 +102,16 @@ class Response extends \yii\base\Response
|
|||||||
*/
|
*/
|
||||||
public $format = self::FORMAT_HTML;
|
public $format = self::FORMAT_HTML;
|
||||||
/**
|
/**
|
||||||
* @var array a list of supported response formats. The keys are MIME types (e.g. `application/json`)
|
* @var string the MIME type (e.g. `application/json`) from the request ACCEPT header chosen for this response.
|
||||||
* while the values are the corresponding formats (e.g. `html`, `json`) which must be supported by [[formatters]].
|
* This property is mainly set by [\yii\filters\ContentNegotiator]].
|
||||||
* When this property is set, a content type negotiation process will be conducted to determine
|
|
||||||
* the value of [[format]] and the corresponding [[mimeType]] and [[acceptParams]] values.
|
|
||||||
*/
|
*/
|
||||||
public $supportedFormats;
|
public $acceptMimeType;
|
||||||
/**
|
/**
|
||||||
* @var string the MIME type (e.g. `application/json`) chosen for this response after content type negotiation.
|
* @var array the parameters (e.g. `['q' => 1, 'version' => '1.0']`) associated with the [[acceptMimeType|chosen MIME type]].
|
||||||
* This property will be set by the content type negotiation process.
|
* This is a list of name-value pairs associated with [[mimeType]] from the ACCEPT HTTP header.
|
||||||
|
* This property is mainly set by [\yii\filters\ContentNegotiator]].
|
||||||
*/
|
*/
|
||||||
public $mimeType;
|
public $acceptParams = [];
|
||||||
/**
|
|
||||||
* @var array the parameters (e.g. `['q' => 1, 'version' => '1.0']`) for the MIME type chosen
|
|
||||||
* by the content type negotiation. This is a list of name-value pairs associated with [[mimeType]]
|
|
||||||
* from the ACCEPT HTTP header. This property will be set by the content type negotiation process.
|
|
||||||
*/
|
|
||||||
public $acceptParams;
|
|
||||||
/**
|
/**
|
||||||
* @var array the formatters for converting data into the response content of the specified [[format]].
|
* @var array the formatters for converting data into the response content of the specified [[format]].
|
||||||
* The array keys are the format names, and the array values are the corresponding configurations
|
* The array keys are the format names, and the array values are the corresponding configurations
|
||||||
|
Reference in New Issue
Block a user