Controller::bindActionParams()   F
last analyzed

Complexity

Conditions 31
Paths 396

Size

Total Lines 92
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 55
CRAP Score 32.9684

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 31
eloc 67
c 2
b 0
f 0
nc 396
nop 2
dl 0
loc 92
ccs 55
cts 63
cp 0.873
crap 32.9684
rs 0.8833

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @link https://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license https://www.yiiframework.com/license/
6
 */
7
8
namespace yii\web;
9
10
use Yii;
11
use yii\base\Exception;
12
use yii\base\InlineAction;
13
use yii\helpers\Url;
14
15
/**
16
 * Controller is the base class of web controllers.
17
 *
18
 * For more details and usage information on Controller, see the [guide article on controllers](guide:structure-controllers).
19
 *
20
 * @property Request $request The request object.
21
 * @property Response $response The response object.
22
 * @property View $view The view object that can be used to render views or view files.
23
 *
24
 * @author Qiang Xue <[email protected]>
25
 * @since 2.0
26
 */
27
class Controller extends \yii\base\Controller
28
{
29
    /**
30
     * @var bool whether to enable CSRF validation for the actions in this controller.
31
     * CSRF validation is enabled only when both this property and [[\yii\web\Request::enableCsrfValidation]] are true.
32
     */
33
    public $enableCsrfValidation = true;
34
    /**
35
     * @var array the parameters bound to the current action.
36
     */
37
    public $actionParams = [];
38
39
40
    /**
41
     * Renders a view in response to an AJAX request.
42
     *
43
     * This method is similar to [[renderPartial()]] except that it will inject into
44
     * the rendering result with JS/CSS scripts and files which are registered with the view.
45
     * For this reason, you should use this method instead of [[renderPartial()]] to render
46
     * a view to respond to an AJAX request.
47
     *
48
     * @param string $view the view name. Please refer to [[render()]] on how to specify a view name.
49
     * @param array $params the parameters (name-value pairs) that should be made available in the view.
50
     * @return string the rendering result.
51
     */
52
    public function renderAjax($view, $params = [])
53
    {
54
        return $this->getView()->renderAjax($view, $params, $this);
0 ignored issues
show
Bug introduced by
The method renderAjax() does not exist on yii\base\View. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

54
        return $this->getView()->/** @scrutinizer ignore-call */ renderAjax($view, $params, $this);
Loading history...
55
    }
56
57
    /**
58
     * Send data formatted as JSON.
59
     *
60
     * This method is a shortcut for sending data formatted as JSON. It will return
61
     * the [[Application::getResponse()|response]] application component after configuring
62
     * the [[Response::$format|format]] and setting the [[Response::$data|data]] that should
63
     * be formatted. A common usage will be:
64
     *
65
     * ```php
66
     * return $this->asJson($data);
67
     * ```
68
     *
69
     * @param mixed $data the data that should be formatted.
70
     * @return Response a response that is configured to send `$data` formatted as JSON.
71
     * @since 2.0.11
72
     * @see Response::$format
73
     * @see Response::FORMAT_JSON
74
     * @see JsonResponseFormatter
75
     */
76 1
    public function asJson($data)
77
    {
78 1
        $this->response->format = Response::FORMAT_JSON;
79 1
        $this->response->data = $data;
80 1
        return $this->response;
81
    }
82
83
    /**
84
     * Send data formatted as XML.
85
     *
86
     * This method is a shortcut for sending data formatted as XML. It will return
87
     * the [[Application::getResponse()|response]] application component after configuring
88
     * the [[Response::$format|format]] and setting the [[Response::$data|data]] that should
89
     * be formatted. A common usage will be:
90
     *
91
     * ```php
92
     * return $this->asXml($data);
93
     * ```
94
     *
95
     * @param mixed $data the data that should be formatted.
96
     * @return Response a response that is configured to send `$data` formatted as XML.
97
     * @since 2.0.11
98
     * @see Response::$format
99
     * @see Response::FORMAT_XML
100
     * @see XmlResponseFormatter
101
     */
102 1
    public function asXml($data)
103
    {
104 1
        $this->response->format = Response::FORMAT_XML;
105 1
        $this->response->data = $data;
106 1
        return $this->response;
107
    }
108
109
    /**
110
     * Binds the parameters to the action.
111
     * This method is invoked by [[\yii\base\Action]] when it begins to run with the given parameters.
112
     * This method will check the parameter names that the action requires and return
113
     * the provided parameters according to the requirement. If there is any missing parameter,
114
     * an exception will be thrown.
115
     * @param \yii\base\Action $action the action to be bound with parameters
116
     * @param array $params the parameters to be bound to the action
117
     * @return array the valid parameters that the action can run with.
118
     * @throws BadRequestHttpException if there are missing or invalid parameters.
119
     */
120 91
    public function bindActionParams($action, $params)
121
    {
122 91
        if ($action instanceof InlineAction) {
123 77
            $method = new \ReflectionMethod($this, $action->actionMethod);
124
        } else {
125 14
            $method = new \ReflectionMethod($action, 'run');
126
        }
127
128 91
        $args = [];
129 91
        $missing = [];
130 91
        $actionParams = [];
131 91
        $requestedParams = [];
132 91
        foreach ($method->getParameters() as $param) {
133 9
            $name = $param->getName();
134 9
            if (array_key_exists($name, $params)) {
135 6
                $isValid = true;
136 6
                $isArray = ($type = $param->getType()) instanceof \ReflectionNamedType && $type->getName() === 'array';
137 6
                if ($isArray) {
138
                    $params[$name] = (array)$params[$name];
139 6
                } elseif (is_array($params[$name])) {
140
                    $isValid = false;
141
                } elseif (
142 6
                    PHP_VERSION_ID >= 70000
143 6
                    && ($type = $param->getType()) !== null
144 6
                    && method_exists($type, 'isBuiltin')
145 6
                    && $type->isBuiltin()
146 6
                    && ($params[$name] !== null || !$type->allowsNull())
147
                ) {
148 1
                    $typeName = PHP_VERSION_ID >= 70100 ? $type->getName() : (string)$type;
0 ignored issues
show
Bug introduced by
The method getName() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionNamedType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

148
                    $typeName = PHP_VERSION_ID >= 70100 ? $type->/** @scrutinizer ignore-call */ getName() : (string)$type;
Loading history...
149
150 1
                    if ($params[$name] === '' && $type->allowsNull()) {
151 1
                        if ($typeName !== 'string') { // for old string behavior compatibility
152 1
                            $params[$name] = null;
153
                        }
154
                    } else {
155
                        switch ($typeName) {
156 1
                            case 'int':
157 1
                                $params[$name] = filter_var($params[$name], FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
158 1
                                break;
159 1
                            case 'float':
160
                                $params[$name] = filter_var($params[$name], FILTER_VALIDATE_FLOAT, FILTER_NULL_ON_FAILURE);
161
                                break;
162 1
                            case 'bool':
163 1
                                $params[$name] = filter_var($params[$name], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
164 1
                                break;
165
                        }
166 1
                        if ($params[$name] === null) {
167 1
                            $isValid = false;
168
                        }
169
                    }
170
                }
171 6
                if (!$isValid) {
172 1
                    throw new BadRequestHttpException(
173 1
                        Yii::t('yii', 'Invalid data received for parameter "{param}".', ['param' => $name])
174 1
                    );
175
                }
176 6
                $args[] = $actionParams[$name] = $params[$name];
177 6
                unset($params[$name]);
178
            } elseif (
179 7
                PHP_VERSION_ID >= 70100
180 7
                && ($type = $param->getType()) !== null
181 7
                && $type instanceof \ReflectionNamedType
182 7
                && !$type->isBuiltin()
183
            ) {
184
                try {
185 6
                    $this->bindInjectedParams($type, $name, $args, $requestedParams);
186 3
                } catch (HttpException $e) {
187 1
                    throw $e;
188 2
                } catch (Exception $e) {
189 5
                    throw new ServerErrorHttpException($e->getMessage(), 0, $e);
190
                }
191 1
            } elseif ($param->isDefaultValueAvailable()) {
192 1
                $args[] = $actionParams[$name] = $param->getDefaultValue();
193
            } else {
194
                $missing[] = $name;
195
            }
196
        }
197
198 88
        if (!empty($missing)) {
199
            throw new BadRequestHttpException(
200
                Yii::t('yii', 'Missing required parameters: {params}', ['params' => implode(', ', $missing)])
201
            );
202
        }
203
204 88
        $this->actionParams = $actionParams;
205
206
        // We use a different array here, specifically one that doesn't contain service instances but descriptions instead.
207 88
        if (Yii::$app->requestedParams === null) {
208 88
            Yii::$app->requestedParams = array_merge($actionParams, $requestedParams);
209
        }
210
211 88
        return $args;
212
    }
213
214
    /**
215
     * {@inheritdoc}
216
     */
217 83
    public function beforeAction($action)
218
    {
219 83
        if (parent::beforeAction($action)) {
220 77
            if ($this->enableCsrfValidation && Yii::$app->getErrorHandler()->exception === null && !$this->request->validateCsrfToken()) {
221
                throw new BadRequestHttpException(Yii::t('yii', 'Unable to verify your data submission.'));
222
            }
223
224 77
            return true;
225
        }
226
227
        return false;
228
    }
229
230
    /**
231
     * Redirects the browser to the specified URL.
232
     * This method is a shortcut to [[Response::redirect()]].
233
     *
234
     * You can use it in an action by returning the [[Response]] directly:
235
     *
236
     * ```php
237
     * // stop executing this action and redirect to login page
238
     * return $this->redirect(['login']);
239
     * ```
240
     *
241
     * @param string|array $url the URL to be redirected to. This can be in one of the following formats:
242
     *
243
     * - a string representing a URL (e.g. "https://example.com")
244
     * - a string representing a URL alias (e.g. "@example.com")
245
     * - an array in the format of `[$route, ...name-value pairs...]` (e.g. `['site/index', 'ref' => 1]`)
246
     *   [[Url::to()]] will be used to convert the array into a URL.
247
     *
248
     * Any relative URL that starts with a single forward slash "/" will be converted
249
     * into an absolute one by prepending it with the host info of the current request.
250
     *
251
     * @param int $statusCode the HTTP status code. Defaults to 302.
252
     * See <https://tools.ietf.org/html/rfc2616#section-10>
253
     * for details about HTTP status code
254
     * @return Response the current response object
255
     */
256 1
    public function redirect($url, $statusCode = 302)
257
    {
258
        // calling Url::to() here because Response::redirect() modifies route before calling Url::to()
259 1
        return $this->response->redirect(Url::to($url), $statusCode);
260
    }
261
262
    /**
263
     * Redirects the browser to the home page.
264
     *
265
     * You can use this method in an action by returning the [[Response]] directly:
266
     *
267
     * ```php
268
     * // stop executing this action and redirect to home page
269
     * return $this->goHome();
270
     * ```
271
     *
272
     * @return Response the current response object
273
     */
274
    public function goHome()
275
    {
276
        return $this->response->redirect(Yii::$app->getHomeUrl());
0 ignored issues
show
Bug introduced by
The method getHomeUrl() does not exist on yii\console\Application. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

276
        return $this->response->redirect(Yii::$app->/** @scrutinizer ignore-call */ getHomeUrl());
Loading history...
277
    }
278
279
    /**
280
     * Redirects the browser to the last visited page.
281
     *
282
     * You can use this method in an action by returning the [[Response]] directly:
283
     *
284
     * ```php
285
     * // stop executing this action and redirect to last visited page
286
     * return $this->goBack();
287
     * ```
288
     *
289
     * For this function to work you have to [[User::setReturnUrl()|set the return URL]] in appropriate places before.
290
     *
291
     * @param string|array|null $defaultUrl the default return URL in case it was not set previously.
292
     * If this is null and the return URL was not set previously, [[Application::homeUrl]] will be redirected to.
293
     * Please refer to [[User::setReturnUrl()]] on accepted format of the URL.
294
     * @return Response the current response object
295
     * @see User::getReturnUrl()
296
     */
297
    public function goBack($defaultUrl = null)
298
    {
299
        return $this->response->redirect(Yii::$app->getUser()->getReturnUrl($defaultUrl));
0 ignored issues
show
Bug introduced by
The method getUser() does not exist on yii\console\Application. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

299
        return $this->response->redirect(Yii::$app->/** @scrutinizer ignore-call */ getUser()->getReturnUrl($defaultUrl));
Loading history...
300
    }
301
302
    /**
303
     * Refreshes the current page.
304
     * This method is a shortcut to [[Response::refresh()]].
305
     *
306
     * You can use it in an action by returning the [[Response]] directly:
307
     *
308
     * ```php
309
     * // stop executing this action and refresh the current page
310
     * return $this->refresh();
311
     * ```
312
     *
313
     * @param string $anchor the anchor that should be appended to the redirection URL.
314
     * Defaults to empty. Make sure the anchor starts with '#' if you want to specify it.
315
     * @return Response the response object itself
316
     */
317
    public function refresh($anchor = '')
318
    {
319
        return $this->response->redirect($this->request->getUrl() . $anchor);
320
    }
321
}
322