Completed
Push — master ( dd1459...47a67a )
by Basil
02:11
created

RestBehaviorsTrait::getUserAuthClass()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.6666
c 0
b 0
f 0
cc 4
nc 4
nop 0
1
<?php
2
3
namespace luya\traits;
4
5
use Yii;
6
use yii\web\Response;
7
use yii\filters\auth\CompositeAuth;
8
use yii\filters\auth\QueryParamAuth;
9
use yii\filters\auth\HttpBearerAuth;
10
use yii\filters\ContentNegotiator;
11
use yii\filters\Cors;
12
use yii\base\Model;
13
use luya\rest\UserBehaviorInterface;
14
use luya\web\filters\JsonCruftFilter;
15
use luya\helpers\RestHelper;
16
17
/**
18
 * Rest Behaviors Trait.
19
 *
20
 * This class overrides the default behaviors method of {{yii\rest\Controller}} controllers.
21
 *
22
 * The following changes are differ to the base implementation:
23
 *
24
 * + If {{luya\rest\UserBehaviorInterface}} is **not** implemented, the `authenticator` behavior ({{yii\filters\auth\CompositeAuth}}) is removed.
25
 * + If {{luya\rest\UserBehaviorInterface}} **is** implemented, the `authenticator` behavior ({{yii\filters\auth\CompositeAuth}}) is enabled.
26
 * + If {{luya\rest\UserBehaviorInterface}} **is** implemented, the `contentNegotiator` behavior ({{yii\filters\ContentNegotiator}}) is enabled.
27
 * + The `rateLimiter` behavior filter is **removed** by default.
28
 *
29
 * Read the {{luya\rest\UserBehaviorInterface}} about the configuration ability to protect the controller.
30
 *
31
 * @author Basil Suter <[email protected]>
32
 * @since 1.0.0
33
 */
34
trait RestBehaviorsTrait
35
{
36
    /**
37
     * @var boolean Whether CORS should be enabled or not.
38
     */
39
    public $enableCors = false;
40
    
41
    /**
42
     * @var array An array with languages which are passed to {{yii\filters\ContentNegotiator::$languages}}. Example
43
     *
44
     * ```php
45
     * 'languages' => [
46
     *     'en',
47
     *     'de',
48
     * ],
49
     * ```
50
     * @since 1.0.7
51
     */
52
    public $languages = [];
53
    
54
    /**
55
     * @var boolean Whether a unparsable cruf should be added to the json response or not. When enabled you have to parse the json response first before interpreting
56
     * as json.
57
     * @since 1.0.7
58
     */
59
    public $jsonCruft = false;
60
    
61
    /**
62
     * Whether the rest controller is protected or not.
63
     *
64
     * @return boolean|\yii\web\User
65
     */
66
    private function getUserAuthClass()
67
    {
68
        if ($this instanceof UserBehaviorInterface) {
69
            $class = $this->userAuthClass();
70
            
71
            if (!$class) { // return false;
72
                return false;
73
            }
74
            
75
            if (!is_object($class)) {
76
                return Yii::createObject($class);
0 ignored issues
show
Bug introduced by
It seems like $class defined by $this->userAuthClass() on line 69 can also be of type boolean; however, yii\BaseYii::createObject() does only seem to accept callable, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
77
            }
78
    
79
            return $class;
80
        }
81
        
82
        return false;
83
    }
84
    
85
    /**
86
     * Return all Auth methods for Composite Auth.
87
     *
88
     * @return array
89
     * @since 1.0.21
90
     */
91
    public function getCompositeAuthMethods()
92
    {
93
        return [
94
            QueryParamAuth::class,
95
            HttpBearerAuth::class,
96
        ];   
97
    }
98
99
    /**
100
     * Override the default {{yii\rest\Controller::behaviors()}} method.
101
     * The following changes are differ to the base implementation:
102
     *
103
     * + If {{luya\rest\UserBehaviorInterface}} is **not** implemented, the `authenticator` behavior ({{yii\filters\auth\CompositeAuth}}) is removed.
104
     * + If {{luya\rest\UserBehaviorInterface}} **is** implemented, the `authenticator` behavior ({{yii\filters\auth\CompositeAuth}}) is enabled.
105
     * + If {{luya\rest\UserBehaviorInterface}} **is** implemented, the `contentNegotiator` behavior ({{yii\filters\ContentNegotiator}}) is enabled.
106
     * + The `rateLimiter` behavior filter is **removed** by default.
107
     *
108
     * @return array Returns an array with registered behavior filters based on the implementation type.
109
     */
110
    public function behaviors()
111
    {
112
        $behaviors = parent::behaviors();
113
114
        if (!$this->getUserAuthClass()) {
115
            unset($behaviors['authenticator']);
116
        } else {
117
            // change to admin user auth class
118
            $behaviors['authenticator'] = [
119
                'class' => CompositeAuth::class,
120
                'user' => $this->getUserAuthClass(),
121
                'authMethods' => $this->getCompositeAuthMethods(),
122
            ];
123
            
124
            if ($this->enableCors) {
125
                $behaviors['authenticator']['except'] = ['options'];
126
            }
127
        }
128
        
129
        if ($this->enableCors) {
130
            $behaviors['cors'] = Cors::class;
131
        }
132
133
        $behaviors['contentNegotiator'] = [
134
            'class' => ContentNegotiator::class,
135
            'formats' => [
136
                'application/json' => Response::FORMAT_JSON,
137
                'application/xml' => Response::FORMAT_XML,
138
            ],
139
            'languages' => $this->languages,
140
        ];
141
        
142
        // by default rate limiter behavior is removed as it requires a database
143
        // user given from the admin module.
144
        if (isset($behaviors['rateLimiter'])) {
145
            unset($behaviors['rateLimiter']);
146
        }
147
148
        if ($this->jsonCruft) {
149
            $behaviors['cruft'] = JsonCruftFilter::class;
150
        }
151
        
152
        return $behaviors;
153
    }
154
155
    /**
156
     * Send Model errors with correct headers.
157
     *
158
     * Helper method to correctly send model errors with the correct response headers.
159
     *
160
     * Example return value:
161
     *
162
     * ```php
163
     * Array
164
     * (
165
     *     [0] => Array
166
     *         (
167
     *             [field] => firstname
168
     *             [message] => Firstname cannot be blank.
169
     *         )
170
     *     [1] => Array
171
     *         (
172
     *             [field] => email
173
     *             [message] => Email cannot be blank.
174
     *         )
175
     * )
176
     * ```
177
     *
178
     * @param \yii\base\Model $model The model to find the first error.
179
     * @throws \yii\base\InvalidParamException
180
     * @return array If the model has errors InvalidParamException will be thrown, otherwise an array with message and field key.
181
     */
182
    public function sendModelError(Model $model)
183
    {
184
        return RestHelper::sendModelError($model);
185
    }
186
    
187
    /**
188
     * Send Array validation error.
189
     *
190
     * Example input:
191
     *
192
     * ```php
193
     * return $this->sendArrayError(['firstname' => 'Firstname cannot be blank']);
194
     * ```
195
     *
196
     * Example return value:
197
     *
198
     * ```php
199
     * Array
200
     * (
201
     *     [0] => Array
202
     *         (
203
     *             [field] => firstname
204
     *             [message] => Firstname cannot be blank.
205
     *         )
206
     * )
207
     * ```
208
     * @param array $errors Provide an array with messages. Where key is the field and value the message.
209
     * @return array Returns an array with field and message keys for each item.
210
     * @since 1.0.3
211
     */
212
    public function sendArrayError(array $errors)
213
    {
214
        return RestHelper::sendArrayError($errors);
215
    }
216
}
217