92 lines
3.9 KiB
PHP
92 lines
3.9 KiB
PHP
<?php
|
||
/**
|
||
* @package Bicycle
|
||
* @author Egor Isaev
|
||
* @description ProfilerToolbar.php
|
||
* @copyright (c) 07/08/2026
|
||
*/
|
||
|
||
namespace System\Classes;
|
||
|
||
use Services\Auth;
|
||
use Services\DataBase\Classes\Profiler;
|
||
|
||
/**
|
||
* Debug-панель внизу страницы: время запроса, память, SQL-запросы
|
||
* (см. Services\DataBase\Classes\Profiler). Видна только role === 'admin'
|
||
* (см. Services\Auth) — render() отдаёт пустую строку всем остальным.
|
||
* Аналог ProfilerToolbar для Kohana (github.com/Alert/profilertoolbar).
|
||
*/
|
||
class ProfilerToolbar
|
||
{
|
||
/**
|
||
* Рендерит панель, если текущий пользователь — admin, иначе — пустую строку.
|
||
*
|
||
* @return string
|
||
*/
|
||
public static function render(): string
|
||
{
|
||
$user = Auth::instance()->getUser();
|
||
|
||
if (($user['role'] ?? null) !== 'admin') {
|
||
return '';
|
||
}
|
||
|
||
$time_ms = (microtime(true) - ($_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true))) * 1000;
|
||
$memory = memory_get_peak_usage(true);
|
||
$query_count = Profiler::count();
|
||
$query_time = Profiler::totalTime();
|
||
|
||
$rows = '';
|
||
foreach (Profiler::entries() as $entry) {
|
||
$rows .= '<tr>' .
|
||
'<td>' . number_format($entry['time_ms'], 2) . ' ms</td>' .
|
||
'<td><code>' . htmlspecialchars($entry['sql'], ENT_QUOTES, 'UTF-8') . '</code></td>' .
|
||
'<td><code>' . htmlspecialchars(json_encode($entry['params'], JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8') . '</code></td>' .
|
||
'</tr>';
|
||
}
|
||
|
||
return self::html($time_ms, $memory, $query_count, $query_time, $rows);
|
||
}
|
||
|
||
/**
|
||
* @param float $time_ms Время выполнения запроса, мс
|
||
* @param int $memory Пиковое потребление памяти, байт
|
||
* @param int $query_count Число SQL-запросов
|
||
* @param float $query_time Суммарное время SQL-запросов, мс
|
||
* @param string $rows Готовые <tr> со списком запросов
|
||
* @return string
|
||
*/
|
||
private static function html(float $time_ms, int $memory, int $query_count, float $query_time, string $rows): string
|
||
{
|
||
$memory_mb = number_format($memory / 1024 / 1024, 2);
|
||
$time = number_format($time_ms, 1);
|
||
$query_ms = number_format($query_time, 1);
|
||
|
||
return <<<HTML
|
||
<div id="profiler-toolbar" style="position:fixed;left:0;right:0;bottom:0;z-index:99999;
|
||
font:12px/1.4 monospace;background:#1b1b1b;color:#ddd;border-top:2px solid #444;">
|
||
<div style="display:flex;gap:16px;align-items:center;padding:4px 12px;cursor:pointer;"
|
||
onclick="var b=document.getElementById('profiler-toolbar-body');b.style.display=b.style.display==='none'?'block':'none';">
|
||
<strong style="color:#8bc34a;">Profiler</strong>
|
||
<span>время: {$time} ms</span>
|
||
<span>память: {$memory_mb} MB</span>
|
||
<span>SQL: {$query_count} ({$query_ms} ms)</span>
|
||
</div>
|
||
<div id="profiler-toolbar-body" style="display:none;max-height:300px;overflow:auto;border-top:1px solid #444;">
|
||
<table style="width:100%;border-collapse:collapse;">
|
||
<thead>
|
||
<tr style="text-align:left;color:#999;">
|
||
<th style="padding:4px 12px;">Время</th>
|
||
<th style="padding:4px 12px;">SQL</th>
|
||
<th style="padding:4px 12px;">Параметры</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>{$rows}</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
HTML;
|
||
}
|
||
}
|