Redirects   F
last analyzed

Complexity

Total Complexity 145

Size/Duplication

Total Lines 1330
Duplicated Lines 0 %

Importance

Changes 27
Bugs 8 Features 1
Metric Value
wmc 145
eloc 624
c 27
b 8
f 1
dl 0
loc 1330
rs 1.976

27 Methods

Rating   Name   Duplication   Size   Complexity  
A getRedirectFromCache() 0 15 1
A enableElementRedirect() 0 20 3
A getRedirectsByMatchType() 0 24 4
D saveRedirect() 0 117 15
A removeElementRedirect() 0 15 6
A getAllExactMatchRedirects() 0 3 1
A deleteShortlinkById() 0 20 4
A getRedirectByRedirectSrcUrl() 0 17 2
A setShortLinkFieldValue() 0 24 5
A getMatchesList() 0 16 3
F doRedirect() 0 107 23
F resolveRedirect() 0 155 20
A getAllRegExRedirects() 0 3 1
A getRedirectsByElementId() 0 11 2
A saveRedirectToCache() 0 26 2
A isPreview() 0 6 2
B findRedirectMatch() 0 45 7
A deleteRedirectById() 0 33 3
A updateAssociatedElementShortLink() 0 19 4
A getAllStaticRedirects() 0 15 3
A invalidateCaches() 0 15 2
A resolveEventRedirect() 0 21 4
A excludeUri() 0 30 6
A incrementRedirectHitCount() 0 29 3
B handle404() 0 57 10
A getRedirectById() 0 9 1
B getStaticRedirect() 0 100 8

How to fix   Complexity   

Complex Class

Complex classes like Redirects often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Redirects, and based on these observations, apply Extract Interface, too.

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\services;
13
14
use Craft;
15
use craft\base\Component;
16
use craft\base\ElementInterface;
0 ignored issues
show
Bug introduced by
The type craft\base\ElementInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use craft\base\Plugin;
18
use craft\db\Query;
19
use craft\errors\ElementNotFoundException;
20
use craft\errors\SiteNotFoundException;
21
use craft\helpers\Db;
22
use craft\helpers\StringHelper;
23
use craft\web\Response as WebResponse;
24
use DateTime;
25
use nystudio107\retour\events\RedirectEvent;
26
use nystudio107\retour\events\RedirectResolvedEvent;
27
use nystudio107\retour\events\ResolveRedirectEvent;
28
use nystudio107\retour\fields\ShortLink;
29
use nystudio107\retour\helpers\Text as TextHelper;
30
use nystudio107\retour\helpers\UrlHelper;
31
use nystudio107\retour\models\StaticRedirects as StaticRedirectsModel;
32
use nystudio107\retour\Retour;
33
use Throwable;
34
use yii\base\ExitException;
35
use yii\base\InvalidConfigException;
36
use yii\base\InvalidRouteException;
37
use yii\caching\TagDependency;
38
use yii\db\Exception;
39
use function call_user_func_array;
40
41
/** @noinspection MissingPropertyAnnotationsInspection */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
42
43
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
44
 * @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...
45
 * @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...
46
 * @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...
47
 */
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...
48
class Redirects extends Component
49
{
50
    // Constants
51
    // =========================================================================
52
53
    public const CACHE_KEY = 'retour_redirect_';
54
55
    public const GLOBAL_REDIRECTS_CACHE_TAG = 'retour_redirects';
56
57
    public const EVENT_REDIRECT_ID = 0;
58
59
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
60
     * @event RedirectEvent The event that is triggered before the redirect is saved
61
     * You may set [[RedirectEvent::isValid]] to `false` to prevent the redirect from getting saved.
62
     *
63
     * ```php
64
     * use nystudio107\retour\services\Redirects;
65
     * use nystudio107\retour\events\RedirectEvent;
66
     *
67
     * Event::on(Redirects::class,
68
     *     Redirects::EVENT_BEFORE_SAVE_REDIRECT,
69
     *     function(RedirectEvent $event) {
70
     *         // potentially set $event->isValid;
71
     *     }
72
     * );
73
     * ```
74
     */
75
    public const EVENT_BEFORE_SAVE_REDIRECT = 'beforeSaveRedirect';
76
77
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
78
     * @event RedirectEvent The event that is triggered after the redirect is saved
79
     *
80
     * ```php
81
     * use nystudio107\retour\services\Redirects;
82
     * use nystudio107\retour\events\RedirectEvent;
83
     *
84
     * Event::on(Redirects::class,
85
     *     Redirects::EVENT_AFTER_SAVE_REDIRECT,
86
     *     function(RedirectEvent $event) {
87
     *         // the redirect was saved
88
     *     }
89
     * );
90
     * ```
91
     */
92
    public const EVENT_AFTER_SAVE_REDIRECT = 'afterSaveRedirect';
93
94
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
95
     * @event RedirectEvent The event that is triggered before the redirect is deleted
96
     * You may set [[RedirectEvent::isValid]] to `false` to prevent the redirect from getting deleted.
97
     *
98
     * ```php
99
     * use nystudio107\retour\services\Redirects;
100
     * use nystudio107\retour\events\RedirectEvent;
101
     *
102
     * Event::on(Redirects::class,
103
     *     Redirects::EVENT_BEFORE_DELETE_REDIRECT,
104
     *     function(RedirectEvent $event) {
105
     *         // potentially set $event->isValid;
106
     *     }
107
     * );
108
     * ```
109
     */
110
    public const EVENT_BEFORE_DELETE_REDIRECT = 'beforeDeleteRedirect';
111
112
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
113
     * @event RedirectEvent The event that is triggered after the redirect is deleted
114
     *
115
     * ```php
116
     * use nystudio107\retour\services\Redirects;
117
     * use nystudio107\retour\events\RedirectEvent;
118
     *
119
     * Event::on(Redirects::class,
120
     *     Redirects::EVENT_AFTER_DELETE_REDIRECT,
121
     *     function(RedirectEvent $event) {
122
     *         // the redirect was deleted
123
     *     }
124
     * );
125
     * ```
126
     */
127
    public const EVENT_AFTER_DELETE_REDIRECT = 'afterDeleteRedirect';
128
129
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
130
     * @event ResolveRedirectEvent The event that is triggered before Retour has attempted
131
     *        to resolve redirects. You may set [[ResolveRedirectEvent::redirectDestUrl]] to
132
     *        to the URL that it should redirect to, or null if no redirect should happen
133
     *
134
     * ```php
135
     * use nystudio107\retour\services\Redirects;
136
     * use nystudio107\retour\events\ResolveRedirectEvent;
137
     *
138
     * Event::on(Redirects::class,
139
     *     Redirects::EVENT_AFTER_SAVE_REDIRECT,
140
     *     function(ResolveRedirectEvent $event) {
141
     *         // potentially set $event->redirectDestUrl;
142
     *     }
143
     * );
144
     * ```
145
     */
146
    public const EVENT_BEFORE_RESOLVE_REDIRECT = 'beforeResolveRedirect';
147
148
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
149
     * @event ResolveRedirectEvent The event that is triggered after Retour has attempted
150
     *        to resolve redirects. You may set [[ResolveRedirectEvent::redirectDestUrl]] to
151
     *        to the URL that it should redirect to, or null if no redirect should happen
152
     *
153
     * ```php
154
     * use nystudio107\retour\services\Redirects;
155
     * use nystudio107\retour\events\ResolveRedirectEvent;
156
     *
157
     * Event::on(Redirects::class,
158
     *     Redirects::EVENT_AFTER_RESOLVE_REDIRECT,
159
     *     function(ResolveRedirectEvent $event) {
160
     *         // potentially set $event->redirectDestUrl;
161
     *     }
162
     * );
163
     * ```
164
     */
165
    public const EVENT_AFTER_RESOLVE_REDIRECT = 'afterResolveRedirect';
166
167
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
168
     * @event RedirectResolvedEvent The event that is triggered once Retour has resolved
169
     *        a redirect. [[RedirectResolvedEvent::redirect]] will be set to the redirect
170
     *        that was resolved. You may set [[RedirectResolvedEvent::redirectDestUrl]] to
171
     *        to a different URL that it should redirect to, or leave it null if the
172
     *        redirect should happen as resolved.
173
     *
174
     * ```php
175
     * use nystudio107\retour\services\Redirects;
176
     * use nystudio107\retour\events\RedirectResolvedEvent;
177
     *
178
     * Event::on(Redirects::class,
179
     *     Redirects::EVENT_REDIRECT_RESOLVED,
180
     *     function(RedirectResolvedEvent $event) {
181
     *         // potentially set $event->redirectDestUrl;
182
     *     }
183
     * );
184
     * ```
185
     */
186
    public const EVENT_REDIRECT_RESOLVED = 'redirectResolved';
187
188
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
189
     * @var array A list of all the element ids for which the short links have been purged.
190
     */
191
    protected static array $purgedShortLinkElementIds = [];
192
193
194
    // Public Methods
195
    // =========================================================================
196
197
    /**
198
     * Handle 404s by looking for redirects
199
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
200
    public function handle404(): void
201
    {
202
        Craft::info(
203
            Craft::t(
204
                'retour',
205
                'A 404 exception occurred'
206
            ),
207
            __METHOD__
208
        );
209
        $request = Craft::$app->getRequest();
210
        // We only want site requests that are not live preview or console requests
211
        if ($request->getIsSiteRequest() && !$this->isPreview($request) && !$request->getIsConsoleRequest()) {
212
            // See if we should redirect
213
            try {
214
                $fullUrl = urldecode($request->getAbsoluteUrl());
215
                $pathOnly = urldecode($request->getUrl());
216
            } catch (InvalidConfigException $e) {
217
                Craft::error(
218
                    $e->getMessage(),
219
                    __METHOD__
220
                );
221
                $pathOnly = '';
222
                $fullUrl = '';
223
            }
224
            // Stash the $pathOnly for use when incrementing the statistics
225
            $originalPathOnly = $pathOnly;
226
            // Strip the query string if `alwaysStripQueryString` is set
227
            if (Retour::$settings->alwaysStripQueryString) {
228
                $fullUrl = UrlHelper::stripQueryString($fullUrl);
229
                $pathOnly = UrlHelper::stripQueryString($pathOnly);
230
            }
231
            Craft::info(
232
                Craft::t(
233
                    'retour',
234
                    '404 full URL: {fullUrl}, 404 path only: {pathOnly}',
235
                    ['fullUrl' => $fullUrl, 'pathOnly' => $pathOnly]
236
                ),
237
                __METHOD__
238
            );
239
            if (!$this->excludeUri($pathOnly)) {
240
                // Redirect if we find a match, otherwise let Craft handle it
241
                $redirect = $this->findRedirectMatch($fullUrl, $pathOnly);
242
                // If the redirect wasn't found, look for it without the Site-defined prefix
243
                if ($redirect === null) {
244
                    // Strip out any site-defined baseUrl path prefixes
245
                    $pathOnly = UrlHelper::stripSitePathPrefix($pathOnly);
246
                    $redirect = $this->findRedirectMatch($fullUrl, $pathOnly);
247
                }
248
                if (!$this->doRedirect($fullUrl, $pathOnly, $redirect) && !Retour::$settings->alwaysStripQueryString) {
249
                    // Try it again without the query string
250
                    $fullUrl = UrlHelper::stripQueryString($fullUrl);
251
                    $pathOnly = UrlHelper::stripQueryString($pathOnly);
252
                    $redirect = $this->findRedirectMatch($fullUrl, $pathOnly);
253
                    $this->doRedirect($fullUrl, $pathOnly, $redirect);
254
                }
255
                // Increment the stats
256
                Retour::$plugin->statistics->incrementStatistics($originalPathOnly, false);
0 ignored issues
show
Bug introduced by
The method incrementStatistics() does not exist on null. ( Ignorable by Annotation )

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

256
                Retour::$plugin->statistics->/** @scrutinizer ignore-call */ 
257
                                             incrementStatistics($originalPathOnly, false);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
257
            }
258
        }
259
    }
260
261
    /**
262
     * Return whether this is a preview request of any kind
263
     *
264
     * @param $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
265
     * @return bool
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
266
     */
267
    public function isPreview($request): bool
268
    {
269
        $isPreview = $request->getIsPreview();
270
        $isLivePreview = $request->getIsLivePreview();
271
272
        return ($isPreview || $isLivePreview);
273
    }
274
275
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
276
     * @param $uri
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
277
     *
278
     * @return bool
279
     */
280
    public function excludeUri($uri): bool
281
    {
282
        $uri = '/' . ltrim($uri, '/');
283
        if (!empty(Retour::$settings->excludePatterns)) {
284
            foreach (Retour::$settings->excludePatterns as $excludePattern) {
285
                if (empty($excludePattern['pattern'])) {
286
                    continue;
287
                }
288
                $pattern = '`' . $excludePattern['pattern'] . '`i';
289
                try {
290
                    if (preg_match($pattern, $uri) === 1) {
291
                        Craft::info(
292
                            Craft::t(
293
                                'retour',
294
                                'Excluded URI: {uri} due to match of pattern: {pattern}',
295
                                ['uri' => $uri, 'pathOnly' => $pattern]
296
                            ),
297
                            __METHOD__
298
                        );
299
300
                        return true;
301
                    }
302
                } catch (\Exception $e) {
303
                    // That's fine
304
                    Craft::error('Invalid exclude URI Regex: ' . $pattern, __METHOD__);
305
                }
306
            }
307
        }
308
309
        return false;
310
    }
311
312
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
313
     * @param string $fullUrl
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
314
     * @param string $pathOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
315
     * @param int|null $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
316
     *
317
     * @return bool|array|null
318
     */
319
    public function findRedirectMatch(string $fullUrl, string $pathOnly, $siteId = null): bool|array|null
320
    {
321
        // Get the current site
322
        if ($siteId === null) {
323
            $currentSite = Craft::$app->getSites()->currentSite;
324
            if ($currentSite) {
325
                $siteId = $currentSite->id;
326
            } else {
327
                $primarySite = Craft::$app->getSites()->primarySite;
328
                $siteId = $primarySite->id;
329
            }
330
        }
331
        // Try getting the full URL redirect from the cache
332
        $redirect = $this->getRedirectFromCache($fullUrl, $siteId);
333
        if ($redirect) {
334
            $this->incrementRedirectHitCount($redirect);
335
            $this->saveRedirectToCache($fullUrl, $redirect);
336
337
            return $redirect;
338
        }
339
        // Try getting the path only redirect from the cache
340
        $redirect = $this->getRedirectFromCache($pathOnly, $siteId);
341
        if ($redirect) {
342
            $this->incrementRedirectHitCount($redirect);
343
            $this->saveRedirectToCache($pathOnly, $redirect);
344
345
            return $redirect;
346
        }
347
348
        $redirect = $this->getStaticRedirect($fullUrl, $pathOnly, $siteId, true);
349
        if ($redirect) {
350
            $this->incrementRedirectHitCount($redirect);
351
            $this->saveRedirectToCache($pathOnly, $redirect);
352
353
            return $redirect;
354
        }
355
356
        // Resolve static redirects
357
        $redirects = $this->getAllRegExRedirects(null, $siteId, true);
358
        $redirect = $this->resolveRedirect($fullUrl, $pathOnly, $redirects, $siteId);
359
        if ($redirect) {
360
            return $redirect;
361
        }
362
363
        return null;
364
    }
365
366
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
367
     * @param string $url
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
368
     * @param int $siteId
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...
369
     *
370
     * @return bool|array
371
     */
372
    public function getRedirectFromCache(string $url, int $siteId = 0): bool|array
373
    {
374
        $cache = Craft::$app->getCache();
375
        $cacheKey = $this::CACHE_KEY . md5($url) . $siteId;
376
        $redirect = $cache->get($cacheKey);
377
        Craft::info(
378
            Craft::t(
379
                'retour',
380
                'Cached redirect hit for {url}',
381
                ['url' => $url]
382
            ),
383
            __METHOD__
384
        );
385
386
        return $redirect;
387
    }
388
389
    /**
390
     * Increment the retour_static_redirects record
391
     *
392
     * @param $redirectConfig
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
393
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
394
    public function incrementRedirectHitCount(&$redirectConfig): void
395
    {
396
        if ($redirectConfig !== null) {
397
            $db = Craft::$app->getDb();
398
            $redirectConfig['hitCount']++;
399
            $redirectConfig['hitLastTime'] = Db::prepareDateForDb(new DateTime());
400
            Craft::debug(
401
                Craft::t(
402
                    'retour',
403
                    'Incrementing statistics for: {redirect}',
404
                    ['redirect' => print_r($redirectConfig, true)]
405
                ),
406
                __METHOD__
407
            );
408
            // Update the existing record
409
            try {
410
                $rowsAffected = $db->createCommand()->update(
411
                    '{{%retour_static_redirects}}',
412
                    [
413
                        'hitCount' => $redirectConfig['hitCount'],
414
                        'hitLastTime' => $redirectConfig['hitLastTime'],
415
                    ],
416
                    [
417
                        'id' => $redirectConfig['id'],
418
                    ]
419
                )->execute();
420
                Craft::debug('Rows affected: ' . $rowsAffected, __METHOD__);
421
            } catch (\Exception $e) {
422
                Craft::error($e->getMessage(), __METHOD__);
423
            }
424
        }
425
    }
426
427
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
428
     * @param string $url
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
429
     * @param array $redirect
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
430
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
431
    public function saveRedirectToCache(string $url, array $redirect): void
432
    {
433
        $cache = Craft::$app->getCache();
434
        // Get the current site id
435
        $sites = Craft::$app->getSites();
436
        try {
437
            $siteId = $sites->getCurrentSite()->id;
438
        } catch (SiteNotFoundException $e) {
439
            $siteId = 1;
440
        }
441
        $cacheKey = $this::CACHE_KEY . md5($url) . $siteId;
442
        // Create the dependency tags
443
        $dependency = new TagDependency([
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...
444
            'tags' => [
445
                $this::GLOBAL_REDIRECTS_CACHE_TAG,
446
                $this::GLOBAL_REDIRECTS_CACHE_TAG . $siteId,
447
            ],
448
        ]);
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...
449
        $cache->set($cacheKey, $redirect, Retour::$cacheDuration, $dependency);
450
        Craft::info(
451
            Craft::t(
452
                'retour',
453
                'Cached redirect saved for {url}',
454
                ['url' => $url]
455
            ),
456
            __METHOD__
457
        );
458
    }
459
460
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $enabledOnly should have a doc-comment as per coding-style.
Loading history...
461
     * @param string $fullUrl
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
462
     * @param string $pathOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
463
     * @param $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
464
     * @return mixed|null
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
465
     */
466
    public function getStaticRedirect(string $fullUrl, string $pathOnly, $siteId, bool $enabledOnly = false)
467
    {
468
        $result = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
469
        // Throw the Redirects::EVENT_BEFORE_RESOLVE_REDIRECT event
470
        $event = new ResolveRedirectEvent([
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...
471
            'fullUrl' => $fullUrl,
472
            'pathOnly' => $pathOnly,
473
            'redirectDestUrl' => null,
474
            'redirectHttpCode' => 301,
475
            'siteId' => $siteId,
476
        ]);
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...
477
        $this->trigger(self::EVENT_BEFORE_RESOLVE_REDIRECT, $event);
478
        if ($event->redirectDestUrl !== null) {
479
            return $this->resolveEventRedirect($event);
480
        }
481
        // Query for the static redirect
482
        $staticCondition = ['redirectMatchType' => 'exactmatch'];
483
        $siteCondition = [
484
            'or',
485
            ['siteId' => $siteId],
486
            ['siteId' => null],
487
        ];
488
        $pathCondition = [
489
            'or',
490
            ['and',
491
                ['redirectSrcMatch' => 'pathonly'],
492
                ['redirectSrcUrlParsed' => TextHelper::cleanupText($pathOnly)],
493
            ],
494
            ['and',
495
                ['redirectSrcMatch' => 'fullurl'],
496
                ['redirectSrcUrlParsed' => TextHelper::cleanupText($fullUrl)],
497
            ],
498
        ];
499
500
        $query = (new Query())
501
            ->from('{{%retour_static_redirects}}')
502
            ->where(['and',
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...
503
                $staticCondition,
504
                $pathCondition,
505
                $siteCondition,
506
            ])
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...
507
            ->limit(1);
508
509
        if ($enabledOnly) {
510
            $query->andWhere(['enabled' => 1]);
511
        }
512
        $result = $query->one();
513
        if ($result) {
514
            // Figure out what type of source matching to do
515
            $redirectSrcMatch = $result['redirectSrcMatch'] ?? 'pathonly';
516
            switch ($redirectSrcMatch) {
517
                case 'pathonly':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
518
                    $url = $pathOnly;
519
                    break;
520
                case 'fullurl':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
521
                    $url = $fullUrl;
522
                    break;
523
                default:
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
524
                    $url = $pathOnly;
525
                    break;
526
            }
527
            // Throw the Redirects::EVENT_REDIRECT_RESOLVED event
528
            $event = new RedirectResolvedEvent([
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...
529
                'fullUrl' => $fullUrl,
530
                'pathOnly' => $pathOnly,
531
                'redirectDestUrl' => null,
532
                'redirectHttpCode' => 301,
533
                'redirect' => $result,
534
                'siteId' => $siteId,
535
            ]);
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...
536
            $this->trigger(self::EVENT_REDIRECT_RESOLVED, $event);
537
            if ($event->redirectDestUrl !== null) {
538
                return $this->resolveEventRedirect($event, $url, $result);
539
            }
540
541
            return $result;
542
        }
543
544
        // Throw the Redirects::EVENT_AFTER_RESOLVE_REDIRECT event
545
        $event = new ResolveRedirectEvent([
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...
546
            'fullUrl' => $fullUrl,
547
            'pathOnly' => $pathOnly,
548
            'redirectDestUrl' => null,
549
            'redirectHttpCode' => 301,
550
            'siteId' => $siteId,
551
        ]);
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...
552
        $this->trigger(self::EVENT_AFTER_RESOLVE_REDIRECT, $event);
553
        if ($event->redirectDestUrl !== null) {
554
            return $this->resolveEventRedirect($event);
555
        }
556
        Craft::info(
557
            Craft::t(
558
                'retour',
559
                'Not handled-> full URL: {fullUrl}, path only: {pathOnly}',
560
                ['fullUrl' => $fullUrl, 'pathOnly' => $pathOnly]
561
            ),
562
            __METHOD__
563
        );
564
565
        return $result;
566
    }
567
568
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $enabledOnly should have a doc-comment as per coding-style.
Loading history...
569
     * @param null|int $limit
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
570
     * @param int|null $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
571
     *
572
     * @return array All of the regex match redirects
573
     */
574
    public function getAllRegExRedirects(int $limit = null, int $siteId = null, bool $enabledOnly = false): array
575
    {
576
        return $this->getRedirectsByMatchType($limit, $siteId, 'regexmatch', $enabledOnly);
577
    }
578
579
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $enabledOnly should have a doc-comment as per coding-style.
Loading history...
580
     * @param null|int $limit
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
581
     * @param int|null $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
582
     *
583
     * @return array All of the regex match redirects
584
     */
585
    public function getAllExactMatchRedirects(int $limit = null, int $siteId = null, bool $enabledOnly = false): array
586
    {
587
        return $this->getRedirectsByMatchType($limit, $siteId, 'exactmatch', $enabledOnly);
588
    }
589
590
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
591
     * @param int|null $limit
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
592
     * @param int|null $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
593
     *
594
     * @return array All of the statistics
595
     */
596
    public function getAllStaticRedirects(int $limit = null, int $siteId = null): array
597
    {
598
        // Query the db table
599
        $query = (new Query())
600
            ->from(['{{%retour_static_redirects}}'])
601
            ->orderBy('redirectMatchType ASC, priority ASC');
602
        if ($siteId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $siteId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
603
            $query
604
                ->where(['siteId' => $siteId])
605
                ->orWhere(['siteId' => null]);
606
        }
607
        if ($limit) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $limit of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
608
            $query->limit($limit);
609
        }
610
        return $query->all();
611
    }
612
613
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
614
     * @param string $fullUrl
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
615
     * @param string $pathOnly
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
616
     * @param array $redirects
0 ignored issues
show
Coding Style introduced by