Passed
Push — develop ( 160f48...9ae27b )
by Andrew
05:22
created

TablesController::actionRedirects()   F

Complexity

Conditions 13
Paths 363

Size

Total Lines 82
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 182

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 52
c 5
b 0
f 0
dl 0
loc 82
ccs 0
cts 73
cp 0
rs 3.7458
cc 13
nc 363
nop 6
crap 182

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 Craft;
15
use craft\db\Query;
16
use craft\errors\SiteNotFoundException;
17
use craft\helpers\UrlHelper;
18
use craft\web\Controller;
19
use nystudio107\retour\helpers\Permission as PermissionHelper;
20
use yii\web\BadRequestHttpException;
21
use yii\web\ForbiddenHttpException;
22
use yii\web\Response;
23
24
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
25
 * @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...
26
 * @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...
27
 * @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...
28
 */
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...
29
class TablesController extends Controller
30
{
31
    // Constants
32
    // =========================================================================
33
34
    const HANDLED_MAP = [
35
        'handled' => 1,
36
        'nothandled' => 0,
37
    ];
38
39
    const SORT_MAP = [
40
        'DESC' => SORT_DESC,
41
        'ASC' => SORT_ASC,
42
    ];
43
44
    const ALLOWED_STATS_SORT_FIELDS = [
45
        'redirectSrcUrl',
46
        'referrerUrl',
47
        'remoteIp',
48
        'hitCount',
49
        'hitLastTime',
50
        'handledByRetour',
51
    ];
52
53
    const ALLOWED_REDIRECTS_SORT_FIELDS = [
54
        'redirectSrcUrl',
55
        'redirectDestUrl',
56
        'redirectMatchType',
57
        'siteId',
58
        'redirectHttpCode',
59
        'hitCount',
60
        'hitLastTime',
61
    ];
62
63
    // Protected Properties
64
    // =========================================================================
65
66
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
67
     * @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...
68
     */
69
    protected $allowAnonymous = [
70
    ];
71
72
    // Public Methods
73
    // =========================================================================
74
75
    /**
76
     * Handle requests for the dashboard statistics table
77
     *
78
     * @param string $sort
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
79
     * @param int $page
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 9 spaces after parameter type; 1 found
Loading history...
80
     * @param int $per_page
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 9 spaces after parameter type; 1 found
Loading history...
81
     * @param string $filter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
82
     * @param int $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 9 spaces after parameter type; 1 found
Loading history...
83
     * @param string|null $handled
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
84
     *
85
     * @return Response
86
     * @throws ForbiddenHttpException
87
     * @throws BadRequestHttpException
88
     */
89
    public function actionDashboard(
90
        string $sort = 'hitCount|desc',
91
        int    $page = 1,
92
        int    $per_page = 20,
93
               $filter = '',
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 8 spaces but found 15
Loading history...
94
               $siteId = 0,
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 8 spaces but found 15
Loading history...
95
               $handled = 'all'
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 8 spaces but found 15
Loading history...
96
    ): Response
97
    {
0 ignored issues
show
Coding Style introduced by
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
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]);
125
        if ((int)$siteId !== 0) {
126
            $query->andWhere(['siteId' => $siteId]);
127
        }
128
        if ($handled !== 'all') {
129
            $query->andWhere(['handledByRetour' => self::HANDLED_MAP[$handled]]);
130
        }
131
        $stats = $query->all();
132
        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...
133
            // Add in the `addLink` field
134
            foreach ($stats as &$stat) {
135
                $stat['addLink'] = '';
136
                if (!$stat['handledByRetour']) {
137
                    $encodedUrl = urlencode('/' . ltrim($stat['redirectSrcUrl'], '/'));
138
                    // Add the siteId to the URL, but keep the current behavior of passing in siteId=0 for "all"
139
                    $statSiteId = $stat['siteId'] ?? 0;
140
                    try {
141
                        $primarySite = Craft::$app->getSites()->getPrimarySite();
142
                    } catch (SiteNotFoundException $e) {
143
                        $primarySite = null;
144
                    }
145
                    if ($primarySite !== null && $statSiteId == (int)$primarySite->id) {
146
                        $statSiteId = 0;
147
                    }
148
                    $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...
149
                        'defaultUrl' => $encodedUrl,
150
                        'siteId' => $statSiteId
151
                    ]);
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...
152
                }
153
            }
154
            // Format the data for the API
155
            $data['data'] = $stats;
156
            $count = $query->count();
157
            $data['links']['pagination'] = [
158
                'total' => $count,
159
                'per_page' => $per_page,
160
                'current_page' => $page,
161
                'last_page' => ceil($count / $per_page),
162
                'next_page_url' => null,
163
                'prev_page_url' => null,
164
                'from' => $offset + 1,
165
                'to' => $offset + ($count > $per_page ? $per_page : $count),
166
            ];
167
        }
168
169
        return $this->asJson($data);
170
    }
171
172
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $shortLinks should have a doc-comment as per coding-style.
Loading history...
173
     * Handle requests for the dashboard redirects table
174
     *
175
     * @param string $sort
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
176
     * @param int $page
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
177
     * @param int $per_page
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
178
     * @param string $filter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
179
     * @param null $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
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
Expected 3 spaces after parameter type; 1 found
Loading history...
180
     *
181
     * @return Response
182
     * @throws ForbiddenHttpException
183
     * @throws BadRequestHttpException
184
     */
185
    public function actionRedirects(
186
        string $sort = 'hitCount|desc',
187
        int    $page = 1,
188
        int    $per_page = 20,
189
               $filter = '',
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 8 spaces but found 15
Loading history...
190
               $siteId = 0,
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 8 spaces but found 15
Loading history...
191
               $shortLinks = false
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 8 spaces but found 15
Loading history...
192
    ): Response
193
    {
0 ignored issues
show
Coding Style introduced by
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
194
        PermissionHelper::controllerPermissionCheck('retour:redirects');
195
        $data = [];
196
        $sortField = 'hitCount';
197
        $sortType = 'DESC';
198
        // Figure out the sorting type
199
        if ($sort !== '') {
200
            if (strpos($sort, '|') === false) {
201
                $sortField = $sort;
202
            } else {
203
                list($sortField, $sortType) = explode('|', $sort);
204
            }
205
        }
206
        $sortType = strtoupper($sortType);
207
        $sortType = self::SORT_MAP[$sortType] ?? self::SORT_MAP['DESC'];
208
        // Validate untrusted data
209
        if (!in_array($sortField, self::ALLOWED_REDIRECTS_SORT_FIELDS, true)) {
210
            throw new BadRequestHttpException(Craft::t('retour', 'Invalid sort field specified.'));
211
        }
212
        // Query the db table
213
        $offset = ($page - 1) * $per_page;
214
        $query = (new Query())
215
            ->from(['{{%retour_static_redirects}}'])
216
            ->offset($offset)
217
            ->limit($per_page)
218
            ->orderBy([$sortField => $sortType])
219
            ->filterWhere(['like', 'redirectSrcUrl', $filter])
220
            ->orFilterWhere(['like', 'redirectDestUrl', $filter]);
221
        if ((int)$siteId !== 0) {
222
            $query->andWhere(['siteId' => $siteId]);
223
        }
224
        if ($shortLinks) {
225
            $query->andWhere(['not', ['associatedElementId' => null]]);
226
        } else {
227
            $query->andWhere(['associatedElementId' => 0]);
228
        }
229
        $redirects = $query->all();
230
        // Add in the `deleteLink` field and clean up the redirects
231
        foreach ($redirects as &$redirect) {
232
            // Make sure the destination URL is not a regex
233
            if ($redirect['redirectMatchType'] !== 'exactmatch') {
234
                if (preg_match("/\$\d+/", $redirect['redirectDestUrl'])) {
235
                    $redirect['redirectDestUrl'] = '';
236
                }
237
            }
238
            // Handle extracting the site name
239
            $redirect['siteName'] = Craft::t('retour', 'All Sites');
240
            if ($redirect['siteId']) {
241
                $sites = Craft::$app->getSites();
242
                $site = $sites->getSiteById($redirect['siteId']);
243
                if ($site) {
244
                    $redirect['siteName'] = $site->name;
245
                }
246
            }
247
248
            $redirect['editLink'] = UrlHelper::cpUrl('retour/edit-redirect/' . $redirect['id']);
249
        }
250
        // Format the data for the API
251
        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...
252
            $data['data'] = $redirects;
253
            $count = $query->count();
254
            $data['links']['pagination'] = [
255
                'total' => $count,
256
                'per_page' => $per_page,
257
                'current_page' => $page,
258
                'last_page' => ceil($count / $per_page),
259
                'next_page_url' => null,
260
                'prev_page_url' => null,
261
                'from' => $offset + 1,
262
                'to' => $offset + ($count > $per_page ? $per_page : $count),
263
            ];
264
        }
265
266
        return $this->asJson($data);
267
    }
268
269
    // Protected Methods
270
    // =========================================================================
271
}
272