Passed
Push — develop ( f4d51c...8caaec )
by Andrew
06:35
created

TablesController::actionDashboard()   B

Complexity

Conditions 10
Paths 39

Size

Total Lines 70
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 7
Bugs 0 Features 1
Metric Value
eloc 45
c 7
b 0
f 1
dl 0
loc 70
ccs 0
cts 64
cp 0
rs 7.3333
cc 10
nc 39
nop 6
crap 110

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
 * Retour plugin for Craft CMS 3.x
4
 *
5
 * Retour allows you to intelligently redirect legacy URLs, so that you don't
6
 * lose SEO value when rebuilding & restructuring a website
7
 *
8
 * @link      https://nystudio107.com/
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
9
 * @copyright Copyright (c) 2018 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
10
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
11
12
namespace nystudio107\retour\controllers;
13
14
use nystudio107\retour\helpers\Permission as PermissionHelper;
15
16
use Craft;
17
use craft\db\Query;
18
use craft\helpers\UrlHelper;
19
use craft\web\Controller;
20
21
use yii\web\BadRequestHttpException;
22
use yii\web\ForbiddenHttpException;
23
use yii\web\Response;
24
25
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
26
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
27
 * @package   Retour
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
28
 * @since     3.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
29
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
30
class TablesController extends Controller
31
{
32
    // Constants
33
    // =========================================================================
34
35
    const HANDLED_MAP = [
36
        'handled' => 1,
37
        'nothandled' => 0,
38
    ];
39
40
    const SORT_MAP = [
41
        'DESC' => SORT_DESC,
42
        'ASC' => SORT_ASC,
43
    ];
44
45
    const ALLOWED_STATS_SORT_FIELDS = [
46
        'redirectSrcUrl',
47
        'referrerUrl',
48
        'remoteIp',
49
        'hitCount',
50
        'hitLastTime',
51
        'handledByRetour',
52
    ];
53
54
    const ALLOWED_REDIRECTS_SORT_FIELDS = [
55
        'redirectSrcUrl',
56
        'redirectDestUrl',
57
        'redirectMatchType',
58
        'siteId',
59
        'redirectHttpCode',
60
        'hitCount',
61
        'hitLastTime',
62
    ];
63
64
    // Protected Properties
65
    // =========================================================================
66
67
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
68
     * @var    bool|array
0 ignored issues
show
Coding Style introduced by
Tag value for @var tag indented incorrectly; expected 1 spaces but found 4
Loading history...
69
     */
70
    protected $allowAnonymous = [
71
    ];
72
73
    // Public Methods
74
    // =========================================================================
75
76
    /**
77
     * Handle requests for the dashboard statistics table
78
     *
79
     * @param string      $sort
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
80
     * @param int         $page
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
81
     * @param int         $per_page
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
82
     * @param string      $filter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
83
     * @param int         $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
84
     * @param string|null $handled
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
85
     *
86
     * @return Response
87
     * @throws ForbiddenHttpException
88
     * @throws BadRequestHttpException
89
     */
90
    public function actionDashboard(
91
        string $sort = 'hitCount|desc',
92
        int $page = 1,
93
        int $per_page = 20,
94
        $filter = '',
95
        $siteId = 0,
96
        $handled = 'all'
97
    ): Response {
98
        PermissionHelper::controllerPermissionCheck('retour:dashboard');
99
        $data = [];
100
        $sortField = 'hitCount';
101
        $sortType = 'DESC';
102
        // Figure out the sorting type
103
        if ($sort !== '') {
104
            if (strpos($sort, '|') === false) {
105
                $sortField = $sort;
106
            } else {
107
                list($sortField, $sortType) = explode('|', $sort);
108
            }
109
        }
110
        $sortType = strtoupper($sortType);
111
        $sortType = self::SORT_MAP[$sortType] ?? self::SORT_MAP['DESC'];
112
        // Validate untrusted data
113
        if (!in_array($sortField, self::ALLOWED_STATS_SORT_FIELDS, true)) {
114
            throw new BadRequestHttpException(Craft::t('retour', 'Invalid sort field specified.'));
115
        }
116
        // Query the db table
117
        $offset = ($page - 1) * $per_page;
118
        $query = (new Query())
119
            ->from(['{{%retour_stats}}'])
120
            ->offset($offset)
121
            ->limit($per_page)
122
            ->orderBy([$sortField => $sortType])
123
            ->filterWhere(['like', 'redirectSrcUrl', $filter])
124
            ->orFilterWhere(['like', 'referrerUrl', $filter])
0 ignored issues
show
Coding Style introduced by
Space after closing parenthesis of function call prohibited
Loading history...
125
            ;
126
        if ((int)$siteId !== 0) {
127
            $query->andWhere(['siteId' => $siteId]);
128
        }
129
        if ($handled !== 'all') {
130
            $query->andWhere(['handledByRetour' => self::HANDLED_MAP[$handled]]);
131
        }
132
        $stats = $query->all();
133
        if ($stats) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stats of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
134
            // Add in the `addLink` field
135
            foreach ($stats as &$stat) {
136
                $stat['addLink'] = '';
137
                if (!$stat['handledByRetour']) {
138
                    $encodedUrl = urlencode('/'.ltrim($stat['redirectSrcUrl'], '/'));
139
                    $stat['addLink'] = UrlHelper::cpUrl('retour/add-redirect', [
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
140
                        'defaultUrl' => $encodedUrl
141
                    ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
142
                }
143
            }
144
            // Format the data for the API
145
            $data['data'] = $stats;
146
            $count = $query->count();
147
            $data['links']['pagination'] = [
148
                'total' => $count,
149
                'per_page' => $per_page,
150
                'current_page' => $page,
151
                'last_page' => ceil($count / $per_page),
152
                'next_page_url' => null,
153
                'prev_page_url' => null,
154
                'from' => $offset + 1,
155
                'to' => $offset + ($count > $per_page ? $per_page : $count),
156
            ];
157
        }
158
159
        return $this->asJson($data);
160
    }
161
162
    /**
163
     * Handle requests for the dashboard redirects table
164
     *
165
     * @param string $sort
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
166
     * @param int    $page
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
167
     * @param int    $per_page
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
168
     * @param string $filter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
169
     * @param null   $siteId
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $siteId is correct as it would always require null to be passed?
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
170
     *
171
     * @return Response
172
     * @throws ForbiddenHttpException
173
     * @throws BadRequestHttpException
174
     */
175
    public function actionRedirects(
176
        string $sort = 'hitCount|desc',
177
        int $page = 1,
178
        int $per_page = 20,
179
        $filter = '',
180
        $siteId = 0
181
    ): Response {
182
        PermissionHelper::controllerPermissionCheck('retour:redirects');
183
        $data = [];
184
        $sortField = 'hitCount';
185
        $sortType = 'DESC';
186
        // Figure out the sorting type
187
        if ($sort !== '') {
188
            if (strpos($sort, '|') === false) {
189
                $sortField = $sort;
190
            } else {
191
                list($sortField, $sortType) = explode('|', $sort);
192
            }
193
        }
194
        $sortType = strtoupper($sortType);
195
        $sortType = self::SORT_MAP[$sortType] ?? self::SORT_MAP['DESC'];
196
        // Validate untrusted data
197
        if (!in_array($sortField, self::ALLOWED_REDIRECTS_SORT_FIELDS, true)) {
198
            throw new BadRequestHttpException(Craft::t('retour', 'Invalid sort field specified.'));
199
        }
200
        // Query the db table
201
        $offset = ($page - 1) * $per_page;
202
        $query = (new Query())
203
            ->from(['{{%retour_static_redirects}}'])
204
            ->offset($offset)
205
            ->limit($per_page)
206
            ->orderBy([$sortField => $sortType])
207
            ->filterWhere(['like', 'redirectSrcUrl', $filter])
208
            ->orFilterWhere(['like', 'redirectDestUrl', $filter])
0 ignored issues
show
Coding Style introduced by
Space after closing parenthesis of function call prohibited
Loading history...
209
           ;
210
        if ((int)$siteId !== 0) {
211
            $query->andWhere(['siteId' => $siteId]);
212
        }
213
        $redirects = $query->all();
214
        // Add in the `deleteLink` field and clean up the redirects
215
        foreach ($redirects as &$redirect) {
216
            // Make sure the destination URL is not a regex
217
            if ($redirect['redirectMatchType'] !== 'exactmatch') {
218
                if (preg_match("/\$\d+/", $redirect['redirectDestUrl'])) {
219
                    $redirect['redirectDestUrl'] = '';
220
                }
221
            }
222
            // Handle extracting the site name
223
            $redirect['siteName'] = Craft::t('retour', 'All Sites');
224
            if ($redirect['siteId']) {
225
                $sites = Craft::$app->getSites();
226
                $site = $sites->getSiteById($redirect['siteId']);
227
                if ($site) {
228
                    $redirect['siteName'] = $site->name;
229
                }
230
            }
231
232
            $redirect['editLink'] = UrlHelper::cpUrl('retour/edit-redirect/'.$redirect['id']);
233
        }
234
        // Format the data for the API
235
        if ($redirects) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirects of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
236
            $data['data'] = $redirects;
237
            $count = $query->count();
238
            $data['links']['pagination'] = [
239
                'total' => $count,
240
                'per_page' => $per_page,
241
                'current_page' => $page,
242
                'last_page' => ceil($count / $per_page),
243
                'next_page_url' => null,
244
                'prev_page_url' => null,
245
                'from' => $offset + 1,
246
                'to' => $offset + ($count > $per_page ? $per_page : $count),
247
            ];
248
        }
249
250
        return $this->asJson($data);
251
    }
252
253
    // Protected Methods
254
    // =========================================================================
255
}
256