Controller.php 5.8 KB
Newer Older
Qiang Xue committed
1 2 3 4 5 6 7 8 9 10
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\rest;

use Yii;
11
use yii\filters\auth\CompositeAuth;
12
use yii\filters\RateLimiter;
Qiang Xue committed
13
use yii\web\Response;
Qiang Xue committed
14
use yii\web\UnsupportedMediaTypeHttpException;
15
use yii\filters\VerbFilter;
Qiang Xue committed
16
use yii\web\ForbiddenHttpException;
Qiang Xue committed
17 18 19 20 21 22 23

/**
 * Controller is the base class for RESTful API controller classes.
 *
 * 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]]);
Qiang Xue committed
24
 * 2. Validating request method (see [[verbs()]]).
25 26 27
 * 3. Authenticating user (see [[\yii\filters\auth\AuthInterface]]);
 * 4. Rate limiting (see [[\yii\filters\RateLimiter]]);
 * 5. Formatting response data (see [[serializeData()]]).
Qiang Xue committed
28 29 30 31 32 33
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class Controller extends \yii\web\Controller
{
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
    /**
     * @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.
     */
    public $serializer = 'yii\rest\Serializer';
    /**
     * @inheritdoc
     */
    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
     */
    public function behaviors()
    {
        return [
            'verbFilter' => [
                'class' => VerbFilter::className(),
                'actions' => $this->verbs(),
            ],
77
            'authenticator' => [
78 79
                'class' => CompositeAuth::className(),
            ],
80 81 82
            'rateLimiter' => [
                'class' => RateLimiter::className(),
            ],
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
        ];
    }

    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        $this->resolveFormatAndVersion();
    }

    /**
     * @inheritdoc
     */
    public function afterAction($action, $result)
    {
        $result = parent::afterAction($action, $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.
     * Please refer to [[VerbFilter::actions]] on how to declare the allowed verbs.
     * @return array the allowed HTTP verbs.
     */
    protected function verbs()
    {
        return [];
    }

    /**
     * Serializes the specified data.
     * The default implementation will create a serializer based on the configuration given by [[serializer]].
     * It then uses the serializer to serialize the given data.
151
     * @param mixed $data the data to be serialized
152 153 154 155 156 157 158 159 160 161 162 163 164 165
     * @return mixed the serialized data.
     */
    protected function serializeData($data)
    {
        return Yii::createObject($this->serializer)->serialize($data);
    }

    /**
     * Checks the privilege of the current user.
     *
     * This method should be overridden to check whether the current user has the privilege
     * to run the specified action against the specified data model.
     * If the user does not have access, a [[ForbiddenHttpException]] should be thrown.
     *
166 167 168
     * @param string $action the ID of the action to be executed
     * @param object $model the model to be accessed. If null, it means no specific model is being accessed.
     * @param array $params additional parameters
169 170 171 172 173
     * @throws ForbiddenHttpException if the user does not have access
     */
    public function checkAccess($action, $model = null, $params = [])
    {
    }
Qiang Xue committed
174
}