Passed
Push — v3 ( 932184...c18a4a )
by Andrew
16:41 queued 09:38
created

Retour::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 16
c 4
b 0
f 0
dl 0
loc 24
ccs 0
cts 5
cp 0
rs 9.7333
cc 1
nc 1
nop 3
crap 2
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;
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\ElementHelper;
28
use craft\helpers\UrlHelper;
29
use craft\services\Dashboard;
30
use craft\services\Elements;
31
use craft\services\Fields;
32
use craft\services\Gql;
33
use craft\services\Plugins;
34
use craft\services\UserPermissions;
35
use craft\utilities\ClearCaches;
36
use craft\web\ErrorHandler;
37
use craft\web\twig\variables\CraftVariable;
38
use craft\web\UrlManager;
39
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...
40
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...
41
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...
42
use nystudio107\retour\fields\ShortLink as ShortLinkField;
43
use nystudio107\retour\gql\interfaces\RetourInterface;
44
use nystudio107\retour\gql\queries\RetourQuery;
45
use nystudio107\retour\listeners\GetCraftQLSchema;
46
use nystudio107\retour\models\Settings;
47
use nystudio107\retour\services\ServicesTrait;
48
use nystudio107\retour\variables\RetourVariable;
49
use nystudio107\retour\widgets\RetourWidget;
50
use yii\base\Event;
51
use yii\web\HttpException;
52
53
/** @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...
54
55
/**
56
 * Class Retour
57
 *
58
 * @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...
59
 * @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...
60
 * @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...
61
 */
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...
62
class Retour extends Plugin
63
{
64
    // Traits
65
    // =========================================================================
66
67
    use ServicesTrait;
68
69
    // Constants
70
    // =========================================================================
71
72
    const DEVMODE_CACHE_DURATION = 30;
73
74
    // Static Properties
75
    // =========================================================================
76
77
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
78
     * @var Retour
79
     */
80
    public static $plugin;
81
82
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
83
     * @var Settings
84
     */
85
    public static $settings;
86
87
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
88
     * @var int
89
     */
90
    public static $cacheDuration;
91
92
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
93
     * @var HttpException
94
     */
95
    public static $currentException;
96
97
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
98
     * @var bool
99
     */
100
    public static $craft31 = false;
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 $craft32 = 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 $craft33 = 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 $craft35 = false;
116
117
    // Public Properties
118
    // =========================================================================
119
120
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
121
     * @var string
122
     */
123
    public $schemaVersion = '3.0.10';
124
125
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
126
     * @var bool
127
     */
128
    public $hasCpSection = true;
129
130
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
131
     * @var bool
132
     */
133
    public $hasCpSettings = true;
134
135
    // Public Methods
136
    // =========================================================================
137
138
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
139
     * @inheritdoc
140
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
141
    public function init()
142
    {
143
        parent::init();
144
        self::$plugin = $this;
145
        // Initialize properties
146
        self::$settings = $this->getSettings();
147
        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...
148
        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...
149
        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...
150
        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...
151
        $this->name = self::$settings->pluginName;
152
        self::$cacheDuration = Craft::$app->getConfig()->getGeneral()->devMode
153
            ? $this::DEVMODE_CACHE_DURATION
154
            : null;
155
        // Handle any console commands
156
        $request = Craft::$app->getRequest();
157
        if ($request->getIsConsoleRequest()) {
158
            $this->controllerNamespace = 'nystudio107\retour\console\controllers';
159
        }
160
        // Install our event listeners
161
        $this->installEventListeners();
162
        // Log that Retour has been loaded
163
        Craft::info(
164
            Craft::t(
165
                'retour',
166
                '{name} plugin loaded',
167
                ['name' => $this->name]
168
            ),
169
            __METHOD__
170
        );
171
    }
172
173
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
174
     * @inheritdoc
175
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
176
    public function getSettingsResponse()
177
    {
178
        // Just redirect to the plugin settings page
179
        Craft::$app->getResponse()->redirect(UrlHelper::cpUrl('retour/settings'));
180
    }
181
182
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
183
     * @inheritdoc
184
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
185
    public function getCpNavItem()
186
    {
187
        $subNavs = [];
188
        $navItem = parent::getCpNavItem();
189
        $currentUser = Craft::$app->getUser()->getIdentity();
190
        // Only show sub-navs the user has permission to view
191
        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

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

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