Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Model/Table/PanelsTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
class PanelsTable extends Table
{
use LazyTableTrait;
use SqlTraceTrait;

/**
* initialize method
Expand Down
1 change: 1 addition & 0 deletions src/Model/Table/RequestsTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
class RequestsTable extends Table
{
use LazyTableTrait;
use SqlTraceTrait;

/**
* initialize method
Expand Down
95 changes: 95 additions & 0 deletions src/Model/Table/SqlTraceTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);

/**
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 5.0.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace DebugKit\Model\Table;

use Cake\Core\Configure;
use Cake\Error\Debugger;
use Cake\ORM\Query\DeleteQuery;
use Cake\ORM\Query\SelectQuery;
use Cake\ORM\Query\UpdateQuery;

/**
* Add this trait to your Table class to append the file reference of where a Query object was created.
*
* @mixin \Cake\ORM\Table
*/
trait SqlTraceTrait
{
/**
* Overwrite parent table method to inject SQL comment
*/
public function selectQuery(): SelectQuery
{
return $this->fileStamp(parent::selectQuery());
}

/**
* Overwrite parent table method to inject SQL comment
*/
public function updateQuery(): UpdateQuery
{
return $this->fileStamp(parent::updateQuery());
}

/**
* Overwrite parent table method to inject SQL comment
*/
public function deleteQuery(): DeleteQuery
{
return $this->fileStamp(parent::deleteQuery());
}

/**
* Applies a comment to a query about which file created it.
*
* @template T of \Cake\ORM\Query\SelectQuery|\Cake\ORM\Query\UpdateQuery|\Cake\ORM\Query\DeleteQuery
* @param \Cake\ORM\Query\SelectQuery|\Cake\ORM\Query\UpdateQuery|\Cake\ORM\Query\DeleteQuery $query The Query to insert a comment into.
* @psalm-param T $query
* @param int $start How many entries in the stack trace to skip.
* @param bool $debugOnly False to always stamp queries with a comment.
* @return \Cake\ORM\Query\SelectQuery|\Cake\ORM\Query\UpdateQuery|\Cake\ORM\Query\DeleteQuery
* @psalm-return T
*/
protected function fileStamp(
SelectQuery|UpdateQuery|DeleteQuery $query,
int $start = 1,
bool $debugOnly = true
): SelectQuery|UpdateQuery|DeleteQuery {
if (!Configure::read('debug') && $debugOnly === true) {
return $query;
}

$traces = Debugger::trace(['start' => $start, 'format' => 'array']);
$file = '[unknown]';
$line = '??';

if (is_array($traces)) {
foreach ($traces as $trace) {
$path = $trace['file'];
$line = $trace['line'];
$file = Debugger::trimPath($path);
if ($path === '[internal]') {
continue;
}
if (defined('CAKE_CORE_INCLUDE_PATH') && strpos($path, CAKE_CORE_INCLUDE_PATH) !== 0) {
break;
}
}
}

return $query->comment(sprintf('%s (line %s)', $file, $line));
}
}
106 changes: 106 additions & 0 deletions tests/TestCase/Model/Table/SqlTraceTraitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php
declare(strict_types=1);

/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 5.0.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace DebugKit\Test\TestCase\Model\Table;

use Cake\Core\Configure;
use Cake\ORM\Locator\LocatorAwareTrait;
use Cake\TestSuite\TestCase;

/**
* Tests for SqlTraceTrait debugging comments.
*/
class SqlTraceTraitTest extends TestCase
{
use LocatorAwareTrait;

/**
* Fixtures
*/
public array $fixtures = [
'plugin.DebugKit.Requests',
'plugin.DebugKit.Panels',
];

/**
* Table names.
*/
public array $tables = [
'DebugKit.Panels',
'DebugKit.Requests',
];

protected bool $debug;

protected function setUp(): void
{
parent::setUp();
$this->debug = Configure::read('App.debug', true);
}

public function tearDown(): void
{
parent::tearDown();
Configure::write('App.debug', $this->debug);
}

/**
* Verify file name when calling find()
*/
public function testFind()
{
foreach ($this->tables as $table) {
$table = $this->fetchTable($table);
$sql = $table->find()->select(['id'])->sql();
$this->assertTrue(str_contains($sql, basename(__FILE__)), 'Expected file: ' . $sql);
}
}

/**
* Verify file name when calling query()/select()
*/
public function testQuery()
{
foreach ($this->tables as $table) {
$table = $this->fetchTable($table);
$sql = $table->query()->sql();
$this->assertTrue(str_contains($sql, basename(__FILE__)), 'Expected file: ' . $sql);
}
}

/**
* Verify file name when calling update()
*/
public function testUpdate()
{
foreach ($this->tables as $table) {
$table = $this->fetchTable($table);
$sql = $table->updateQuery()->set(['title' => 'fooBar'])->sql();
$this->assertTrue(str_contains($sql, basename(__FILE__)), 'Expected file: ' . $sql);
}
}

/**
* Verify file name when calling delete()
*/
public function testDelete()
{
foreach ($this->tables as $table) {
$table = $this->fetchTable($table);
$sql = $table->deleteQuery()->where(['title' => 'fooBar'])->sql();
$this->assertTrue(str_contains($sql, basename(__FILE__)), 'Expected file: ' . $sql);
}
}
}