Passed
Push — v1 ( 601be5...b67f55 )
by Andrew
03:08
created

Webperf::getCpNavItem()   B

Complexity

Conditions 6
Paths 32

Size

Total Lines 45
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 30
dl 0
loc 45
rs 8.8177
c 0
b 0
f 0
cc 6
nc 32
nop 0
1
<?php
2
/**
3
 * Webperf plugin for Craft CMS 3.x
4
 *
5
 * Monitor the performance of your webpages through real-world user timing data
6
 *
7
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2019 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
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...
10
11
namespace nystudio107\webperf;
12
13
use nystudio107\webperf\base\CraftDataSample;
14
use nystudio107\webperf\log\ErrorsTarget;
15
use nystudio107\webperf\log\ProfileTarget;
16
use nystudio107\webperf\models\RecommendationDataSample;
17
use nystudio107\webperf\models\Settings;
18
use nystudio107\webperf\services\DataSamples as DataSamplesService;
19
use nystudio107\webperf\services\ErrorSamples as ErrorSamplesService;
20
use nystudio107\webperf\services\Beacons as BeaconsService;
21
use nystudio107\webperf\services\Recommendations as RecommendationsService;
22
use nystudio107\webperf\variables\WebperfVariable;
23
use nystudio107\webperf\widgets\Metrics as MetricsWidget;
24
25
use Craft;
0 ignored issues
show
Bug introduced by
The type Craft 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...
26
use craft\base\Plugin;
0 ignored issues
show
Bug introduced by
The type craft\base\Plugin 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...
27
use craft\services\Plugins;
0 ignored issues
show
Bug introduced by
The type craft\services\Plugins 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...
28
use craft\events\PluginEvent;
0 ignored issues
show
Bug introduced by
The type craft\events\PluginEvent 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...
29
use craft\events\RegisterComponentTypesEvent;
0 ignored issues
show
Bug introduced by
The type craft\events\RegisterComponentTypesEvent 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...
30
use craft\events\RegisterUserPermissionsEvent;
0 ignored issues
show
Bug introduced by
The type craft\events\RegisterUserPermissionsEvent 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...
31
use craft\events\RegisterUrlRulesEvent;
0 ignored issues
show
Bug introduced by
The type craft\events\RegisterUrlRulesEvent 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...
32
use craft\helpers\UrlHelper;
0 ignored issues
show
Bug introduced by
The type craft\helpers\UrlHelper 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...
33
use craft\services\Dashboard;
0 ignored issues
show
Bug introduced by
The type craft\services\Dashboard 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...
34
use craft\services\UserPermissions;
0 ignored issues
show
Bug introduced by
The type craft\services\UserPermissions 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...
35
use craft\web\Application;
0 ignored issues
show
Bug introduced by
The type craft\web\Application 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...
36
use craft\web\twig\variables\CraftVariable;
0 ignored issues
show
Bug introduced by
The type craft\web\twig\variables\CraftVariable 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...
37
use craft\web\UrlManager;
0 ignored issues
show
Bug introduced by
The type craft\web\UrlManager 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...
38
use craft\web\View;
0 ignored issues
show
Bug introduced by
The type craft\web\View 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...
39
40
use yii\base\Event;
0 ignored issues
show
Bug introduced by
The type yii\base\Event 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 yii\base\InvalidConfigException;
0 ignored issues
show
Bug introduced by
The type yii\base\InvalidConfigException 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
43
/**
44
 * Class Webperf
45
 *
46
 * @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 indented incorrectly; expected 2 spaces but found 4
Loading history...
47
 * @package   Webperf
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 3
Loading history...
48
 * @since     1.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 indented incorrectly; expected 3 spaces but found 5
Loading history...
49
 *
50
 * @property  RecommendationsService  $recommendations
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 2
Loading history...
51
 * @property  DataSamplesService      $dataSamples
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 2
Loading history...
52
 * @property  ErrorSamplesService     $errorSamples
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 2
Loading history...
53
 * @property  BeaconsService          $beacons
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 2
Loading history...
54
 * @property  ErrorsTarget            $errorsTarget
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 2
Loading history...
55
 * @property  ProfileTarget           $profileTarget
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 1 spaces but found 2
Loading history...
56
 */
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...
57
class Webperf extends Plugin
58
{
59
    // Constants
60
    // =========================================================================
61
62
    const RECOMMENDATIONS_CACHE_KEY = 'webperf-recommendations';
63
    const RECOMMENDATIONS_CACHE_DURATION = 60;
64
65
    const ERRORS_CACHE_KEY = 'webperf-errors';
66
    const ERRORS_CACHE_DURATION = 60;
67
68
    // Static Properties
69
    // =========================================================================
70
71
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
72
     * @var Webperf
73
     */
74
    public static $plugin;
75
76
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
77
     * @var Settings
78
     */
79
    public static $settings;
80
81
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
82
     * @var int|null
83
     */
84
    public static $requestUuid;
85
86
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
87
     * @var int|null
88
     */
89
    public static $requestUrl;
90
91
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
92
     * @var bool
93
     */
94
    public static $beaconIncluded = false;
95
96
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
97
     * @var string
98
     */
99
    public static $renderType = 'html';
100
101
    // Public Properties
102
    // =========================================================================
103
104
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
105
     * @var string
106
     */
107
    public $schemaVersion = '1.0.0';
108
109
    // Public Methods
110
    // =========================================================================
111
112
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
113
     * @inheritdoc
114
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
115
    public function init()
116
    {
117
        parent::init();
118
        // Initialize properties
119
        self::$plugin = $this;
120
        self::$settings = $this->getSettings();
121
        try {
122
            self::$requestUuid = random_int(0, PHP_INT_MAX);
123
        } catch (\Exception $e) {
124
            self::$requestUuid = null;
125
        }
126
        $this->name = self::$settings->pluginName;
0 ignored issues
show
Bug Best Practice introduced by
The property name does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
127
        // Handle any console commands
128
        $request = Craft::$app->getRequest();
129
        if ($request->getIsConsoleRequest()) {
130
            $this->controllerNamespace = 'nystudio107\webperf\console\controllers';
0 ignored issues
show
Bug Best Practice introduced by
The property controllerNamespace does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
131
        }
132
        // Add in our components
133
        $this->addComponents();
134
        // Install event listeners
135
        $this->installEventListeners();
136
        // Load that we've loaded
137
        Craft::info(
138
            Craft::t(
139
                'webperf',
140
                '{name} plugin loaded',
141
                ['name' => $this->name]
142
            ),
143
            __METHOD__
144
        );
145
    }
146
147
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
148
     * @inheritdoc
149
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
150
    public function getSettingsResponse()
151
    {
152
        // Just redirect to the plugin settings page
153
        Craft::$app->getResponse()->redirect(UrlHelper::cpUrl('webperf/settings'));
154
    }
155
156
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
157
     * @inheritdoc
158
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
159
    public function getCpNavItem()
160
    {
161
        $subNavs = [];
162
        $navItem = parent::getCpNavItem();
163
        $recommendations = $this->getRecommendationsCount();
164
        $errors = $this->getErrorsCount();
165
        $navItem['badgeCount'] = $errors.$recommendations;
166
        $currentUser = Craft::$app->getUser()->getIdentity();
167
        // Only show sub-navs the user has permission to view
168
        if ($currentUser->can('webperf:dashboard')) {
169
            $subNavs['dashboard'] = [
170
                'label' => 'Dashboard',
171
                'url' => 'webperf/dashboard',
172
            ];
173
        }
174
        if ($currentUser->can('webperf:performance')) {
175
            $subNavs['performance'] = [
176
                'label' => 'Performance',
177
                'url' => 'webperf/performance',
178
            ];
179
        }
180
        if ($currentUser->can('webperf:errors')) {
181
            $subNavs['errors'] = [
182
                'label' => 'Errors',
183
                'url' => 'webperf/errors',
184
                'badge' => $errors,
185
            ];
186
        }
187
        if ($currentUser->can('webperf:alerts')) {
188
            $subNavs['alerts'] = [
189
                'label' => 'Alerts',
190
                'url' => 'webperf/alerts',
191
            ];
192
        }
193
        if ($currentUser->can('webperf:settings')) {
194
            $subNavs['settings'] = [
195
                'label' => 'Settings',
196
                'url' => 'webperf/settings',
197
            ];
198
        }
199
        $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...
200
            'subnav' => $subNavs,
201
        ]);
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...
202
203
        return $navItem;
204
    }
205
206
    // Protected Methods
207
    // =========================================================================
208
209
    /**
210
     * Add in our components
211
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
212
    protected function addComponents()
213
    {
214
        $request = Craft::$app->getRequest();
215
        if ($request->getIsSiteRequest() && !$request->getIsConsoleRequest()) {
216
            $this->setRequestUrl();
217
            try {
218
                $uri = $request->getPathInfo();
219
            } catch (InvalidConfigException $e) {
220
                $uri = '';
221
            }
222
            // Ignore our own controllers
223
            if (self::$settings->includeCraftProfiling && strpos($uri, 'webperf/') === false) {
224
                // Add in the ProfileTarget component
225
                try {
226
                    $this->set('profileTarget', [
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...
227
                        'class' => ProfileTarget::class,
228
                        'levels' => ['profile'],
229
                        'categories' => [],
230
                        'logVars' => [],
231
                        'except' => [],
232
                    ]);
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...
233
                } catch (InvalidConfigException $e) {
234
                    Craft::error($e->getMessage(), __METHOD__);
235
                }
236
                // Attach our log target
237
                Craft::$app->getLog()->targets['webperf-profile'] = $this->profileTarget;
238
                // Add in the ErrorsTarget component
239
                $except = [];
240
                // If devMode is on, exclude errors/warnings from `seomatic`
241
                if (Craft::$app->getConfig()->getGeneral()->devMode) {
242
                    $except = ['nystudio107\seomatic\*'];
243
                }
244
                $levels = ['error'];
245
                if (self::$settings->includeCraftWarnings) {
246
                    $levels[] = 'warning';
247
                }
248
                try {
249
                    $this->set('errorsTarget', [
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...
250
                        'class' => ErrorsTarget::class,
251
                        'levels' => $levels,
252
                        'categories' => [],
253
                        'logVars' => [],
254
                        'except' => $except,
255
                    ]);
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...
256
                } catch (InvalidConfigException $e) {
257
                    Craft::error($e->getMessage(), __METHOD__);
258
                }
259
                // Attach our log target
260
                Craft::$app->getLog()->targets['webperf-errors'] = $this->errorsTarget;
261
            }
262
        }
263
    }
264
265
    /**
266
     * Set the request URL
267
     *
268
     * @param bool $force
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
269
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
270
    protected function setRequestUrl(bool $force = false)
271
    {
272
        self::$requestUrl = CraftDataSample::PLACEHOLDER_URL;
0 ignored issues
show
Documentation Bug introduced by
It seems like nystudio107\webperf\base...Sample::PLACEHOLDER_URL of type string is incompatible with the declared type integer|null of property $requestUrl.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
273
        if (!self::$settings->includeBeacon || $force || self::$settings->staticCachedSite) {
274
            $request = Craft::$app->getRequest();
275
            self::$requestUrl = UrlHelper::stripQueryString(
276
                urldecode($request->getAbsoluteUrl())
277
            );
278
        }
279
    }
280
281
    /**
282
     * Install our event listeners.
283
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
284
    protected function installEventListeners()
285
    {
286
        $request = Craft::$app->getRequest();
287
        // Add in our event listeners that are needed for every request
288
        $this->installGlobalEventListeners();
289
        // Install only for non-console site requests
290
        if ($request->getIsSiteRequest() && !$request->getIsConsoleRequest()) {
291
            $this->installSiteEventListeners();
292
        }
293
        // Install only for non-console Control Panel requests
294
        if ($request->getIsCpRequest() && !$request->getIsConsoleRequest()) {
295
            $this->installCpEventListeners();
296
        }
297
        // Handler: EVENT_AFTER_INSTALL_PLUGIN
298
        Event::on(
299
            Plugins::class,
300
            Plugins::EVENT_AFTER_INSTALL_PLUGIN,
301
            function (PluginEvent $event) {
302
                if ($event->plugin === $this) {
303
                    // Invalidate our caches after we've been installed
304
                    $this->clearAllCaches();
305
                    // Send them to our welcome screen
306
                    $request = Craft::$app->getRequest();
307
                    if ($request->isCpRequest) {
308
                        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...
309
                            'webperf/dashboard',
310
                            [
311
                                'showWelcome' => true,
312
                            ]
313
                        ))->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...
314
                    }
315
                }
316
            }
317
        );
318
    }
319
320
    /**
321
     * Install global event listeners for all request types
322
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
323
    protected function installGlobalEventListeners()
324
    {
325
        // Handler: CraftVariable::EVENT_INIT
326
        Event::on(
327
            CraftVariable::class,
328
            CraftVariable::EVENT_INIT,
329
            function (Event $event) {
330
                /** @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...
331
                $variable = $event->sender;
332
                $variable->set('webperf', WebperfVariable::class);
333
            }
334
        );
335
        // Handler: Plugins::EVENT_AFTER_LOAD_PLUGINS
336
        Event::on(
337
            Plugins::class,
338
            Plugins::EVENT_AFTER_LOAD_PLUGINS,
339
            function () {
340
                // Install these only after all other plugins have loaded
341
                $request = Craft::$app->getRequest();
342
                // Only respond to non-console site requests
343
                if ($request->getIsSiteRequest() && !$request->getIsConsoleRequest()) {
344
                    $this->handleSiteRequest();
345
                }
346
                // Respond to Control Panel requests
347
                if ($request->getIsCpRequest() && !$request->getIsConsoleRequest()) {
348
                    $this->handleAdminCpRequest();
349
                }
350
            }
351
        );
352
    }
353
354
    /**
355
     * Install site event listeners for site requests only
356
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
357
    protected function installSiteEventListeners()
358
    {
359
        // Handler: UrlManager::EVENT_REGISTER_SITE_URL_RULES
360
        Event::on(
361
            UrlManager::class,
362
            UrlManager::EVENT_REGISTER_SITE_URL_RULES,
363
            function (RegisterUrlRulesEvent $event) {
364
                Craft::debug(
365
                    'UrlManager::EVENT_REGISTER_SITE_URL_RULES',
366
                    __METHOD__
367
                );
368
                // Register our Control Panel routes
369
                $event->rules = array_merge(
370
                    $event->rules,
371
                    $this->customFrontendRoutes()
372
                );
373
            }
374
        );
375
    }
376
377
    /**
378
     * Install site event listeners for Control Panel requests only
379
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
380
    protected function installCpEventListeners()
381
    {
382
        // Handler: UrlManager::EVENT_REGISTER_CP_URL_RULES
383
        Event::on(
384
            UrlManager::class,
385
            UrlManager::EVENT_REGISTER_CP_URL_RULES,
386
            function (RegisterUrlRulesEvent $event) {
387
                Craft::debug(
388
                    'UrlManager::EVENT_REGISTER_CP_URL_RULES',
389
                    __METHOD__
390
                );
391
                // Register our Control Panel routes
392
                $event->rules = array_merge(
393
                    $event->rules,
394
                    $this->customAdminCpRoutes()
395
                );
396
            }
397
        );
398
        // Handler: Dashboard::EVENT_REGISTER_WIDGET_TYPES
399
        Event::on(
400
            Dashboard::class,
401
            Dashboard::EVENT_REGISTER_WIDGET_TYPES,
402
            function (RegisterComponentTypesEvent $event) {
403
                $event->types[] = MetricsWidget::class;
404
            }
405
        );
406
        // Handler: UserPermissions::EVENT_REGISTER_PERMISSIONS
407
        Event::on(
408
            UserPermissions::class,
409
            UserPermissions::EVENT_REGISTER_PERMISSIONS,
410
            function (RegisterUserPermissionsEvent $event) {
411
                Craft::debug(
412
                    'UserPermissions::EVENT_REGISTER_PERMISSIONS',
413
                    __METHOD__
414
                );
415
                // Register our custom permissions
416
                $event->permissions[Craft::t('webperf', 'Webperf')] = $this->customAdminCpPermissions();
417
            }
418
        );
419
    }
420
421
    /**
422
     * Handle site requests.  We do it only after we receive the event
423
     * EVENT_AFTER_LOAD_PLUGINS so that any pending db migrations can be run
424
     * before our event listeners kick in
425
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
426
    protected function handleSiteRequest()
427
    {
428
        // Don't include the beacon for response codes >= 400
429
        $response = Craft::$app->getResponse();
430
        if ($response->statusCode < 400) {
431
            // Handler: View::EVENT_END_PAGE
432
            Event::on(
433
                View::class,
434
                View::EVENT_END_PAGE,
435
                function () {
436
                    Craft::debug(
437
                        'View::EVENT_END_PAGE',
438
                        __METHOD__
439
                    );
440
                    $view = Craft::$app->getView();
441
                    // The page is done rendering, include our beacon
442
                    if (Webperf::$settings->includeBeacon && $view->getIsRenderingPageTemplate()) {
443
                        switch (self::$renderType) {
444
                            case 'html':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
445
                                Webperf::$plugin->beacons->includeHtmlBeacon();
446
                                self::$beaconIncluded = true;
447
                                break;
448
                            case 'amp-html':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
449
                                Webperf::$plugin->beacons->includeAmpHtmlScript();
450
                                break;
451
                        }
452
                    }
453
                }
454
            );
455
            // Handler: View::EVENT_END_BODY
456
            Event::on(
457
                View::class,
458
                View::EVENT_END_BODY,
459
                function () {
460
                    Craft::debug(
461
                        'View::EVENT_END_BODY',
462
                        __METHOD__
463
                    );
464
                    $view = Craft::$app->getView();
465
                    // The page is done rendering, include our beacon
466
                    if (Webperf::$settings->includeBeacon && $view->getIsRenderingPageTemplate()) {
467
                        switch (self::$renderType) {
468
                            case 'html':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
469
                                break;
470
                            case 'amp-html':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 24 spaces, found 28
Loading history...
471
                                Webperf::$plugin->beacons->includeAmpHtmlBeacon();
472
                                self::$beaconIncluded = true;
473
                                break;
474
                        }
475
                    }
476
                }
477
            );
478
            // Handler: Application::EVENT_AFTER_REQUEST
479
            Event::on(
480
                Application::class,
481
                Application::EVENT_AFTER_REQUEST,
482
                function () {
483
                    Craft::debug(
484
                        'Application::EVENT_AFTER_REQUEST',
485
                        __METHOD__
486
                    );
487
                    // If the beacon wasn't included, allow for the Craft timings
488
                    if (!self::$beaconIncluded) {
489
                        $this->setRequestUrl(true);
490
                    }
491
                }
492
            );
493
        }
494
    }
495
496
    /**
497
     * Handle Control Panel requests. We do it only after we receive the event
498
     * EVENT_AFTER_LOAD_PLUGINS so that any pending db migrations can be run
499
     * before our event listeners kick in
500
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
501
    protected function handleAdminCpRequest()
502
    {
503
    }
504
505
    /**
506
     * Clear all the caches!
507
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
508
    public function clearAllCaches()
509
    {
510
    }
511
512
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
513
     * @inheritdoc
514
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
515
    protected function createSettingsModel()
516
    {
517
        return new Settings();
518
    }
519
520
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
521
     * @inheritdoc
522
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
523
    protected function settingsHtml(): string
524
    {
525
        return Craft::$app->view->renderTemplate(
526
            'webperf/settings',
527
            [
528
                'settings' => $this->getSettings()
529
            ]
530
        );
531
    }
532
533
    /**
534
     * Return the custom frontend routes
535
     *
536
     * @return array
537
     */
538
    protected function customFrontendRoutes(): array
539
    {
540
        return [
541
            // Beacon
542
            '/webperf/metrics/beacon' => 'webperf/metrics/beacon',
543
            // Render
544
            '/webperf/render/amp-iframe' => 'webperf/render/amp-iframe',
545
            // Tables
546
            '/webperf/tables/pages-index' => 'webperf/tables/pages-index',
547
            '/webperf/tables/page-detail' => 'webperf/tables/page-detail',
548
            '/webperf/tables/errors-index' => 'webperf/tables/errors-index',
549
            '/webperf/tables/errors-detail' => 'webperf/tables/errors-detail',
550
            // Charts
551
            '/webperf/charts/dashboard-stats-average/<column:{handle}>'
552
            => 'webperf/charts/dashboard-stats-average',
553
            '/webperf/charts/dashboard-stats-average/<column:{handle}>/<siteId:\d+>'
554
            => 'webperf/charts/dashboard-stats-average',
555
556
            '/webperf/charts/dashboard-slowest-pages/<column:{handle}>/<limit:\d+>'
557
            => 'webperf/charts/dashboard-slowest-pages',
558
            '/webperf/charts/dashboard-slowest-pages/<column:{handle}>/<limit:\d+>/<siteId:\d+>'
559
            => 'webperf/charts/dashboard-slowest-pages',
560
561
            '/webperf/charts/pages-area-chart'
562
            => 'webperf/charts/pages-area-chart',
563
            '/webperf/charts/pages-area-chart/<siteId:\d+>'
564
            => 'webperf/charts/pages-area-chart',
565
566
            '/webperf/charts/errors-area-chart'
567
            => 'webperf/charts/errors-area-chart',
568
            '/webperf/charts/errors-area-chart/<siteId:\d+>'
569
            => 'webperf/charts/errors-area-chart',
570
571
            '/webperf/recommendations/list'
572
            => 'webperf/recommendations/list',
573
            '/webperf/recommendations/list/<siteId:\d+>'
574
            => 'webperf/recommendations/list',
575
576
            '/webperf/charts/widget/<days>' => 'webperf/charts/widget',
577
        ];
578
    }
579
    /**
580
     * Return the custom Control Panel routes
581
     *
582
     * @return array
583
     */
584
    protected function customAdminCpRoutes(): array
585
    {
586
        return [
587
            'webperf' => 'webperf/sections/dashboard',
588
            'webperf/dashboard' => 'webperf/sections/dashboard',
589
            'webperf/dashboard/<siteHandle:{handle}>' => 'webperf/sections/dashboard',
590
591
            'webperf/performance' => 'webperf/sections/pages-index',
592
            'webperf/performance/<siteHandle:{handle}>' => 'webperf/sections/pages-index',
593
594
            'webperf/performance/page-detail' => 'webperf/sections/page-detail',
595
            'webperf/performance/page-detail/<siteHandle:{handle}>' => 'webperf/sections/page-detail',
596
597
            'webperf/errors' => 'webperf/sections/errors-index',
598
            'webperf/errors/<siteHandle:{handle}>' => 'webperf/sections/errors-index',
599
600
            'webperf/errors/page-detail' => 'webperf/sections/errors-detail',
601
            'webperf/errors/page-detail/<siteHandle:{handle}>' => 'webperf/errors/page-detail',
602
603
            'webperf/alerts' => 'webperf/sections/alerts',
604
            'webperf/alerts/<siteHandle:{handle}>' => 'webperf/sections/alerts',
605
606
            'webperf/settings' => 'webperf/settings/plugin-settings',
607
        ];
608
    }
609
610
    /**
611
     * Returns the custom Control Panel user permissions.
612
     *
613
     * @return array
614
     */
615
    protected function customAdminCpPermissions(): array
616
    {
617
        return [
618
            'webperf:dashboard' => [
619
                'label' => Craft::t('webperf', 'Dashboard'),
620
            ],
621
            'webperf:performance' => [
622
                'label' => Craft::t('webperf', 'Performance'),
623
                'nested' => [
624
                    'webperf:performance-detail' => [
625
                        'label' => Craft::t('webperf', 'Performance Detail'),
626
                    ],
627
                    'webperf:delete-data-samples' => [
628
                        'label' => Craft::t('webperf', 'Delete Data Samples'),
629
                    ],
630
                ],
631
            ],
632
            'webperf:errors' => [
633
                'label' => Craft::t('webperf', 'Errors'),
634
                'nested' => [
635
                    'webperf:errors-detail' => [
636
                        'label' => Craft::t('webperf', 'Errors Detail'),
637
                    ],
638
                    'webperf:delete-error-samples' => [
639
                        'label' => Craft::t('webperf', 'Delete Error Samples'),
640
                    ],
641
                ],
642
            ],
643
            'webperf:alerts' => [
644
                'label' => Craft::t('webperf', 'Alerts'),
645
            ],
646
            'webperf:recommendations' => [
647
                'label' => Craft::t('webperf', 'Recommendations'),
648
            ],
649
            'webperf:settings' => [
650
                'label' => Craft::t('webperf', 'Settings'),
651
            ],
652
        ];
653
    }
654
655
    /**
656
     * Get a string value with the number of recommendations
657
     *
658
     * @return string
659
     */
660
    protected function getRecommendationsCount(): string
661
    {
662
        $cache = Craft::$app->getCache();
663
        // See if there are any recommendations to add as a badge
664
        $recommendations = $cache->getOrSet(self::RECOMMENDATIONS_CACHE_KEY, function () {
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...
665
            $data = [];
666
            $now = new \DateTime();
667
            $end = $now->format('Y-m-d');
668
            $start = $now->modify('-30 days')->format('Y-m-d');
669
            $stats = Webperf::$plugin->recommendations->data('', $start, $end);
670
            if (!empty($stats)) {
671
                $recSample = new RecommendationDataSample($stats);
672
                $data = Webperf::$plugin->recommendations->list($recSample);
673
            }
674
675
            return count($data);
676
        }, self::RECOMMENDATIONS_CACHE_DURATION);
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...
677
678
        if (!$recommendations) {
679
            $recommendations = '';
680
        }
681
682
        return (string)$recommendations;
683
    }
684
685
    /**
686
     * Get a string value with the number of errors
687
     *
688
     * @return string
689
     */
690
    protected function getErrorsCount(): string
691
    {
692
        $cache = Craft::$app->getCache();
693
        // See if there are any recommendations to add as a badge
694
        $errors = $cache->getOrSet(self::ERRORS_CACHE_KEY, function () {
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...
695
            $now = new \DateTime();
696
            $end = $now->format('Y-m-d');
697
            $start = $now->modify('-30 days')->format('Y-m-d');
698
699
            return Webperf::$plugin->errorSamples->totalErrorSamplesRange(0, $start, $end);
700
        }, self::ERRORS_CACHE_DURATION);
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...
701
702
        if (!$errors) {
703
            $errors = '';
704
        } else {
705
            $errors = '⚠';
706
        }
707
708
        return (string)$errors;
709
    }
710
}
711