mirror of
https://github.com/torrentpier/torrentpier
synced 2025-08-22 14:23:57 -07:00
feat(database): add visual markers for Nette Explorer queries in debug panel
Add automatic detection and colorful badges to distinguish Nette Explorer queries from legacy database calls, helping track modernization progress. - Detect Nette SQL patterns (backticks, parentheses) - Add green styled [Nette Explorer] badges - Fix HTML escaping in debug tooltips - Prevent marker duplication
This commit is contained in:
parent
6c0219d53c
commit
91cc6fe0a9
3 changed files with 103 additions and 1 deletions
|
@ -34,6 +34,9 @@ class DatabaseDebugger
|
|||
public string $explain_hold = '';
|
||||
public string $explain_out = '';
|
||||
|
||||
// Nette Explorer tracking
|
||||
public bool $is_nette_explorer_query = false;
|
||||
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
|
@ -70,6 +73,12 @@ class DatabaseDebugger
|
|||
|
||||
if ($this->dbg_enabled) {
|
||||
$dbg['sql'] = preg_replace('#^(\s*)(/\*)(.*)(\*/)(\s*)#', '', $this->db->cur_query);
|
||||
|
||||
// Also check SQL syntax to detect Nette Explorer queries
|
||||
if (!$this->is_nette_explorer_query && $this->detectNetteExplorerBySqlSyntax($dbg['sql'])) {
|
||||
$this->markAsNetteExplorerQuery();
|
||||
}
|
||||
|
||||
$dbg['src'] = $this->debug_find_source();
|
||||
$dbg['file'] = $this->debug_find_source('file');
|
||||
$dbg['line'] = $this->debug_find_source('line');
|
||||
|
@ -96,6 +105,18 @@ class DatabaseDebugger
|
|||
$dbg['time'] = $this->cur_query_time > 0 ? $this->cur_query_time : (microtime(true) - $this->sql_starttime);
|
||||
$dbg['info'] = $this->db->query_info();
|
||||
$dbg['mem_after'] = function_exists('sys') ? sys('mem') : 0;
|
||||
|
||||
// Add Nette Explorer marker to debug info for panel display
|
||||
if ($this->is_nette_explorer_query && !str_contains($dbg['info'], '[Nette Explorer]')) {
|
||||
// Store both plain text and HTML versions
|
||||
$dbg['info_plain'] = $dbg['info'] . ' [Nette Explorer]';
|
||||
$dbg['info'] .= ' <span style="color: #28a745; font-weight: bold; background: #d4edda; padding: 2px 6px; border-radius: 3px; font-size: 11px;">[Nette Explorer]</span>';
|
||||
$dbg['is_nette_explorer'] = true;
|
||||
} else {
|
||||
$dbg['info_plain'] = $dbg['info'];
|
||||
$dbg['is_nette_explorer'] = false;
|
||||
}
|
||||
|
||||
$id++;
|
||||
}
|
||||
|
||||
|
@ -108,6 +129,9 @@ class DatabaseDebugger
|
|||
$this->log_query($this->db->DBS['log_file']);
|
||||
$this->db->DBS['log_counter']--;
|
||||
}
|
||||
|
||||
// Reset Nette Explorer flag after query completion
|
||||
$this->resetNetteExplorerFlag();
|
||||
}
|
||||
|
||||
// Update timing in main Database object
|
||||
|
@ -125,6 +149,12 @@ class DatabaseDebugger
|
|||
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
|
||||
// Check if this is a Nette Explorer query by examining the call stack
|
||||
$isNetteExplorer = $this->detectNetteExplorerInTrace($trace);
|
||||
if ($isNetteExplorer) {
|
||||
$this->markAsNetteExplorerQuery();
|
||||
}
|
||||
|
||||
// Find first non-DB call (skip Database.php, DebugSelection.php, and DatabaseDebugger.php)
|
||||
foreach ($trace as $frame) {
|
||||
if (isset($frame['file']) &&
|
||||
|
@ -148,6 +178,57 @@ class DatabaseDebugger
|
|||
return 'src not found';
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if the current query comes from Nette Explorer by examining the call stack
|
||||
*/
|
||||
public function detectNetteExplorerInTrace(array $trace): bool
|
||||
{
|
||||
foreach ($trace as $frame) {
|
||||
if (isset($frame['class'])) {
|
||||
// Check for Nette Database classes in the call stack
|
||||
if (str_contains($frame['class'], 'Nette\\Database\\') ||
|
||||
str_contains($frame['class'], 'TorrentPier\\Database\\DebugSelection')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($frame['file'])) {
|
||||
// Check for Nette Database files or our DebugSelection
|
||||
if (str_contains($frame['file'], 'vendor/nette/database/') ||
|
||||
str_contains($frame['file'], 'Database/DebugSelection.php')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if SQL query syntax suggests it came from Nette Explorer
|
||||
*/
|
||||
public function detectNetteExplorerBySqlSyntax(string $sql): bool
|
||||
{
|
||||
// Nette Database typically generates SQL with these characteristics:
|
||||
// 1. Backticks around column/table names
|
||||
// 2. Parentheses around WHERE conditions like (column = value)
|
||||
// 3. Specific patterns like IN (value) instead of IN (value)
|
||||
|
||||
$nettePatterns = [
|
||||
'/`[a-zA-Z0-9_]+`/', // Backticks around identifiers
|
||||
'/WHERE\s*\([^)]+\)/', // Parentheses around WHERE conditions
|
||||
'/SELECT\s+`[^`]+`.*FROM\s+`[^`]+`/', // SELECT with backticked columns and tables
|
||||
];
|
||||
|
||||
foreach ($nettePatterns as $pattern) {
|
||||
if (preg_match($pattern, $sql)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare for logging
|
||||
*/
|
||||
|
@ -346,4 +427,20 @@ class DatabaseDebugger
|
|||
$this->explain_hold = '';
|
||||
$this->explain_out = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark next query as coming from Nette Explorer
|
||||
*/
|
||||
public function markAsNetteExplorerQuery(): void
|
||||
{
|
||||
$this->is_nette_explorer_query = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Nette Explorer query flag
|
||||
*/
|
||||
public function resetNetteExplorerFlag(): void
|
||||
{
|
||||
$this->is_nette_explorer_query = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,9 @@ class DebugSelection
|
|||
// Use the actual SQL with substituted parameters for both logging and EXPLAIN
|
||||
$sql = $this->generateSqlForLogging($method, $arguments, false);
|
||||
|
||||
// Mark this query as coming from Nette Explorer
|
||||
$this->db->debugger->markAsNetteExplorerQuery();
|
||||
|
||||
// Set the query for debug logging
|
||||
$this->db->cur_query = $sql;
|
||||
$this->db->debug('start');
|
||||
|
|
|
@ -258,9 +258,11 @@ class Dev
|
|||
$sql = $this->shortQueryInstance($dbg['sql'], true);
|
||||
$time = sprintf('%.3f', $dbg['time']);
|
||||
$perc = '[' . round($dbg['time'] * 100 / $db_obj->sql_timetotal) . '%]';
|
||||
// Use plain text version for title attribute to avoid HTML issues
|
||||
$info_plain = !empty($dbg['info_plain']) ? $dbg['info_plain'] . ' [' . $dbg['src'] . ']' : $dbg['src'];
|
||||
$info = !empty($dbg['info']) ? $dbg['info'] . ' [' . $dbg['src'] . ']' : $dbg['src'];
|
||||
|
||||
$log .= '<div onclick="$(this).toggleClass(\'sqlHighlight\');" class="sqlLogRow" title="' . $info . '">'
|
||||
$log .= '<div onclick="$(this).toggleClass(\'sqlHighlight\');" class="sqlLogRow" title="' . htmlspecialchars($info_plain) . '">'
|
||||
. '<span style="letter-spacing: -1px;">' . $time . ' </span>'
|
||||
. '<span class="copyElement" data-clipboard-target="#' . $id . '" title="Copy to clipboard" style="color: rgb(128,128,128); letter-spacing: -1px;">' . $perc . '</span> '
|
||||
. '<span style="letter-spacing: 0;" id="' . $id . '">' . $sql . '</span>'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue