| @copyright 2007-2026 (c) AVE.cms | @link https://ave-cms.ru | @version 3.3 */ namespace App\Common\Db\Core; use App\Helpers\Number; /** * Класс для отладки SQL запросов * Показывает информацию о том, был ли запрос взят из кеша или выполнен напрямую */ class QueryDebug { /** * Список всех отладочных сообщений * @var array */ protected static $_debug_list = []; /** * Включен ли дебаг * @var bool */ protected static $_enabled = false; /** * Инициализация дебага * @param bool $enabled Включить/выключить дебаг */ public static function init($enabled = false) { self::$_enabled = $enabled; } /** * Проверить, включен ли дебаг * @return bool */ public static function isEnabled() { return self::$_enabled; } /** * Зарегистрировать попытку получения из кеша * @param string $query Хешированный запрос * @param bool $hit true если кеш найден, false если промах * @param float $time Время выполнения в секундах */ public static function logCacheHit(string $query, bool $hit, float $time) { if (!self::$_enabled) { return; } self::$_debug_list[] = [ 'type' => $hit ? 'cache_hit' : 'cache_miss', 'query' => QueryLogger::queryTrim($query), 'time' => Number::numFormat($time * 1000, 2, ',', ''), 'unit' => 'ms', 'source' => $hit ? 'Кеш' : 'БД' ]; } /** * Зарегистрировать выполнение запроса напрямую ( без кеша ) * @param string $query Выполненный запрос * @param float $time Время выполнения в секундах * @param int $affected_rows Количество затронутых строк */ public static function logDirectQuery(string $query, float $time, int $affected_rows = 0) { if (!self::$_enabled) { return; } self::$_debug_list[] = [ 'type' => 'direct', 'query' => QueryLogger::queryTrim($query), 'time' => Number::numFormat($time * 1000, 2, ',', ''), 'unit' => 'ms', 'source' => 'БД', 'affected' => $affected_rows ]; } /** * Зарегистрировать сохранение в кеш * @param string $query Сохраненный запрос * @param float $time Время сохранения * @param int $ttl Время жизни кеша в секундах */ public static function logCacheSave(string $query, float $time, int $ttl) { if (!self::$_enabled) { return; } self::$_debug_list[] = [ 'type' => 'cache_save', 'query' => QueryLogger::queryTrim($query), 'time' => Number::numFormat($time * 1000, 2, ',', ''), 'unit' => 'ms', 'source' => 'Кеш (сохранено)', 'ttl' => $ttl . 's' ]; } /** * Получить все отладочные сообщения * @return array */ public static function getDebugList() { return self::$_debug_list; } /** * Получить количество запросов * @return array ['total' => int, 'from_cache' => int, 'from_db' => int, 'cached_saved' => int] */ public static function getStats() { $stats = [ 'total' => 0, 'from_cache' => 0, 'from_db' => 0, 'cached_saved' => 0 ]; foreach (self::$_debug_list as $item) { $stats['total']++; switch ($item['type']) { case 'cache_hit': case 'cache_save': $stats['from_cache']++; break; case 'direct': $stats['from_db']++; break; } if ($item['type'] === 'cache_save') { $stats['cached_saved']++; } } return $stats; } /** * Очистить список отладки */ public static function clear() { self::$_debug_list = []; } /** * Сформировать HTML отчет для отладки * @return string */ public static function getHtmlReport() { if (!self::$_enabled || empty(self::$_debug_list)) { return ''; } $stats = self::getStats(); $totalTime = 0; foreach (self::$_debug_list as $item) { $totalTime += floatval($item['time']); } $html = '
'; $html .= '
'; $html .= 'SQL Debug Report | '; $html .= 'Всего запросов: ' . $stats['total'] . ' | '; $html .= 'Из кеша: ' . $stats['from_cache'] . ' | '; $html .= 'Напрямую: ' . $stats['from_db'] . ' | '; $html .= 'Кеш сохранено: ' . $stats['cached_saved'] . ' | '; $html .= 'Общее время: ' . Number::numFormat($totalTime, 2, ',', '') . ' ms'; $html .= '
'; $html .= ''; $html .= ''; $html .= ''; $html .= ''; $html .= ''; $html .= ''; $html .= ''; $html .= ''; foreach (self::$_debug_list as $item) { $bgColor = $item['source'] === 'Кеш' ? '#e8f5e8' : '#f5f5f5'; if ($item['source'] === 'Кеш (сохранено)') { $bgColor = '#fff3e0'; } $html .= ''; $html .= ''; $html .= ''; $html .= ''; $html .= ''; $html .= ''; } $html .= '
ТипИсточникВремяЗапрос
' . htmlspecialchars($item['type']) . '' . htmlspecialchars($item['source']) . '' . $item['time'] . ' ' . $item['unit'] . ''; $html .= htmlspecialchars($item['query']); if (isset($item['ttl'])) { $html .= ' [' . $item['ttl'] . ']'; } if (isset($item['affected'])) { $html .= ' (' . $item['affected'] . ' rows)'; } $html .= '
'; return $html; } }