diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e93b190..d289d1f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -68,7 +68,7 @@ jobs: run: composer install --prefer-dist --no-progress --no-suggest - name: Run test suite - run: ./vendor/bin/phpunit + run: ./vendor/bin/phpunit tests test_mysql80: @@ -131,4 +131,4 @@ jobs: run: composer install --prefer-dist --no-progress --no-suggest - name: Run test suite - run: ./vendor/bin/phpunit + run: ./vendor/bin/phpunit tests diff --git a/composer.json b/composer.json index f135ce1..47f846e 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,6 @@ "phpunit/phpunit": "6.5.14" }, "scripts": { - "test": "phpunit" + "test": "phpunit tests" } } diff --git a/lib/PicoDb/StatementHandler.php b/lib/PicoDb/StatementHandler.php index b06f940..5abd995 100644 --- a/lib/PicoDb/StatementHandler.php +++ b/lib/PicoDb/StatementHandler.php @@ -54,6 +54,14 @@ class StatementHandler */ protected $logQueries = false; + /** + * Flag to combine values in the logged SQL queries. + * + * @access protected + * @var boolean + */ + protected $logQueryValues = false; + /** * Run explain command on each query * @@ -125,10 +133,12 @@ public function __construct(Database $db) * Enable query logging * * @access public + * @param bool $includeValues * @return $this */ - public function withLogging() + public function withLogging(bool $includeValues = false) { + $this->logQueryValues = $includeValues; $this->logQueries = true; return $this; } @@ -229,6 +239,7 @@ public function getNbQueries() * * @access public * @return PDOStatement|false + * @throws SQLException */ public function execute() { @@ -285,7 +296,26 @@ protected function bindParams(PDOStatement $pdoStatement) protected function beforeExecute() { if ($this->logQueries) { - $this->db->setLogMessage($this->sql); + $sql = $this->sql; + if ($this->logQueryValues) { + $params = $this->lobParams ?: $this->positionalParams ?: $this->namedParams; + + if ($this->useNamedParams) { + $sql = preg_replace_callback('/:([a-zA-Z0-9_]+)/', function ($matches) use ($params) { + $paramName = $matches[1]; + $replacement = $params[$paramName] ?? $matches[0]; + return "'$replacement'"; + }, $sql); + } else { + $i = 0; + $sql = preg_replace_callback('/\?/', function($matches) use ($params, &$i) { + $replacement = $params[$i] ?? ''; + $i++; + return "'$replacement'"; + }, $sql); + } + } + $this->db->setLogMessage($sql); } if ($this->stopwatch) { @@ -335,7 +365,6 @@ protected function cleanup() * * @access public * @param PDOException $e - * @return bool * @throws SQLException */ public function handleSqlError(PDOException $e) diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index ac2dd62..0000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,28 +0,0 @@ - - - - tests/UrlParserTest.php - tests/SqliteDriverTest.php - tests/SqliteDatabaseTest.php - tests/SqliteSchemaTest.php - tests/SqliteTableTest.php - - - tests/UrlParserTest.php - tests/MysqlDriverTest.php - tests/MysqlDatabaseTest.php - tests/MysqlSchemaTest.php - tests/MysqlTableTest.php - - - tests/UrlParserTest.php - tests/PostgresDriverTest.php - tests/PostgresDatabaseTest.php - tests/PostgresSchemaTest.php - tests/PostgresTableTest.php - - - diff --git a/tests/PicoDb/StatementHandlerTest.php b/tests/PicoDb/StatementHandlerTest.php new file mode 100644 index 0000000..6c81520 --- /dev/null +++ b/tests/PicoDb/StatementHandlerTest.php @@ -0,0 +1,106 @@ +db = new Database(array('driver' => 'sqlite', 'filename' => ':memory:')); + $this->statementHandler = new StatementHandler($this->db); + parent::setUp(); + } + + + public function testBeforeExecuteLogs() + { + // create an anon class that extends statement handler + $statementHandler = new class($this->db) extends StatementHandler { + + /** + * A wrapper to set the state of the class before running the protected var. + * + * @param array{ + * 'logQueries': boolean, + * 'logQueryValues': boolean, + * 'sql': string, + * 'lobParams': array, + * 'positionalParams': array, + * 'namedParams': array + * } $props + * @return void + */ + public function testBeforeExecute(array $props) + { + foreach ($props as $key => $value) { + $this->{$key} = $value; + } + $this->beforeExecute(); + } + }; + + $statementHandler->testBeforeExecute([ + 'logQueries' => true, + 'logQueryValues' => true, + 'useNamedParams' => false, + 'sql' => "SELECT * FROM `some_table` WHERE `someCoumn` = ? and `someOtherColumn` = ?", + 'lobParams' => ['first value has a ? inside it', 'second value'], + 'positionalParams' => [], + 'namedParams' => [] + ]); + + $logMessages = $this->db->getLogMessages(); + self::assertCount(1, $logMessages); + self::assertEquals( + "SELECT * FROM `some_table` WHERE `someCoumn` = 'first value has a ? inside it' and `someOtherColumn` = 'second value'", + $logMessages[0], + var_export($logMessages, true) + ); + + + // now test with positional params + $statementHandler->testBeforeExecute([ + 'logQueries' => true, + 'logQueryValues' => true, + 'sql' => "SELECT * FROM `some_table` WHERE `someCoumn` = ? and `someOtherColumn` = ?", + 'lobParams' => [], + 'positionalParams' => ['first value has a ? inside it', 'second value'], + 'namedParams' => [] + ]); + + $logMessages = $this->db->getLogMessages(); + self::assertCount(2, $logMessages); + self::assertEquals( + "SELECT * FROM `some_table` WHERE `someCoumn` = 'first value has a ? inside it' and `someOtherColumn` = 'second value'", + $logMessages[1], + var_export($logMessages, true) + ); + + // now test with named params + $statementHandler->testBeforeExecute([ + 'logQueries' => true, + 'logQueryValues' => true, + 'useNamedParams' => true, + 'sql' => "SELECT * FROM `some_table` WHERE `someCoumn` = :first and `someOtherColumn` = :second", + 'lobParams' => [], + 'positionalParams' => [], + 'namedParams' => ['first' => 'first value has :second inside it', 'second' => 'second value'] + ]); + + $logMessages = $this->db->getLogMessages(); + self::assertCount(3, $logMessages); + self::assertEquals( + "SELECT * FROM `some_table` WHERE `someCoumn` = 'first value has :second inside it' and `someOtherColumn` = 'second value'", + $logMessages[2], + var_export($logMessages, true) + ); + } +}