TablesController::actionRedirects()   F
last analyzed

Complexity

Conditions 16
Paths 1335

Size

Total Lines 96
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 2 Features 0
Metric Value
eloc 63
dl 0
loc 96
rs 1.4
c 4
b 2
f 0
cc 16
nc 1335
nop 6

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
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\ElementHelper;
18
use craft\web\Controller;
19
use nystudio107\retour\helpers\Permission as PermissionHelper;
20
use nystudio107\retour\helpers\UrlHelper;
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
    protected const HANDLED_MAP = [
36
        'handled' => 1,
37
        'nothandled' => 0,
38
    ];
39
40
    protected const SORT_MAP = [
41
        'DESC' => SORT_DESC,
42
        'ASC' => SORT_ASC,
43
    ];
44
45
    protected const ALLOWED_STATS_SORT_FIELDS = [
46
        'redirectSrcUrl',
47
        'referrerUrl',
48
        'remoteIp',
49
        'hitCount',
50
        'hitLastTime',
51
        'handledByRetour',
52
    ];
53
54
    protected const ALLOWED_REDIRECTS_SORT_FIELDS = [
55
        'redirectSrcUrl',
56
        'redirectDestUrl',
57
        'redirectMatchType',
58
        'siteId',
59
        'redirectHttpCode',
60
        'priority',
61
        'hitCount',
62
        'hitLastTime',
63
    ];
64
65
    // Protected Properties
66
    // =========================================================================
67
68
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
69
     * @inheritdoc
70
     */
71
    protected array|bool|int $allowAnonymous = [
72
    ];
73
74
    // Public Methods
75
    // =========================================================================
76
77
    /**
78
     * Handle requests for the dashboard statistics table
79
     *
80
     * @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...
81
     * @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...
82
     * @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...
83
     * @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...
84
     * @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...
85
     * @param string|null $handled
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
86
     *
87
     * @return Response
88
     * @throws ForbiddenHttpException
89
     * @throws BadRequestHttpException
90
     */
91
    public function actionDashboard(
92
        string $sort = 'hitCount|desc',
93
        int    $page = 1,
94
        int    $per_page = 20,
95
               $filter = '',
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 8 spaces but found 15
Loading history...
96
               $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...
97
               $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...
98
    ): Response {
99
        PermissionHelper::controllerPermissionCheck('retour:dashboard');
100
        $data = [];
101
        $sortField = 'hitCount';
102
        $sortType = 'DESC';
103
        // Figure out the sorting type
104
        if ($sort !== '') {
105
            if (strpos($sort, '|') === false) {
106
                $sortField = $sort;
107
            } else {
108
                list($sortField, $sortType) = explode('|', $sort);
109
            }
110
        }
111
        $sortType = strtoupper($sortType);
112
        $sortType = self::SORT_MAP[$sortType] ?? self::SORT_MAP['DESC'];
113
        // Validate untrusted data
114
        if (!in_array($sortField, self::ALLOWED_STATS_SORT_FIELDS, true)) {
115
            throw new BadRequestHttpException(Craft::t('retour', 'Invalid sort field specified.'));
116
        }
117
        // Query the db table
118
        $offset = ($page - 1) * $per_page;
119
        $query = (new Query())
120
            ->from(['{{%retour_stats}}'])
121
            ->offset($offset)
122
            ->limit($per_page)
123
            ->orderBy([$sortField => $sortType])
124
            ->filterWhere(['like', 'redirectSrcUrl', $filter])
125
            ->orFilterWhere(['like', 'referrerUrl', $filter]);
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) {
134
            // Add in the `addLink` field
135
            foreach ($stats as &$stat) {
136
                // Normalize the `redirectSrcUrl` to point to a valid frontend site URL
137
                $stat['redirectSrcUrlFull'] = $stat['redirectSrcUrl'];
138
                if (!UrlHelper::isAbsoluteUrl($stat['redirectSrcUrlFull'])) {
139
                    $sites = Craft::$app->getSites();
140
                    $site = $sites->getSiteById($stat['siteId'], true);
141
                    if ($site) {
142
                        $stat['redirectSrcUrlFull'] = UrlHelper::mergeUrlWithPath($site->baseUrl, $stat['redirectSrcUrlFull']);
143
                    }
144
                }
145
                $stat['addLink'] = '';
146
                if (!$stat['handledByRetour']) {
147
                    $encodedUrl = urlencode('/' . ltrim($stat['redirectSrcUrl'], '/'));
148
                    // Add the siteId to the URL, but keep the current behavior of passing in siteId=0 for "all"
149
                    $statSiteId = $stat['siteId'] ?? 0;
150
                    try {
151
                        $primarySite = Craft::$app->getSites()->getPrimarySite();
152
                    } catch (SiteNotFoundException $e) {
153
                        $primarySite = null;
154
                    }
155
                    if ($primarySite !== null && $statSiteId == (int)$primarySite->id) {
156
                        $statSiteId = 0;
157
                    }
158
                    $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...
159
                        'defaultUrl' => $encodedUrl,
160
                        'siteId' => $statSiteId,
161
                    ]);
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...
162
                }
163
            }
164
            // Format the data for the API
165
            $data['data'] = $stats;
166
            $count = $query->count();
167
            $data['links']['pagination'] = [
168
                'total' => $count,
169
                'per_page' => $per_page,
170
                'current_page' => $page,
171
                'last_page' => ceil($count / $per_page),
172
                'next_page_url' => null,
173
                'prev_page_url' => null,
174
                'from' => $offset + 1,
175
                'to' => $offset + ($count > $per_page ? $per_page : $count),
176
            ];
177
        }
178
179
        return $this->asJson($data);
180
    }
181
182
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $shortLinks should have a doc-comment as per coding-style.
Loading history...
183
     * Handle requests for the dashboard redirects table
184
     *
185
     * @param string $sort
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
186
     * @param int $page
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
187
     * @param int $per_page
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
188
     * @param string $filter
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
189
     * @param int $siteId
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...
190
     *
191
     * @return Response
192
     * @throws ForbiddenHttpException
193
     * @throws BadRequestHttpException
194
     */
195
    public function actionRedirects(
196
        string $sort = 'hitCount|desc',
197
        int    $page = 1,
198
        int    $per_page = 20,
199
               $filter = '',
0 ignored issues
show
Coding Style introduced by
Multi-line function declaration not indented correctly; expected 8 spaces but found 15
Loading history...
200
               $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...
201
               $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...
202
    ): Response {
203
        PermissionHelper::controllerPermissionCheck('retour:redirects');
204
        $data = [];
205
        $sortField = 'hitCount';
206
        $sortType = 'DESC';
207
        // Figure out the sorting type
208
        if ($sort !== '') {
209
            if (strpos($sort, '|') === false) {
210
                $sortField = $sort;
211
            } else {
212
                list($sortField, $sortType) = explode('|', $sort);
213
            }
214
        }
215
        $sortType = strtoupper($sortType);
216
        $sortType = self::SORT_MAP[$sortType] ?? self::SORT_MAP['DESC'];
217
        // Validate untrusted data
218
        if (!in_array($sortField, self::ALLOWED_REDIRECTS_SORT_FIELDS, true)) {
219
            throw new BadRequestHttpException(Craft::t('retour', 'Invalid sort field specified.'));
220
        }
221
        // Query the db table
222
        $offset = ($page - 1) * $per_page;
223
        $query = (new Query())
224
            ->from(['{{%retour_static_redirects}}'])
225
            ->offset($offset)
226
            ->limit($per_page)
227
            ->orderBy([$sortField => $sortType])
228
            ->filterWhere(['like', 'redirectSrcUrl', $filter])
229
            ->orFilterWhere(['like', 'redirectDestUrl', $filter]);
230
        if ((int)$siteId !== 0) {
231
            $query->andWhere(['siteId' => $siteId]);
232
        }
233
        if ($shortLinks) {
234
            $query->andWhere(['not', ['associatedElementId' => 0]]);
235
        } else {
236
            $query->andWhere(['associatedElementId' => 0]);
237
        }
238
        $redirects = $query->all();
239
        // Add in the `deleteLink` field and clean up the redirects
240
        foreach ($redirects as &$redirect) {
241
            // Handle short links by adding the element's title and CP URL
242
            if ($shortLinks) {
243
                $redirect['elementTitle'] = '';
244
                $redirect['elementCpUrl'] = '';
245
                $elementId = $redirect['associatedElementId'] ?? null;
246
                $elementSiteId = $redirect['siteId'] ?? null;
247
                if (!empty($elementId)) {
248
                    $element = Craft::$app->getElements()->getElementById($elementId, null, $elementSiteId);
249
                    if ($element) {
250
                        $element = ElementHelper::rootElement($element);
0 ignored issues
show
Deprecated Code introduced by
The function craft\helpers\ElementHelper::rootElement() has been deprecated: in 5.4.0. Use [[ElementInterface::getRootOwner()]] instead. ( Ignorable by Annotation )

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

250
                        $element = /** @scrutinizer ignore-deprecated */ ElementHelper::rootElement($element);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
251
                        $redirect['elementTitle'] = $element->title;
252
                        $redirect['elementCpUrl'] = $element->getCpEditUrl();
253
                    }
254
                }
255
            }
256
            // Make sure the destination URL is not a regex
257
            if ($redirect['redirectMatchType'] !== 'exactmatch') {
258
                if (preg_match("/\$\d+/", $redirect['redirectDestUrl'])) {
259
                    $redirect['redirectDestUrl'] = '';
260
                }
261
            }
262
            // Handle extracting the site name
263
            $redirect['siteName'] = Craft::t('retour', 'All Sites');
264
            if ($redirect['siteId']) {
265
                $sites = Craft::$app->getSites();
266
                $site = $sites->getSiteById($redirect['siteId']);
267
                if ($site) {
268
                    $redirect['siteName'] = $site->name;
269
                }
270
            }
271
272
            $redirect['editLink'] = UrlHelper::cpUrl('retour/edit-redirect/' . $redirect['id']);
273
        }
274
        // Format the data for the API
275
        if ($redirects) {
276
            $data['data'] = $redirects;
277
            $count = $query->count();
278
            $data['links']['pagination'] = [
279
                'total' => $count,
280
                'per_page' => $per_page,
281
                'current_page' => $page,
282
                'last_page' => ceil($count / $per_page),
283
                'next_page_url' => null,
284
                'prev_page_url' => null,
285
                'from' => $offset + 1,
286
                'to' => $offset + ($count > $per_page ? $per_page : $count),
287
            ];
288
        }
289
290
        return $this->asJson($data);
291
    }
292
293
    // Protected Methods
294
    // =========================================================================
295
}
296