Skip to content

Commit 973ab18

Browse files
committed
Refactor Database Collector display
1 parent a09f7d9 commit 973ab18

File tree

3 files changed

+103
-19
lines changed

3 files changed

+103
-19
lines changed

system/Debug/Toolbar/Collectors/Database.php

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public static function collect(Query $query)
8989
'query' => $query,
9090
'string' => $queryString,
9191
'duplicate' => in_array($queryString, array_column(static::$queries, 'string', null), true),
92-
'trace' => debug_backtrace(),
92+
'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS),
9393
];
9494
}
9595
}
@@ -134,23 +134,46 @@ public function display(): array
134134
$data['queries'] = array_map(static function (array $query) {
135135
$isDuplicate = $query['duplicate'] === true;
136136

137-
// Find the first line that doesn't include `system` in the backtrace
138-
$line = [];
139-
140-
foreach ($query['trace'] as &$traceLine) {
141-
// Clean up the file paths
142-
$traceLine['file'] = str_ireplace(APPPATH, 'APPPATH/', $traceLine['file']);
143-
$traceLine['file'] = str_ireplace(SYSTEMPATH, 'SYSTEMPATH/', $traceLine['file']);
144-
if (defined('VENDORPATH')) {
145-
// VENDORPATH is not defined unless `vendor/autoload.php` exists
146-
$traceLine['file'] = str_ireplace(VENDORPATH, 'VENDORPATH/', $traceLine['file']);
137+
foreach ($query['trace'] as $index => &$line) {
138+
// simplify file and line
139+
if (isset($line['file'])) {
140+
$line['file'] = clean_path($line['file']) . ':' . $line['line'];
141+
unset($line['line']);
142+
} else {
143+
$line['file'] = '[internal function]';
144+
}
145+
146+
// simplify function call
147+
if (isset($line['class'])) {
148+
$line['function'] = $line['class'] . $line['type'] . $line['function'];
149+
unset($line['class'], $line['type']);
147150
}
148-
$traceLine['file'] = str_ireplace(ROOTPATH, 'ROOTPATH/', $traceLine['file']);
149151

150-
if (strpos($traceLine['file'], 'SYSTEMPATH') !== false) {
151-
continue;
152+
if (strrpos($line['function'], '{closure}') === false) {
153+
$line['function'] .= '()';
154+
}
155+
156+
$line['function'] = str_repeat(chr(0xC2) . chr(0xA0), 8) . $line['function'];
157+
158+
// add index numbering padded with nonbreaking space
159+
$indexPadded = str_pad(sprintf('%d', $index + 1), 3, ' ', STR_PAD_LEFT);
160+
$indexPadded = preg_replace('/\s/', chr(0xC2) . chr(0xA0), $indexPadded);
161+
162+
$line['index'] = $indexPadded . str_repeat(chr(0xC2) . chr(0xA0), 4);
163+
}
164+
165+
// remove the caller trace which is duplicated as the last item
166+
array_pop($query['trace']);
167+
168+
// Find the first line that doesn't include `system` in the backtrace
169+
$firstNonSystemLine = '';
170+
171+
foreach ($query['trace'] as $line) {
172+
if (strpos($line['file'], 'SYSTEMPATH') === false) {
173+
$firstNonSystemLine = $line['file'];
174+
175+
break;
152176
}
153-
$line = empty($line) ? $traceLine : $line;
154177
}
155178

156179
return [
@@ -159,8 +182,7 @@ public function display(): array
159182
'duration' => ((float) $query['query']->getDuration(5) * 1000) . ' ms',
160183
'sql' => $query['query']->debugToolbarDisplay(),
161184
'trace' => $query['trace'],
162-
'trace-file' => str_replace(ROOTPATH, '/', $line['file'] ?? ''),
163-
'trace-line' => $line['line'] ?? '',
185+
'trace-file' => $firstNonSystemLine,
164186
'qid' => md5($query['query'] . microtime()),
165187
];
166188
}, static::$queries);

system/Debug/Toolbar/Views/_database.tpl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
<tr class="{class}" title="{hover}" data-toggle="{qid}-trace">
1111
<td class="narrow">{duration}</td>
1212
<td>{! sql !}</td>
13-
<td style="text-align: right">{trace-file}:<strong>{trace-line}</strong></td>
13+
<td style="text-align: right"><strong>{trace-file}</strong></td>
1414
</tr>
1515
<tr class="muted" id="{qid}-trace" style="display:none">
1616
<td></td>
1717
<td colspan="2">
1818
{trace}
19-
{file}:<strong>{line}</strong><br/>
19+
{index}<strong>{file}</strong><br/>
20+
{function}<br/><br/>
2021
{/trace}
2122
</td>
2223
</tr>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
/**
4+
* This file is part of CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <[email protected]>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
namespace CodeIgniter\Debug\Toolbar\Collectors;
13+
14+
use CodeIgniter\Database\Query;
15+
use CodeIgniter\Test\CIUnitTestCase;
16+
use PHPUnit\Framework\MockObject\MockObject;
17+
18+
/**
19+
* @internal
20+
*/
21+
final class DatabaseTest extends CIUnitTestCase
22+
{
23+
public function testDisplay(): void
24+
{
25+
/** @var MockObject&Query $query */
26+
$query = $this->getMockBuilder(Query::class)
27+
->disableOriginalConstructor()
28+
->getMock();
29+
30+
// set mock returns
31+
$query->method('getQuery')->willReturn('SHOW TABLES;');
32+
$query->method('debugToolbarDisplay')->willReturn('<strong>SHOW</strong> TABLES;');
33+
$query->method('getDuration')->with(5)->willReturn('1.23456');
34+
35+
Database::collect($query); // <== $query will be called here
36+
$collector = new Database();
37+
38+
$queries = $collector->display()['queries'];
39+
40+
$this->assertSame('1234.56 ms', $queries[0]['duration']);
41+
$this->assertSame('<strong>SHOW</strong> TABLES;', $queries[0]['sql']);
42+
$this->assertSame(clean_path(__FILE__) . ':35', $queries[0]['trace-file']);
43+
44+
foreach ($queries[0]['trace'] as $i => $trace) {
45+
// since we added the index numbering
46+
$this->assertArrayHasKey('index', $trace);
47+
$this->assertSame(
48+
sprintf('%s', $i + 1),
49+
preg_replace(sprintf('/%s/', chr(0xC2) . chr(0xA0)), '', $trace['index'])
50+
);
51+
52+
// since we merged file & line together
53+
$this->assertArrayNotHasKey('line', $trace);
54+
$this->assertArrayHasKey('file', $trace);
55+
56+
// since we dropped object & args in the backtrace for performance
57+
$this->assertArrayNotHasKey('object', $trace);
58+
$this->assertArrayNotHasKey('args', $trace);
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)