Completed
Push — master ( e3f8d4...3c1926 )
by Charles
02:37
created

Controller::beforeAction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
namespace yrc\rest;
4
5
use yii\rest\Controller as RestController;
6
use yii\filters\Cors;
7
use yii\filters\RateLimiter;
8
use yii\filters\VerbFilter;
9
use yii\web\HttpException;
10
use Yii;
11
12
use ReflectionClass;
13
use ReflectionMethod;
14
15
/**
16
 * Implements Restful API controller interfaces
17
 * @class Controller
18
 */
19
class Controller extends RestController
20
{
21
    /**
22
     * Allowed HTTP verbs
23
     * @var array $httpVerbs
24
     */
25
    private $httpVerbs = ['post', 'get', 'delete', 'put', 'patch', 'options', 'head'];
26
    
27
    /**
28
     * Global access filter
29
     */
30
    public function beforeAction($action)
31
    {
32
        $parent = parent::beforeAction($action);
33
34
        // Check the global access control header
35
        if (!Yii::$app->yrc->checkAccessHeader(Yii::$app->request)) {
36
            throw new HttpException(401);
37
        }
38
39
        return $parent;
40
    }
41
42
    /**
43
     * RestController automatically applies HTTP verb filtering and CORS headers
44
     * @return array
45
     */
46
    public function behaviors()
47
    {
48
        $behaviors = parent::behaviors();
49
        
50
        $behaviors['corsFilter'] = [
51
            'class' => Cors::className(),
52
            'cors' => [
53
                'Origin' => ['*'],
54
                'Access-Control-Request-Method' => $this->getHttpVerbMethodsFromClass($this->actions()[$this->action->id]),
55
                'Access-Control-Request-Headers' => [
56
                    'Origin',
57
                    'X-Requested-With',
58
                    'Content-Type',
59
                    'Accept',
60
                    'Authorization',
61
                    'X-Date'
62
                ],
63
                'Access-Control-Expose-Headers' => [
64
                    'X-Pagination-Per-Page',
65
                    'X-Pagination-Total-Count',
66
                    'X-Pagination-Current-Page',
67
                    'X-Pagination-Page-Count',
68
                    'Allow',
69
                    'X-Rate-Limit-Limit',
70
                    'X-Rate-Limit-Remaining',
71
                    'X-Rate-Limit-Reset'
72
                ],
73
            ]
74
        ];
75
76
        $behaviors['verbs'] = [
77
            'class' => VerbFilter::className(),
78
            'actions' => $this->getVerbFilterActionMap()
79
        ];
80
81
        $behaviors['rateLimiter'] = [
82
            'class' => RateLimiter::className(),
83
            'enableRateLimitHeaders' => true
84
        ];
85
86
        return $behaviors;
87
    }
88
89
    /**
90
     * Retrieves the HTTP verb list
91
     * @param string $class
92
     * @return array
93
     */
94
    private function getHttpVerbMethodsFromClass($class)
95
    {
96
        $result = [];
97
98
        // Fetch the static methods for the class
99
        $reflection = new ReflectionClass($class);
100
        $methods = $reflection->getMethods(ReflectionMethod::IS_STATIC);
101
        foreach ($methods as $method) {
102
            if (in_array($method->name, $this->httpVerbs)) {
103
                $result[] = $method->name;
104
            }
105
        }
106
107
        return $result;
108
    }
109
110
    /**
111
     * Convers self::actions() for automatic verb filtering
112
     * @return array
113
     */
114
    private function getVerbFilterActionMap()
115
    {
116
        $actions = $this->actions();
117
118
        // Only apply this filtering for ActionMapped Controllers
119
        if (empty($actions)) {
120
            return [];
121
        }
122
123
        $actionMap = [];
124
        
125
        // Iterate over all the actions, and automatically determine the methods implemented
126
        foreach ($actions as $actionName => $params) {
127
            static $class = null;
128
            if (is_array($params)) {
129
                $class = $params['class'];
130
            } else {
131
                $class = $params;
132
            }
133
134
            $actionMap[$actionName] = $this->getHttpVerbMethodsFromClass($class);
135
        }
136
137
        return $actionMap;
138
    }
139
}