DebugBar::disabledCriteria()   F
last analyzed

Complexity

Conditions 13
Paths 1024

Size

Total Lines 34
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
cc 13
eloc 22
c 3
b 0
f 1
nc 1024
nop 0
dl 0
loc 34
rs 2.45

How to fix   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
namespace LeKoala\DebugBar;
4
5
use Exception;
6
use Monolog\Logger;
7
use ReflectionObject;
8
use Psr\Log\LoggerInterface;
9
use SilverStripe\Core\Kernel;
10
use DebugBar\JavascriptRenderer;
11
use DebugBar\Storage\FileStorage;
12
use SilverStripe\Dev\Deprecation;
13
use SilverStripe\Control\Director;
14
use SilverStripe\Core\Environment;
15
use SilverStripe\Admin\LeftAndMain;
16
use SilverStripe\View\Requirements;
17
use SilverStripe\Control\Controller;
18
use Symfony\Component\Mailer\Mailer;
19
use SilverStripe\Control\HTTPRequest;
20
use DebugBar\DebugBar as BaseDebugBar;
21
use SilverStripe\Core\Injector\Injector;
22
use SilverStripe\Core\Config\ConfigLoader;
23
use SilverStripe\Core\Config\Configurable;
24
use SilverStripe\Core\Injector\Injectable;
25
use DebugBar\DataCollector\MemoryCollector;
26
use LeKoala\DebugBar\Messages\LogFormatter;
27
use SilverStripe\Admin\AdminRootController;
28
use SilverStripe\Core\Manifest\ModuleLoader;
29
use DebugBar\DataCollector\MessagesCollector;
30
use LeKoala\DebugBar\Bridge\MonologCollector;
31
use Symfony\Component\Mailer\MailerInterface;
32
use LeKoala\DebugBar\Collector\CacheCollector;
33
use SilverStripe\Core\Manifest\ModuleResource;
34
use LeKoala\DebugBar\Collector\ConfigCollector;
35
use LeKoala\DebugBar\Proxy\ConfigManifestProxy;
36
use LeKoala\DebugBar\Collector\PhpInfoCollector;
37
use LeKoala\DebugBar\Extension\ProxyDBExtension;
38
use LeKoala\DebugBar\Collector\DatabaseCollector;
39
use LeKoala\DebugBar\Collector\TimeDataCollector;
40
use LeKoala\DebugBar\Proxy\DeltaConfigManifestProxy;
41
use LeKoala\DebugBar\Collector\PartialCacheCollector;
42
use LeKoala\DebugBar\Collector\SilverStripeCollector;
43
use SilverStripe\Config\Collections\DeltaConfigCollection;
44
use SilverStripe\Config\Collections\CachedConfigCollection;
45
use LeKoala\DebugBar\Bridge\SymfonyMailer\SymfonyMailerCollector;
46
use SilverStripe\Security\Permission;
47
48
/**
49
 * A simple helper
50
 */
51
class DebugBar
52
{
53
    use Configurable;
54
    use Injectable;
55
56
    /**
57
     * @var BaseDebugBar|false|null
58
     */
59
    protected static $debugbar;
60
61
    /**
62
     * @var bool
63
     */
64
    public static $bufferingEnabled = false;
65
66
    /**
67
     * @var bool
68
     */
69
    public static $suppressJquery = false;
70
71
    /**
72
     * @var JavascriptRenderer|null
73
     */
74
    protected static $renderer;
75
76
    /**
77
     * @var bool
78
     */
79
    protected static $showQueries = false;
80
81
    /**
82
     * @var HTTPRequest|null
83
     */
84
    protected static $request;
85
86
    /**
87
     * @var array<string,array<float>>
88
     */
89
    protected static $extraTimes = [];
90
91
    /**
92
     * Get the Debug Bar instance
93
     * @throws Exception
94
     * @global array $databaseConfig
95
     * @return BaseDebugBar|false
96
     */
97
    public static function getDebugBar()
98
    {
99
        if (self::$debugbar !== null) {
100
            return self::$debugbar;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::debugbar also could return the type boolean which is incompatible with the documented return type DebugBar\DebugBar|false.
Loading history...
101
        }
102
103
        $reasons = self::disabledCriteria();
104
        if (!empty($reasons)) {
105
            self::$debugbar = false; // no need to check again
106
            return false;
107
        }
108
109
        self::initDebugBar();
110
111
        if (!self::$debugbar) {
112
            throw new Exception("Failed to initialize the DebugBar");
113
        }
114
115
        return self::$debugbar;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::debugbar returns the type void which is incompatible with the documented return type DebugBar\DebugBar|false.
Loading history...
116
    }
117
118
    /**
119
     * Init the debugbar instance
120
     *
121
     * @global array $databaseConfig
122
     * @return BaseDebugBar|null
123
     */
124
    public static function initDebugBar()
125
    {
126
        // Prevent multiple inits
127
        if (self::$debugbar) {
128
            return self::$debugbar;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::debugbar also could return the type true which is incompatible with the documented return type DebugBar\DebugBar|null.
Loading history...
129
        }
130
131
        self::$debugbar = $debugbar = new BaseDebugBar();
132
133
        if (isset($_REQUEST['showqueries']) && Director::isDev()) {
134
            self::setShowQueries(true);
135
            unset($_REQUEST['showqueries']);
136
        }
137
138
        $debugbar->addCollector(new PhpInfoCollector());
139
        $debugbar->addCollector(new TimeDataCollector());
140
        self::measureExtraTime();
141
        $debugbar->addCollector(new MemoryCollector());
142
143
        // Add config proxy replacing the core config manifest
144
        if (self::config()->config_collector) {
145
            /** @var ConfigLoader $configLoader */
146
            $configLoader = Injector::inst()->get(Kernel::class)->getConfigLoader();
147
            // There is no getManifests method on ConfigLoader
148
            $manifests = self::getProtectedValue($configLoader, 'manifests');
149
            foreach ($manifests as $manifestIdx => $manifest) {
150
                if ($manifest instanceof CachedConfigCollection) {
151
                    $manifest = new ConfigManifestProxy($manifest);
152
                    $manifests[$manifestIdx] = $manifest;
153
                }
154
                if ($manifest instanceof DeltaConfigCollection) {
155
                    $manifest = DeltaConfigManifestProxy::createFromOriginal($manifest);
156
                    $manifests[$manifestIdx] = $manifest;
157
                }
158
            }
159
            // Don't push as it may change stack order
160
            self::setProtectedValue($configLoader, 'manifests', $manifests);
161
        }
162
163
        // If enabled and available
164
        if (self::config()->db_collector && class_exists(\TractorCow\SilverStripeProxyDB\ProxyDBFactory::class)) {
165
            $debugbar->addCollector(new DatabaseCollector);
166
        }
167
168
        // Add message collector last so other collectors can send messages to the console using it
169
        $debugbar->addCollector(new MessagesCollector());
170
171
        // Aggregate monolog into messages
172
        $logger = Injector::inst()->get(LoggerInterface::class);
173
        if ($logger instanceof Logger) {
174
            $logCollector = new MonologCollector($logger);
175
            $logCollector->setFormatter(new LogFormatter);
176
            $debugbar['messages']->aggregate($logCollector);
0 ignored issues
show
Bug introduced by
The method aggregate() does not exist on DebugBar\DataCollector\DataCollectorInterface. It seems like you code against a sub-type of DebugBar\DataCollector\DataCollectorInterface such as DebugBar\DataCollector\MessagesCollector. ( Ignorable by Annotation )

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

176
            $debugbar['messages']->/** @scrutinizer ignore-call */ 
177
                                   aggregate($logCollector);
Loading history...
177
        }
178
179
        // Add some SilverStripe specific infos
180
        $debugbar->addCollector(new SilverStripeCollector);
181
182
        if (self::config()->get('enable_storage')) {
183
            $debugBarTempFolder = TEMP_FOLDER . '/debugbar';
184
            $debugbar->setStorage($fileStorage = new FileStorage($debugBarTempFolder));
185
            if (isset($_GET['flush']) && is_dir($debugBarTempFolder)) {
186
                // FileStorage::clear() is implemented with \DirectoryIterator which throws UnexpectedValueException if dir can not be opened
187
                $fileStorage->clear();
188
            }
189
        }
190
191
        if (self::config()->config_collector) {
192
            // Add the config collector
193
            $debugbar->addCollector(new ConfigCollector);
194
        }
195
196
        // Cache
197
        if (self::config()->cache_collector) {
198
            $debugbar->addCollector($cacheCollector = new CacheCollector);
199
            $cacheCollector->setShowGet(self::config()->cache_collector_show_get);
200
        }
201
202
        // Partial cache
203
        if (self::config()->partial_cache_collector) {
204
            $debugbar->addCollector(new PartialCacheCollector);
205
        }
206
207
        // Email logging
208
        if (self::config()->email_collector) {
209
            $mailer = Injector::inst()->get(MailerInterface::class);
210
            if ($mailer instanceof Mailer) {
211
                $debugbar->addCollector(new SymfonyMailerCollector);
212
            }
213
        }
214
215
        // Since we buffer everything, why not enable all dev options ?
216
        if (self::config()->get('auto_debug')) {
217
            $_REQUEST['debug'] = true;
218
            $_REQUEST['debug_request'] = true;
219
        }
220
221
        if (isset($_REQUEST['debug']) || isset($_REQUEST['debug_request'])) {
222
            self::$bufferingEnabled = true;
223
            ob_start(); // We buffer everything until we have called an action
224
        }
225
226
        return $debugbar;
227
    }
228
229
    /**
230
     * Access a protected property when the api does not allow access
231
     *
232
     * @param object $object
233
     * @param string $property
234
     * @return mixed
235
     */
236
    protected static function getProtectedValue($object, $property)
237
    {
238
        $refObject = new ReflectionObject($object);
239
        $refProperty = $refObject->getProperty($property);
240
        $refProperty->setAccessible(true);
241
        return $refProperty->getValue($object);
242
    }
243
244
    /**
245
     * Set a protected property when the api does not allow access
246
     *
247
     * @param object $object
248
     * @param string $property
249
     * @param mixed $newValue
250
     * @return void
251
     */
252
    protected static function setProtectedValue($object, $property, $newValue)
253
    {
254
        $refObject = new ReflectionObject($object);
255
        $refProperty = $refObject->getProperty($property);
256
        $refProperty->setAccessible(true);
257
        $refProperty->setValue($object, $newValue);
258
    }
259
260
    /**
261
     * Clear the current instance of DebugBar
262
     *
263
     * @return void
264
     */
265
    public static function clearDebugBar()
266
    {
267
        self::$debugbar = null;
268
        self::$bufferingEnabled = false;
269
        self::$renderer = null;
270
        self::$showQueries = false;
271
        self::$request = null;
272
        self::$extraTimes = [];
273
        ProxyDBExtension::resetQueries();
274
    }
275
276
    /**
277
     * @return boolean
278
     */
279
    public static function getShowQueries()
280
    {
281
        return self::$showQueries;
282
    }
283
284
    /**
285
     * Override default showQueries mode
286
     *
287
     * @param boolean $showQueries
288
     * @return void
289
     */
290
    public static function setShowQueries($showQueries)
291
    {
292
        self::$showQueries = $showQueries;
293
    }
294
295
    /**
296
     * Helper to access this module resources
297
     *
298
     * @param string $path
299
     * @return ModuleResource
300
     */
301
    public static function moduleResource($path)
302
    {
303
        return ModuleLoader::getModule('lekoala/silverstripe-debugbar')->getResource($path);
304
    }
305
306
    /**
307
     * @param bool $flag
308
     * @return void
309
     */
310
    public static function suppressJquery($flag = true)
311
    {
312
        $file = "debugbar/assets/vendor/jquery/dist/jquery.min.js";
313
        if ($flag) {
314
            Requirements::block($file);
315
        } else {
316
            Requirements::unblock($file);
317
        }
318
319
        self::$suppressJquery = $flag;
320
    }
321
322
    /**
323
     * Include DebugBar assets using Requirements API
324
     * This needs to be called before the template is rendered otherwise the calls to the Requirements API are ignored
325
     *
326
     * @return bool
327
     */
328
    public static function includeRequirements()
329
    {
330
        $debugbar = self::getDebugBar();
331
332
        if (!$debugbar) {
0 ignored issues
show
introduced by
$debugbar is of type DebugBar\DebugBar, thus it always evaluated to true.
Loading history...
333
            return false;
334
        }
335
336
        // Already called
337
        if (self::$renderer) {
338
            return false;
339
        }
340
341
        $renderer = $debugbar->getJavascriptRenderer();
342
343
        // We don't need the true path since we are going to use Requirements API that appends the BASE_PATH
344
        $assetsResource = self::moduleResource('assets');
345
        $renderer->setBasePath($assetsResource->getRelativePath());
346
        $renderer->setBaseUrl(Director::makeRelative($assetsResource->getURL()));
347
348
        $includeJquery = self::config()->get('include_jquery');
349
        // In CMS, jQuery is already included
350
        if (self::isAdminController()) {
351
            $includeJquery = false;
352
        }
353
        // If jQuery is already included, set to false
354
        $js = Requirements::backend()->getJavascript();
355
        foreach ($js as $url => $args) {
356
            $name = basename($url);
357
            if ($name == 'jquery.js' || $name == 'jquery.min.js') {
358
                $includeJquery = false;
359
                break;
360
            }
361
        }
362
363
        if ($includeJquery) {
364
            $renderer->setEnableJqueryNoConflict(true);
365
        } else {
366
            $renderer->disableVendor('jquery');
367
            $renderer->setEnableJqueryNoConflict(false);
368
        }
369
370
        if (DebugBar::config()->get('enable_storage')) {
371
            $renderer->setOpenHandlerUrl('__debugbar');
372
        }
373
374
        foreach ($renderer->getAssets('css') as $cssFile) {
375
            Requirements::css(self::replaceAssetPath($cssFile));
376
        }
377
378
        foreach ($renderer->getAssets('js') as $jsFile) {
379
            Requirements::javascript(self::replaceAssetPath($jsFile), [
380
                'type' => 'application/javascript'
381
            ]);
382
        }
383
384
        self::$renderer = $renderer;
385
386
        return true;
387
    }
388
389
    /**
390
     * @param string $file
391
     * @return string
392
     */
393
    protected static function replaceAssetPath($file)
394
    {
395
        return Director::makeRelative(str_replace('\\', '/', ltrim($file, '/')));
396
    }
397
398
    /**
399
     * Returns the script to display the DebugBar
400
     *
401
     * @return string
402
     */
403
    public static function renderDebugBar()
404
    {
405
        if (!self::$renderer) {
406
            return '';
407
        }
408
409
        // If we have any extra time pending, add it
410
        if (!empty(self::$extraTimes)) {
411
            foreach (self::$extraTimes as $extraTime => $extraTimeData) {
412
                self::trackTime($extraTime);
413
            }
414
        }
415
416
        // Requirements may have been cleared (CMS iframes...) or not set
417
        $js = Requirements::backend()->getJavascript();
418
        $debugBarResource = self::moduleResource('assets/debugbar.js');
419
        $path = $debugBarResource->getRelativePath();
420
421
        // Url in getJavascript has a / slash, so fix if necessary
422
        $path = str_replace("\\", "/", $path);
423
        if (!array_key_exists($path, $js)) {
424
            return '';
425
        }
426
        $initialize = true;
427
        if (Director::is_ajax()) {
428
            $initialize = false;
429
        }
430
431
        // Normally deprecation notices are output in a shutdown function, which runs well after debugbar has rendered.
432
        // This ensures the deprecation notices which have been noted up to this point are logged out and collected by
433
        // the MonologCollector.
434
        Deprecation::outputNotices();
435
436
        $script = self::$renderer->render($initialize);
437
438
        return $script;
439
    }
440
441
    /**
442
     * Get all criteria why the DebugBar could be disabled
443
     *
444
     * @return array<string>
445
     */
446
    public static function disabledCriteria()
447
    {
448
        $reasons = [];
449
        if (!Director::isDev() && !self::allowAllEnvironments()) {
450
            $reasons[] = 'Not in dev mode';
451
        }
452
        if (self::isDisabled()) {
453
            $reasons[] = 'Disabled by a constant or configuration';
454
        }
455
        if (self::vendorNotInstalled()) {
456
            $reasons[] = 'DebugBar is not installed in vendors';
457
        }
458
        if (self::notLocalIp()) {
459
            $reasons[] = 'Not a local ip';
460
        }
461
        if (Director::is_cli()) {
462
            $reasons[] = 'In CLI mode';
463
        }
464
        if (self::isDevUrl()) {
465
            $reasons[] = 'Dev tools';
466
        }
467
        if (self::isAdminUrl() && !self::config()->get('enabled_in_admin')) {
468
            $reasons[] = 'In admin';
469
        }
470
        if (isset($_GET['CMSPreview'])) {
471
            $reasons[] = 'CMS Preview';
472
        }
473
        if (self::isExcludedRoute()) {
474
            $reasons[] = 'Route excluded';
475
        }
476
        if (!self::hasRequiredPermissions()) {
477
            $reasons[] = 'Not allowed';
478
        }
479
        return $reasons;
480
    }
481
482
    /**
483
     * Determine why DebugBar is disabled
484
     *
485
     * Deprecated in favor of disabledCriteria
486
     *
487
     * @return string
488
     */
489
    public static function whyDisabled()
490
    {
491
        $reasons = self::disabledCriteria();
492
        if (!empty($reasons)) {
493
            return $reasons[0];
494
        }
495
        return "I don't know why";
496
    }
497
498
    /**
499
     * @return bool
500
     */
501
    public static function vendorNotInstalled()
502
    {
503
        return !class_exists('DebugBar\\StandardDebugBar');
504
    }
505
506
    /**
507
     * @return bool
508
     */
509
    public static function notLocalIp()
510
    {
511
        if (!self::config()->get('check_local_ip')) {
512
            return false;
513
        }
514
        if (isset($_SERVER['REMOTE_ADDR'])) {
515
            return !in_array($_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1', '1']);
516
        }
517
        return false;
518
    }
519
520
    /**
521
     * @return bool
522
     */
523
    public static function allowAllEnvironments()
524
    {
525
        // You will also need to add a debugbar-live config
526
        if (Environment::getEnv('DEBUGBAR_ALLOW_ALL_ENV')) {
527
            return true;
528
        }
529
        return false;
530
    }
531
532
    /**
533
     * @return bool
534
     */
535
    public static function isDisabled()
536
    {
537
        if (Environment::getEnv('DEBUGBAR_DISABLE') || static::config()->get('disabled')) {
538
            return true;
539
        }
540
        return false;
541
    }
542
543
    /**
544
     * @return bool
545
     */
546
    public static function hasRequiredPermissions()
547
    {
548
        if (static::config()->get('user_admin_only')) {
549
            return Permission::check('ADMIN');
550
        }
551
        return true;
552
    }
553
554
    /**
555
     * @return bool
556
     */
557
    public static function isDevUrl()
558
    {
559
        return strpos(self::getRequestUrl(), '/dev/') === 0;
560
    }
561
562
    /**
563
     * @return bool
564
     */
565
    public static function isAdminUrl()
566
    {
567
        $baseUrl = rtrim(BASE_URL, '/');
568
        if (class_exists(AdminRootController::class)) {
569
            $adminUrl = AdminRootController::config()->get('url_base');
570
        } else {
571
            $adminUrl = 'admin';
572
        }
573
574
        return strpos(self::getRequestUrl(), $baseUrl . '/' . $adminUrl . '/') === 0;
575
    }
576
577
    /**
578
     * @return bool
579
     */
580
    public static function isExcludedRoute()
581
    {
582
        $isExcluded = false;
583
        $excludedRoutes = self::config()->get('excluded_routes');
584
        if (!empty($excludedRoutes)) {
585
            $url = self::getRequestUrl();
586
            foreach ($excludedRoutes as $excludedRoute) {
587
                if (strpos($url, (string) $excludedRoute) === 0) {
588
                    $isExcluded = true;
589
                    break;
590
                }
591
            }
592
        }
593
        return $isExcluded;
594
    }
595
596
    /**
597
     * @return bool
598
     */
599
    public static function isAdminController()
600
    {
601
        if (Controller::has_curr()) {
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Control\Controller::has_curr() has been deprecated: 5.4.0 Will be removed without equivalent functionality to replace it in a future major release ( Ignorable by Annotation )

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

601
        if (/** @scrutinizer ignore-deprecated */ Controller::has_curr()) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
602
            return Controller::curr() instanceof LeftAndMain;
603
        }
604
        return self::isAdminUrl();
605
    }
606
607
    /**
608
     * Avoid triggering data collection for open handler
609
     *
610
     * @return boolean
611
     */
612
    public static function isDebugBarRequest()
613
    {
614
        if ($url = self::getRequestUrl()) {
615
            return strpos($url, '/__debugbar') === 0;
616
        }
617
        return true;
618
    }
619
620
    /**
621
     * Get request url
622
     *
623
     * @return string
624
     */
625
    public static function getRequestUrl()
626
    {
627
        if (isset($_REQUEST['url'])) {
628
            return $_REQUEST['url'];
629
        }
630
        if (isset($_SERVER['REQUEST_URI'])) {
631
            return $_SERVER['REQUEST_URI'];
632
        }
633
        return '';
634
    }
635
636
    /**
637
     * Helper to make code cleaner
638
     *
639
     * @param callable $callback
640
     * @return void
641
     */
642
    public static function withDebugBar($callback)
643
    {
644
        if (self::getDebugBar() && !self::isDebugBarRequest()) {
645
            $callback(self::getDebugBar());
646
        }
647
    }
648
649
    /**
650
     * Set the current request. Is provided by the DebugBarMiddleware.
651
     *
652
     * @param HTTPRequest $request
653
     * @return void
654
     */
655
    public static function setRequest(HTTPRequest $request)
656
    {
657
        self::$request = $request;
658
    }
659
660
    /**
661
     * Get the current request
662
     *
663
     * @return HTTPRequest|null
664
     */
665
    public static function getRequest()
666
    {
667
        if (self::$request) {
668
            return self::$request;
669
        }
670
        // Fall back to trying from the global state
671
        if (Controller::has_curr()) {
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Control\Controller::has_curr() has been deprecated: 5.4.0 Will be removed without equivalent functionality to replace it in a future major release ( Ignorable by Annotation )

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

671
        if (/** @scrutinizer ignore-deprecated */ Controller::has_curr()) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
672
            return Controller::curr()->getRequest();
673
        }
674
        return null;
675
    }
676
677
    /**
678
     * @return TimeDataCollector|false
679
     */
680
    public static function getTimeCollector()
681
    {
682
        $debugbar = self::getDebugBar();
683
        if (!$debugbar) {
0 ignored issues
show
introduced by
$debugbar is of type DebugBar\DebugBar, thus it always evaluated to true.
Loading history...
684
            return false;
685
        }
686
        //@phpstan-ignore-next-line
687
        return $debugbar->getCollector('time');
688
    }
689
690
    /**
691
     * @return MessagesCollector|false
692
     */
693
    public static function getMessageCollector()
694
    {
695
        $debugbar = self::getDebugBar();
696
        if (!$debugbar) {
0 ignored issues
show
introduced by
$debugbar is of type DebugBar\DebugBar, thus it always evaluated to true.
Loading history...
697
            return false;
698
        }
699
        //@phpstan-ignore-next-line
700
        return  $debugbar->getCollector('messages');
701
    }
702
703
    /**
704
     * Start/stop time tracking (also before init)
705
     *
706
     * @param string $label
707
     * @return void
708
     */
709
    public static function trackTime($label)
710
    {
711
        if (!isset(self::$extraTimes[$label])) {
712
            self::$extraTimes[$label] = [microtime(true)];
713
        } else {
714
            self::$extraTimes[$label][] = microtime(true);
715
716
            // If we have the debugbar instance, add the measure
717
            if (self::$debugbar) {
718
                $timeData = self::getTimeCollector();
719
                if (!$timeData) {
0 ignored issues
show
introduced by
$timeData is of type LeKoala\DebugBar\Collector\TimeDataCollector, thus it always evaluated to true.
Loading history...
720
                    return;
721
                }
722
                $values = self::$extraTimes[$label];
723
                $timeData->addMeasure(
724
                    $label,
725
                    $values[0],
726
                    $values[1]
727
                );
728
                unset(self::$extraTimes[$label]);
729
            }
730
        }
731
    }
732
733
    /**
734
     * Close any open extra time record
735
     *
736
     * @return void
737
     */
738
    public static function closeExtraTime()
739
    {
740
        foreach (self::$extraTimes as $label => $values) {
741
            if (!isset($values[1])) {
742
                self::$extraTimes[$label][] = microtime(true);
743
            }
744
        }
745
    }
746
747
    /**
748
     * Add extra time to time collector
749
     * @return void
750
     */
751
    public static function measureExtraTime()
752
    {
753
        $timeData = self::getTimeCollector();
754
        if (!$timeData) {
0 ignored issues
show
introduced by
$timeData is of type LeKoala\DebugBar\Collector\TimeDataCollector, thus it always evaluated to true.
Loading history...
755
            return;
756
        }
757
        foreach (self::$extraTimes as $label => $values) {
758
            if (!isset($values[1])) {
759
                continue; // unfinished measure
760
            }
761
            $timeData->addMeasure(
762
                $label,
763
                $values[0],
764
                $values[1]
765
            );
766
            unset(self::$extraTimes[$label]);
767
        }
768
    }
769
}
770