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
![]() |
|||||||
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
|
|||||||
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
|
|||||||
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
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
![]() |
|||||||
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
|
|||||||
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
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
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. ![]() |
|||||||
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
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
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. ![]() |
|||||||
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
|
|||||||
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
|
|||||||
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
|
|||||||
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
|
|||||||
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 |