diff --git a/src/Model/Table/PanelsTable.php b/src/Model/Table/PanelsTable.php index 3e167ef9..33516fac 100644 --- a/src/Model/Table/PanelsTable.php +++ b/src/Model/Table/PanelsTable.php @@ -34,6 +34,7 @@ class PanelsTable extends Table { use LazyTableTrait; + use SqlTraceTrait; /** * initialize method diff --git a/src/Model/Table/RequestsTable.php b/src/Model/Table/RequestsTable.php index 75cefc4a..1b5f724a 100644 --- a/src/Model/Table/RequestsTable.php +++ b/src/Model/Table/RequestsTable.php @@ -36,6 +36,7 @@ class RequestsTable extends Table { use LazyTableTrait; + use SqlTraceTrait; /** * initialize method diff --git a/src/Model/Table/SqlTraceTrait.php b/src/Model/Table/SqlTraceTrait.php new file mode 100644 index 00000000..8856306c --- /dev/null +++ b/src/Model/Table/SqlTraceTrait.php @@ -0,0 +1,95 @@ +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)); + } +} diff --git a/tests/TestCase/Model/Table/SqlTraceTraitTest.php b/tests/TestCase/Model/Table/SqlTraceTraitTest.php new file mode 100644 index 00000000..32fcfb85 --- /dev/null +++ b/tests/TestCase/Model/Table/SqlTraceTraitTest.php @@ -0,0 +1,106 @@ +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); + } + } +}