Passed
Push — v3 ( 53e94e...6511ed )
by Andrew
40:04 queued 16:36
created

Retour::getAllElementUris()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 14
dl 0
loc 23
ccs 0
cts 15
cp 0
rs 9.4888
c 1
b 0
f 0
cc 5
nc 2
nop 1
crap 30
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;
13
14
use craft\events\RegisterGqlSchemaComponentsEvent;
15
use nystudio107\retour\assetbundles\retour\RetourAsset;
16
use nystudio107\retour\gql\interfaces\RetourInterface;
17
use nystudio107\retour\gql\queries\RetourQuery;
18
use nystudio107\retour\listeners\GetCraftQLSchema;
19
use nystudio107\retour\models\Settings;
20
use nystudio107\retour\services\Events;
21
use nystudio107\retour\services\Redirects;
22
use nystudio107\retour\services\Statistics;
23
use nystudio107\retour\variables\RetourVariable;
24
use nystudio107\retour\widgets\RetourWidget;
25
26
use nystudio107\pluginmanifest\services\ManifestService;
27
28
use Craft;
29
use craft\base\Element;
30
use craft\base\Plugin;
31
use craft\events\ElementEvent;
32
use craft\events\ExceptionEvent;
33
use craft\events\PluginEvent;
34
use craft\events\RegisterCacheOptionsEvent;
35
use craft\events\RegisterComponentTypesEvent;
36
use craft\events\RegisterGqlQueriesEvent;
37
use craft\events\RegisterGqlTypesEvent;
38
use craft\events\RegisterUrlRulesEvent;
39
use craft\events\RegisterUserPermissionsEvent;
40
use craft\helpers\ElementHelper;
41
use craft\helpers\UrlHelper;
42
use craft\services\Elements;
43
use craft\services\Dashboard;
44
use craft\services\Gql;
45
use craft\services\Plugins;
46
use craft\services\UserPermissions;
47
use craft\utilities\ClearCaches;
48
use craft\web\ErrorHandler;
49
use craft\web\twig\variables\CraftVariable;
50
use craft\web\UrlManager;
51
52
use yii\base\Event;
53
use yii\web\HttpException;
54
55
use markhuot\CraftQL\Builders\Schema;
0 ignored issues
show
Bug introduced by
The type markhuot\CraftQL\Builders\Schema 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...
56
use markhuot\CraftQL\CraftQL;
0 ignored issues
show
Bug introduced by
The type markhuot\CraftQL\CraftQL 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...
57
use markhuot\CraftQL\Events\AlterSchemaFields;
0 ignored issues
show
Bug introduced by
The type markhuot\CraftQL\Events\AlterSchemaFields 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...
58
59
/** @noinspection MissingPropertyAnnotationsInspection */
0 ignored issues
show
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
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...
60
61
/**
62
 * Class Retour
63
 *
64
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
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
The tag in position 1 should be the @package tag
Loading history...
65
 * @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...
66
 * @since     3.0.0
0 ignored issues
show
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
67
 *
68
 * @property Events             $events
69
 * @property Redirects          $redirects
70
 * @property Statistics         $statistics
71
 * @property ManifestService    $manifest
72
 */
0 ignored issues
show
Coding Style introduced by
Missing @link tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @category tag in class comment
Loading history...
73
class Retour extends Plugin
74
{
75
    // Constants
76
    // =========================================================================
77
78
    const DEVMODE_CACHE_DURATION = 30;
79
80
    // Static Properties
81
    // =========================================================================
82
83
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
84
     * @var Retour
85
     */
86
    public static $plugin;
87
88
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
89
     * @var Settings
90
     */
91
    public static $settings;
92
93
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
94
     * @var int
95
     */
96
    public static $cacheDuration;
97
98
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
99
     * @var HttpException
100
     */
101
    public static $currentException;
102
103
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
104
     * @var bool
105
     */
106
    public static $craft31 = false;
107
108
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
109
     * @var bool
110
     */
111
    public static $craft32 = false;
112
113
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
114
     * @var bool
115
     */
116
    public static $craft33 = false;
117
118
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
119
     * @var bool
120
     */
121
    public static $craft35 = false;
122
123
    // Static Methods
124
    // =========================================================================
125
126
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $id should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $parent should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $config should have a doc-comment as per coding-style.
Loading history...
127
     * @inheritdoc
128
     */
129
    public function __construct($id, $parent = null, array $config = [])
130
    {
131
        $config['components'] = [
132
            'events' => Events::class,
133
            'redirects' => Redirects::class,
134
            'statistics' => Statistics::class,
135
            // Register the manifest service
136
            'manifest' => [
137
                'class' => ManifestService::class,
138
                'assetClass' => RetourAsset::class,
139
                'devServerManifestPath' => 'http://craft-retour-buildchain:8080/',
140
                'devServerPublicPath' => 'http://craft-retour-buildchain:8080/',
141
            ]
142
        ];
143
144
        parent::__construct($id, $parent, $config);
145
    }
146
147
    // Public Properties
148
    // =========================================================================
149
150
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
151
     * @var string
152
     */
153
    public $schemaVersion = '3.0.10';
154
155
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
156
     * @var bool
157
     */
158
    public $hasCpSection = true;
159
160
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
161
     * @var bool
162
     */
163
    public $hasCpSettings = true;
164
165
    // Public Methods
166
    // =========================================================================
167
168
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
169
     * @inheritdoc
170
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
171
    public function init()
172
    {
173
        parent::init();
174
        self::$plugin = $this;
175
        // Initialize properties
176
        self::$settings = $this->getSettings();
177
        self::$craft31 = version_compare(Craft::$app->getVersion(), '3.1', '>=');
0 ignored issues
show
Documentation Bug introduced by
It seems like version_compare(Craft::a...Version(), '3.1', '>=') can also be of type integer. However, the property $craft31 is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
178
        self::$craft32 = version_compare(Craft::$app->getVersion(), '3.2', '>=');
0 ignored issues
show
Documentation Bug introduced by
It seems like version_compare(Craft::a...Version(), '3.2', '>=') can also be of type integer. However, the property $craft32 is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
179
        self::$craft33 = version_compare(Craft::$app->getVersion(), '3.3', '>=');
0 ignored issues
show
Documentation Bug introduced by
It seems like version_compare(Craft::a...Version(), '3.3', '>=') can also be of type integer. However, the property $craft33 is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
180
        self::$craft35 = version_compare(Craft::$app->getVersion(), '3.5', '>=');
0 ignored issues
show
Documentation Bug introduced by
It seems like version_compare(Craft::a...Version(), '3.5', '>=') can also be of type integer. However, the property $craft35 is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
181
        $this->name = self::$settings->pluginName;
182
        self::$cacheDuration = Craft::$app->getConfig()->getGeneral()->devMode
183
            ? $this::DEVMODE_CACHE_DURATION
184
            : null;
185
        // Handle any console commands
186
        $request = Craft::$app->getRequest();
187
        if ($request->getIsConsoleRequest()) {
188
            $this->controllerNamespace = 'nystudio107\retour\console\controllers';
189
        }
190
        // Install our event listeners
191
        $this->installEventListeners();
192
        // Log that Retour has been loaded
193
        Craft::info(
194
            Craft::t(
195
                'retour',
196
                '{name} plugin loaded',
197
                ['name' => $this->name]
198
            ),
199
            __METHOD__
200
        );
201
    }
202
203
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
204
     * @inheritdoc
205
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
206
    public function getSettingsResponse()
207
    {
208
        // Just redirect to the plugin settings page
209
        Craft::$app->getResponse()->redirect(UrlHelper::cpUrl('retour/settings'));
210
    }
211
212
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
213
     * @inheritdoc
214
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
215
    public function getCpNavItem()
216
    {
217
        $subNavs = [];
218
        $navItem = parent::getCpNavItem();
219
        $currentUser = Craft::$app->getUser()->getIdentity();
220
        // Only show sub-navs the user has permission to view
221
        if ($currentUser->can('retour:dashboard')) {
0 ignored issues
show
Bug introduced by
The method can() does not exist on yii\web\IdentityInterface. It seems like you code against a sub-type of yii\web\IdentityInterface such as craft\elements\User. ( Ignorable by Annotation )

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

221
        if ($currentUser->/** @scrutinizer ignore-call */ can('retour:dashboard')) {
Loading history...
222
            $subNavs['dashboard'] = [
223
                'label' => 'Dashboard',
224
                'url' => 'retour/dashboard',
225
            ];
226
        }
227
        if ($currentUser->can('retour:redirects')) {
228
            $subNavs['redirects'] = [
229
                'label' => 'Redirects',
230
                'url' => 'retour/redirects',
231
            ];
232
        }
233
        $editableSettings = true;
234
        $general = Craft::$app->getConfig()->getGeneral();
235
        if (self::$craft31 && !$general->allowAdminChanges) {
236
            $editableSettings = false;
237
        }
238
        if ($currentUser->can('retour:settings') && $editableSettings) {
239
            $subNavs['settings'] = [
240
                'label' => 'Settings',
241
                'url' => 'retour/settings',
242
            ];
243
        }
244
        // Retour doesn't really have an index page, so if the user can't access any sub nav items, we probably shouldn't show the main sub nav item either
245
        if (empty($subNavs)) {
246
            return null;
247
        }
248
        // A single sub nav item is redundant
249
        if (count($subNavs) === 1) {
250
            $subNavs = [];
251
        }
252
        $navItem = array_merge($navItem, [
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...
253
            'subnav' => $subNavs,
254
        ]);
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...
255
256
        return $navItem;
257
    }
258
259
    /**
260
     * Clear all the caches!
261
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
262
    public function clearAllCaches()
263
    {
264
        // Clear all of Retour's caches
265
        self::$plugin->redirects->invalidateCaches();
266
    }
267
268
    // Protected Methods
269
    // =========================================================================
270
271
    /**
272
     * Determine whether our table schema exists or not; this is needed because
273
     * migrations such as the install migration and base_install migration may
274
     * not have been run by the time our init() method has been called
275
     *
276
     * @return bool
277
     */
278
    protected function tableSchemaExists(): bool
279
    {
280
        return (Craft::$app->db->schema->getTableSchema('{{%retour_redirects}}') !== null);
281
    }
282
283
    /**
284
     * Install our event listeners.
285
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
286
    protected function installEventListeners()
287
    {
288
        // Install our event listeners only if our table schema exists
289
        if ($this->tableSchemaExists()) {
290
            $request = Craft::$app->getRequest();
291
            // Add in our event listeners that are needed for every request
292
            $this->installGlobalEventListeners();
293
            // Install only for non-console site requests
294
            if ($request->getIsSiteRequest() && !$request->getIsConsoleRequest()) {
295
                $this->installSiteEventListeners();
296
            }
297
            // Install only for non-console Control Panel requests
298
            if ($request->getIsCpRequest() && !$request->getIsConsoleRequest()) {
299
                $this->installCpEventListeners();
300
            }
301
        }
302
        // Handler: ClearCaches::EVENT_REGISTER_CACHE_OPTIONS
303
        Event::on(
304
            ClearCaches::class,
305
            ClearCaches::EVENT_REGISTER_CACHE_OPTIONS,
306
            function (RegisterCacheOptionsEvent $event) {
307
                Craft::debug(
308
                    'ClearCaches::EVENT_REGISTER_CACHE_OPTIONS',
309
                    __METHOD__
310
                );
311
                // Register our Control Panel routes
312
                $event->options = array_merge(
313
                    $event->options,
314
                    $this->customAdminCpCacheOptions()
315
                );
316
            }
317
        );
318
        // Handler: EVENT_AFTER_INSTALL_PLUGIN
319
        Event::on(
320
            Plugins::class,
321
            Plugins::EVENT_AFTER_INSTALL_PLUGIN,
322
            function (PluginEvent $event) {
323
                if ($event->plugin === $this) {
324
                    // Invalidate our caches after we've been installed
325
                    $this->clearAllCaches();
326
                    // Send them to our welcome screen
327
                    $request = Craft::$app->getRequest();
328
                    if ($request->isCpRequest) {
329
                        Craft::$app->getResponse()->redirect(UrlHelper::cpUrl(
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...
330
                            'retour/dashboard',
331
                            [
332
                                'showWelcome' => true,
333
                            ]
334
                        ))->send();
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...
335
                    }
336
                }
337
            }
338
        );
339
    }
340
341
    /**
342
     * Install global event listeners for all request types
343
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
344
    protected function installGlobalEventListeners()
345
    {
346
        Event::on(
347
            CraftVariable::class,
348
            CraftVariable::EVENT_INIT,
349
            function (Event $event) {
350
                /** @var CraftVariable $variable */
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
The close comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
351
                $variable = $event->sender;
352
                $variable->set('retour', [
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...
353
                    'class' => RetourVariable::class,
354
                    'manifestService' => $this->manifest,
355
                ]);
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...
356
            }
357
        );
358
        // Handler: Elements::EVENT_BEFORE_SAVE_ELEMENT
359
        Event::on(
360
            Elements::class,
361
            Elements::EVENT_BEFORE_SAVE_ELEMENT,
362
            function (ElementEvent $event) {
363
                Craft::debug(
364
                    'Elements::EVENT_BEFORE_SAVE_ELEMENT',
365
                    __METHOD__
366
                );
367
                /** @var Element $element */
0 ignored issues
show
Coding Style introduced by
The close 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 open comment tag must be the only content on the line
Loading history...
368
                $element = $event->element;
369
                if ($element !== null && !$event->isNew && $element->getUrl() !== null && !$element->propagating) {
370
                    $checkElementSlug = true;
371
                    // If we're running Craft 3.2 or later, also check that isn't not a draft or revision
372
                    if (Retour::$craft32 && (
373
                            ElementHelper::isDraftOrRevision($element)
0 ignored issues
show
Coding Style introduced by
Multi-line IF statement not indented correctly; expected 24 spaces but found 28
Loading history...
Coding Style introduced by
Each line in a multi-line IF statement must begin with a boolean operator
Loading history...
374
                        )) {
0 ignored issues
show
Coding Style introduced by
Each line in a multi-line IF statement must begin with a boolean operator
Loading history...
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
375
                        $checkElementSlug = false;
376
                    }
377
                    // Only do this for elements that aren't new, pass $checkElementSlug, and the user
378
                    // has turned on the setting
379
                    if (self::$settings->createUriChangeRedirects && $checkElementSlug) {
380
                        // Make sure this isn't a transitioning temporary draft/revision and that it's
381
                        // not propagating to other sites
382
                        if (strpos($element->uri, '__temp_') === false && !$element->propagating) {
0 ignored issues
show
Bug introduced by
It seems like $element->uri can also be of type null; however, parameter $haystack of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

382
                        if (strpos(/** @scrutinizer ignore-type */ $element->uri, '__temp_') === false && !$element->propagating) {
Loading history...
383
                            Retour::$plugin->events->stashElementUris($element);
384
                        }
385
                    }
386
                }
387
            }
388
        );
389
        // Handler: Elements::EVENT_AFTER_SAVE_ELEMENT
390
        Event::on(
391
            Elements::class,
392
            Elements::EVENT_AFTER_SAVE_ELEMENT,
393
            function (ElementEvent $event) {
394
                Craft::debug(
395
                    'Elements::EVENT_AFTER_SAVE_ELEMENT',
396
                    __METHOD__
397
                );
398
                /** @var Element $element */
0 ignored issues
show
Coding Style introduced by
The close 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 open comment tag must be the only content on the line
Loading history...
399
                $element = $event->element;
400
                if ($element !== null && !$event->isNew && $element->getUrl() !== null) {
401
                    $checkElementSlug = true;
402
                    if (Retour::$craft32 && ElementHelper::isDraftOrRevision($element)) {
403
                        $checkElementSlug = false;
404
                    }
405
                    if (self::$settings->createUriChangeRedirects && $checkElementSlug) {
406
                        Retour::$plugin->events->handleElementUriChange($element);
407
                    }
408
                }
409
            }
410
        );
411
        // Handler: Plugins::EVENT_AFTER_LOAD_PLUGINS
412
        Event::on(
413
            Plugins::class,
414
            Plugins::EVENT_AFTER_LOAD_PLUGINS,
415
            function () {
416
                // Install these only after all other plugins have loaded
417
                $request = Craft::$app->getRequest();
418
                // Only respond to non-console site requests
419
                if ($request->getIsSiteRequest() && !$request->getIsConsoleRequest()) {
420
                    $this->handleSiteRequest();
421
                }
422
                // Respond to Control Panel requests
423
                if ($request->getIsCpRequest() && !$request->getIsConsoleRequest()) {
424
                    $this->handleAdminCpRequest();
425
                }
426
            }
427
        );
428
        if (self::$craft33) {
429
            // Handler: Gql::EVENT_REGISTER_GQL_TYPES
430
            Event::on(
431
                Gql::class,
432
                Gql::EVENT_REGISTER_GQL_TYPES,
433
                function (RegisterGqlTypesEvent $event) {
434
                    Craft::debug(
435
                        'Gql::EVENT_REGISTER_GQL_TYPES',
436
                        __METHOD__
437
                    );
438
                    $event->types[] = RetourInterface::class;
439
                }
440
            );
441
            // Handler: Gql::EVENT_REGISTER_GQL_QUERIES
442
            Event::on(
443
                Gql::class,
444
                Gql::EVENT_REGISTER_GQL_QUERIES,
445
                function (RegisterGqlQueriesEvent $event) {
446
                    Craft::debug(
447
                        'Gql::EVENT_REGISTER_GQL_QUERIES',
448
                        __METHOD__
449
                    );
450
                    $queries = RetourQuery::getQueries();
451
                    foreach ($queries as $key => $value) {
452
                        $event->queries[$key] = $value;
453
                    }
454
                }
455
            );
456
            if (self::$craft35) {
457
                // Handler: Gql::EVENT_REGISTER_SCHEMA_COMPONENTS
458
                Event::on(
459
                    Gql::class,
460
                    Gql::EVENT_REGISTER_GQL_SCHEMA_COMPONENTS,
461
                    function (RegisterGqlSchemaComponentsEvent $event) {
462
                        Craft::debug(
463
                            'Gql::EVENT_REGISTER_GQL_SCHEMA_COMPONENTS',
464
                            __METHOD__
465
                        );
466
                        $label = Craft::t('retour', 'Retour');
467
                        $event->queries[$label]['retour.all:read'] = ['label' => Craft::t('retour', 'Query Retour data')];
468
                    }
469
                );
470
            }
471
        }
472
        // CraftQL Support
473
        if (class_exists(CraftQL::class)) {
474
            Event::on(
475
                Schema::class,
476
                AlterSchemaFields::EVENT,
477
                [GetCraftQLSchema::class, 'handle']
478
            );
479
        }
480
    }
481
482
    /**
483
     * Install site event listeners for site requests only
484
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
485
    protected function installSiteEventListeners()
486
    {
487
        // Handler: UrlManager::EVENT_REGISTER_SITE_URL_RULES
488
        Event::on(
489
            UrlManager::class,
490
            UrlManager::EVENT_REGISTER_SITE_URL_RULES,
491
            function (RegisterUrlRulesEvent $event) {
492
                Craft::debug(
493
                    'UrlManager::EVENT_REGISTER_SITE_URL_RULES',
494
                    __METHOD__
495
                );
496
                // Register our Control Panel routes
497
                $event->rules = array_merge(
498
                    $event->rules,
499
                    $this->customFrontendRoutes()
500
                );
501
            }
502
        );
503
    }
504
505
    /**
506
     * Install site event listeners for Control Panel requests only
507
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
508
    protected function installCpEventListeners()
509
    {
510
        // Handler: Dashboard::EVENT_REGISTER_WIDGET_TYPES
511
        Event::on(
512
            Dashboard::class,
513
            Dashboard::EVENT_REGISTER_WIDGET_TYPES,
514
            function (RegisterComponentTypesEvent $event) {
515
                $event->types[] = RetourWidget::class;
516
            }
517
        );
518
        // Handler: UrlManager::EVENT_REGISTER_CP_URL_RULES
519
        Event::on(
520
            UrlManager::class,
521
            UrlManager::EVENT_REGISTER_CP_URL_RULES,
522
            function (RegisterUrlRulesEvent $event) {
523
                Craft::debug(
524
                    'UrlManager::EVENT_REGISTER_CP_URL_RULES',
525
                    __METHOD__
526
                );
527
                // Register our Control Panel routes
528
                $event->rules = array_merge(
529
                    $event->rules,
530
                    $this->customAdminCpRoutes()
531
                );
532
            }
533
        );
534
        // Handler: UserPermissions::EVENT_REGISTER_PERMISSIONS
535
        Event::on(
536
            UserPermissions::class,
537
            UserPermissions::EVENT_REGISTER_PERMISSIONS,
538
            function (RegisterUserPermissionsEvent $event) {
539
                Craft::debug(
540
                    'UserPermissions::EVENT_REGISTER_PERMISSIONS',
541
                    __METHOD__
542
                );
543
                // Register our custom permissions
544
                $event->permissions[Craft::t('retour', 'Retour')] = $this->customAdminCpPermissions();
545
            }
546
        );
547
    }
548
549
    /**
550
     * Handle site requests.  We do it only after we receive the event
551
     * EVENT_AFTER_LOAD_PLUGINS so that any pending db migrations can be run
552
     * before our event listeners kick in
553
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
554
    protected function handleSiteRequest()
555
    {
556
        // Handler: ErrorHandler::EVENT_BEFORE_HANDLE_EXCEPTION
557
        Event::on(
558
            ErrorHandler::class,
559
            ErrorHandler::EVENT_BEFORE_HANDLE_EXCEPTION,
560
            function (ExceptionEvent $event) {
561
                Craft::debug(
562
                    'ErrorHandler::EVENT_BEFORE_HANDLE_EXCEPTION',
563
                    __METHOD__
564
                );
565
                $exception = $event->exception;
566
                // If this is a Twig Runtime exception, use the previous one instead
567
                if ($exception instanceof \Twig\Error\RuntimeError &&
568
                    ($previousException = $exception->getPrevious()) !== null) {
0 ignored issues
show
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
Coding Style introduced by
Each line in a multi-line IF statement must begin with a boolean operator
Loading history...
569
                    $exception = $previousException;
570
                }
571
                // If this is a 404 error, see if we can handle it
572
                if ($exception instanceof HttpException && $exception->statusCode === 404) {
573
                    self::$currentException = $exception;
574
                    Retour::$plugin->redirects->handle404();
575
                }
576
            }
577
        );
578
    }
579
580
    /**
581
     * Handle Control Panel requests. We do it only after we receive the event
582
     * EVENT_AFTER_LOAD_PLUGINS so that any pending db migrations can be run
583
     * before our event listeners kick in
584
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
585
    protected function handleAdminCpRequest()
586
    {
587
    }
588
589
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
590
     * @inheritdoc
591
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
592
    protected function createSettingsModel()
593
    {
594
        return new Settings();
595
    }
596
597
    /**
598
     * Return the custom Control Panel routes
599
     *
600
     * @return array
601
     */
602
    protected function customAdminCpRoutes(): array
603
    {
604
        return [
605
            'retour' => '',
606
607
            'retour/redirects' => 'retour/redirects/redirects',
608
            'retour/redirects/<siteHandle:{handle}>' => 'retour/redirects/redirects',
609
610
            'retour/edit-redirect/<redirectId:\d+>' => 'retour/redirects/edit-redirect',
611
612
            'retour/add-redirect' => 'retour/redirects/edit-redirect',
613
            'retour/add-redirect/<siteId:\d+>' => 'retour/redirects/edit-redirect',
614
615
            'retour/dashboard' => 'retour/statistics/dashboard',
616
            'retour/dashboard/<siteHandle:{handle}>' => 'retour/statistics/dashboard',
617
618
            'retour/settings' => 'retour/settings/plugin-settings',
619
        ];
620
    }
621
622
    /**
623
     * Return the custom frontend routes
624
     *
625
     * @return array
626
     */
627
    protected function customFrontendRoutes(): array
628
    {
629
        return [
630
        ];
631
    }
632
633
    /**
634
     * Returns the custom Control Panel cache options.
635
     *
636
     * @return array
637
     */
638
    protected function customAdminCpCacheOptions(): array
639
    {
640
        return [
641
            [
642
                'key' => 'retour-redirect-caches',
643
                'label' => Craft::t('retour', 'Retour redirect caches'),
644
                'action' => [self::$plugin->redirects, 'invalidateCaches'],
645
            ],
646
        ];
647
    }
648
649
    /**
650
     * Returns the custom Control Panel user permissions.
651
     *
652
     * @return array
653
     */
654
    protected function customAdminCpPermissions(): array
655
    {
656
        return [
657
            'retour:dashboard' => [
658
                'label' => Craft::t('retour', 'Dashboard'),
659
            ],
660
            'retour:redirects' => [
661
                'label' => Craft::t('retour', 'Redirects'),
662
            ],
663
            'retour:settings' => [
664
                'label' => Craft::t('retour', 'Settings'),
665
            ],
666
        ];
667
    }
668
}
669