Passed
Push — v3 ( 0d1d42...e1dcac )
by Andrew
32:56 queued 25:33
created

Retour::installGlobalEventListeners()   F

Complexity

Conditions 26
Paths 6

Size

Total Lines 176
Code Lines 106

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 702

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 106
c 4
b 0
f 0
dl 0
loc 176
ccs 0
cts 107
cp 0
rs 3.3333
cc 26
nc 6
nop 0
crap 702

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Retour plugin for Craft CMS 3.x
4
 *
5
 * Retour allows you to intelligently redirect legacy URLs, so that you don't
6
 * lose SEO value when rebuilding & restructuring a website
7
 *
8
 * @link      https://nystudio107.com/
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
9
 * @copyright Copyright (c) 2018 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
10
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
11
12
namespace nystudio107\retour;
13
14
use Craft;
15
use craft\base\Element;
16
use craft\base\Plugin;
17
use craft\events\ElementEvent;
18
use craft\events\ExceptionEvent;
19
use craft\events\PluginEvent;
20
use craft\events\RegisterCacheOptionsEvent;
21
use craft\events\RegisterComponentTypesEvent;
22
use craft\events\RegisterGqlQueriesEvent;
23
use craft\events\RegisterGqlSchemaComponentsEvent;
24
use craft\events\RegisterGqlTypesEvent;
25
use craft\events\RegisterUrlRulesEvent;
26
use craft\events\RegisterUserPermissionsEvent;
27
use craft\helpers\ArrayHelper;
28
use craft\helpers\ElementHelper;
29
use craft\helpers\UrlHelper;
30
use craft\services\Dashboard;
31
use craft\services\Elements;
32
use craft\services\Fields;
33
use craft\services\Gql;
34
use craft\services\Plugins;
35
use craft\services\UserPermissions;
36
use craft\utilities\ClearCaches;
37
use craft\web\ErrorHandler;
38
use craft\web\twig\variables\CraftVariable;
39
use craft\web\UrlManager;
40
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...
41
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...
42
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...
43
use nystudio107\pluginvite\services\VitePluginService;
44
use nystudio107\retour\assetbundles\retour\RetourAsset;
45
use nystudio107\retour\fields\ShortLink as ShortLinkField;
46
use nystudio107\retour\gql\interfaces\RetourInterface;
47
use nystudio107\retour\gql\queries\RetourQuery;
48
use nystudio107\retour\listeners\GetCraftQLSchema;
49
use nystudio107\retour\models\Settings;
50
use nystudio107\retour\services\Events;
51
use nystudio107\retour\services\Redirects;
52
use nystudio107\retour\services\Statistics;
53
use nystudio107\retour\variables\RetourVariable;
54
use nystudio107\retour\widgets\RetourWidget;
55
use yii\base\Event;
56
use yii\web\HttpException;
57
58
/** @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
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...
59
60
/**
61
 * Class Retour
62
 *
63
 * @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...
64
 * @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...
65
 * @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...
66
 *
67
 * @property Events $events
68
 * @property Redirects $redirects
69
 * @property Statistics $statistics
70
 * @property VitePluginService $vite
71
 */
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...
72
class Retour extends Plugin
73
{
74
    // Constants
75
    // =========================================================================
76
77
    const DEVMODE_CACHE_DURATION = 30;
78
79
    // Static Properties
80
    // =========================================================================
81
82
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
83
     * @var Retour
84
     */
85
    public static $plugin;
86
87
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
88
     * @var Settings
89
     */
90
    public static $settings;
91
92
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
93
     * @var int
94
     */
95
    public static $cacheDuration;
96
97
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
98
     * @var HttpException
99
     */
100
    public static $currentException;
101
102
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
103
     * @var bool
104
     */
105
    public static $craft31 = false;
106
107
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
108
     * @var bool
109
     */
110
    public static $craft32 = false;
111
112
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
113
     * @var bool
114
     */
115
    public static $craft33 = false;
116
117
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
118
     * @var bool
119
     */
120
    public static $craft35 = false;
121
122
    // Static Methods
123
    // =========================================================================
124
125
    /**
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 $config 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...
126
     * @inheritdoc
127
     */
128
    public function __construct($id, $parent = null, array $config = [])
129
    {
130
        // Merge in the passed config, so it our config can be overridden by Plugins::pluginConfigs['vite']
131
        // ref: https://github.com/craftcms/cms/issues/1989
132
        $config = ArrayHelper::merge([
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...
133
            'components' => [
134
                'events' => Events::class,
135
                'redirects' => Redirects::class,
136
                'statistics' => Statistics::class,
137
                // Register the vite service
138
                'vite' => [
139
                    'class' => VitePluginService::class,
140
                    'assetClass' => RetourAsset::class,
141
                    'useDevServer' => true,
142
                    'devServerPublic' => 'http://localhost:3001',
143
                    'serverPublic' => 'http://localhost:8000',
144
                    'errorEntry' => 'src/js/Retour.js',
145
                    'devServerInternal' => 'http://craft-retour-buildchain:3001',
146
                    'checkDevServer' => true,
147
                ],
148
            ]
149
        ], $config);
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...
150
151
        parent::__construct($id, $parent, $config);
152
    }
153
154
    // Public Properties
155
    // =========================================================================
156
157
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
158
     * @var string
159
     */
160
    public $schemaVersion = '3.0.10';
161
162
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
163
     * @var bool
164
     */
165
    public $hasCpSection = true;
166
167
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
168
     * @var bool
169
     */
170
    public $hasCpSettings = true;
171
172
    // Public Methods
173
    // =========================================================================
174
175
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
176
     * @inheritdoc
177
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
178
    public function init()
179
    {
180
        parent::init();
181
        self::$plugin = $this;
182
        // Initialize properties
183
        self::$settings = $this->getSettings();
184
        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...
185
        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...
186
        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...
187
        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...
188
        $this->name = self::$settings->pluginName;
189
        self::$cacheDuration = Craft::$app->getConfig()->getGeneral()->devMode
190
            ? $this::DEVMODE_CACHE_DURATION
191
            : null;
192
        // Handle any console commands
193
        $request = Craft::$app->getRequest();
194
        if ($request->getIsConsoleRequest()) {
195
            $this->controllerNamespace = 'nystudio107\retour\console\controllers';
196
        }
197
        // Install our event listeners
198
        $this->installEventListeners();
199
        // Log that Retour has been loaded
200
        Craft::info(
201
            Craft::t(
202
                'retour',
203
                '{name} plugin loaded',
204
                ['name' => $this->name]
205
            ),
206
            __METHOD__
207
        );
208
    }
209
210
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
211
     * @inheritdoc
212
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
213
    public function getSettingsResponse()
214
    {
215
        // Just redirect to the plugin settings page
216
        Craft::$app->getResponse()->redirect(UrlHelper::cpUrl('retour/settings'));
217
    }
218
219
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
220
     * @inheritdoc
221
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
222
    public function getCpNavItem()
223
    {
224
        $subNavs = [];
225
        $navItem = parent::getCpNavItem();
226
        $currentUser = Craft::$app->getUser()->getIdentity();
227
        // Only show sub-navs the user has permission to view
228
        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

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

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