From 1fa5c8616c0cba31830151a1026542bd9a3afd38 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Fri, 7 Jan 2022 10:48:08 +0800 Subject: [PATCH] Refactor Database Collector display --- system/Debug/Toolbar/Collectors/Database.php | 34 ++++++------ system/Debug/Toolbar/Views/_database.tpl | 4 +- .../Debug/Toolbar/Collectors/DatabaseTest.php | 54 +++++++++++++++++++ 3 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 tests/system/Debug/Toolbar/Collectors/DatabaseTest.php diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php index 520ddc7c5dc6..ef6e0f9c85c8 100644 --- a/system/Debug/Toolbar/Collectors/Database.php +++ b/system/Debug/Toolbar/Collectors/Database.php @@ -89,7 +89,7 @@ public static function collect(Query $query) 'query' => $query, 'string' => $queryString, 'duplicate' => in_array($queryString, array_column(static::$queries, 'string', null), true), - 'trace' => debug_backtrace(), + 'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), ]; } } @@ -134,23 +134,24 @@ public function display(): array $data['queries'] = array_map(static function (array $query) { $isDuplicate = $query['duplicate'] === true; - // Find the first line that doesn't include `system` in the backtrace - $line = []; - - foreach ($query['trace'] as &$traceLine) { - // Clean up the file paths - $traceLine['file'] = str_ireplace(APPPATH, 'APPPATH/', $traceLine['file']); - $traceLine['file'] = str_ireplace(SYSTEMPATH, 'SYSTEMPATH/', $traceLine['file']); - if (defined('VENDORPATH')) { - // VENDORPATH is not defined unless `vendor/autoload.php` exists - $traceLine['file'] = str_ireplace(VENDORPATH, 'VENDORPATH/', $traceLine['file']); + foreach ($query['trace'] as &$line) { + if (isset($line['file'])) { + $line['file'] = clean_path($line['file']) . ':' . $line['line']; + unset($line['line']); + } else { + $line['file'] = '[internal function]'; } - $traceLine['file'] = str_ireplace(ROOTPATH, 'ROOTPATH/', $traceLine['file']); + } + + // Find the first line that doesn't include `system` in the backtrace + $firstNonSystemLine = ''; + + foreach ($query['trace'] as $line) { + if (strpos($line['file'], 'SYSTEMPATH') === false) { + $firstNonSystemLine = $line['file']; - if (strpos($traceLine['file'], 'SYSTEMPATH') !== false) { - continue; + break; } - $line = empty($line) ? $traceLine : $line; } return [ @@ -159,8 +160,7 @@ public function display(): array 'duration' => ((float) $query['query']->getDuration(5) * 1000) . ' ms', 'sql' => $query['query']->debugToolbarDisplay(), 'trace' => $query['trace'], - 'trace-file' => str_replace(ROOTPATH, '/', $line['file'] ?? ''), - 'trace-line' => $line['line'] ?? '', + 'trace-file' => $firstNonSystemLine, 'qid' => md5($query['query'] . microtime()), ]; }, static::$queries); diff --git a/system/Debug/Toolbar/Views/_database.tpl b/system/Debug/Toolbar/Views/_database.tpl index a2f5bd9808f1..e5260a52a8c2 100644 --- a/system/Debug/Toolbar/Views/_database.tpl +++ b/system/Debug/Toolbar/Views/_database.tpl @@ -10,13 +10,13 @@ {duration} {! sql !} - {trace-file}:{trace-line} + {trace-file} {trace} - {file}:{line}
+ {file}
{/trace} diff --git a/tests/system/Debug/Toolbar/Collectors/DatabaseTest.php b/tests/system/Debug/Toolbar/Collectors/DatabaseTest.php new file mode 100644 index 000000000000..7ad1a49fdb5c --- /dev/null +++ b/tests/system/Debug/Toolbar/Collectors/DatabaseTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Debug\Toolbar\Collectors; + +use CodeIgniter\Database\Query; +use CodeIgniter\Test\CIUnitTestCase; +use PHPUnit\Framework\MockObject\MockObject; + +/** + * @internal + */ +final class DatabaseTest extends CIUnitTestCase +{ + public function testDisplay(): void + { + /** @var MockObject&Query $query */ + $query = $this->getMockBuilder(Query::class) + ->disableOriginalConstructor() + ->getMock(); + + // set mock returns + $query->method('getQuery')->willReturn('SHOW TABLES;'); + $query->method('debugToolbarDisplay')->willReturn('SHOW TABLES;'); + $query->method('getDuration')->with(5)->willReturn('1.23456'); + + Database::collect($query); // <== $query will be called here + $collector = new Database(); + + $queries = $collector->display()['queries']; + + $this->assertSame('1234.56 ms', $queries[0]['duration']); + $this->assertSame('SHOW TABLES;', $queries[0]['sql']); + $this->assertSame(clean_path(__FILE__) . ':35', $queries[0]['trace-file']); + + foreach ($queries[0]['trace'] as $trace) { + // since we merged file & line together + $this->assertArrayNotHasKey('line', $trace); + $this->assertArrayHasKey('file', $trace); + + // since we dropped object & args in the backtrace for performance + $this->assertArrayNotHasKey('object', $trace); + $this->assertArrayNotHasKey('args', $trace); + } + } +}