diff --git a/classes/Database.php b/classes/Database.php index 290d014..db01be2 100644 --- a/classes/Database.php +++ b/classes/Database.php @@ -13,6 +13,8 @@ * @license http://www.opensource.org/licenses/mit-license.html * @package PICKLES * @link https://github.com/joshtronic/pickles + * @todo Drop driver, hardcode drivers based on the type + * @todo More assumptions for the datasource variables */ /** @@ -231,12 +233,6 @@ class Database extends Object { if ($this->connection === null) { - // Checks that the prefix is set - if ($this->dsn == null) - { - throw new Exception('Data source name is not defined'); - } - switch ($this->driver) { case 'pdo_mysql': @@ -256,30 +252,22 @@ class Database extends Object if (isset($this->username, $this->password, $this->database)) { - // Creates a new PDO database object (persistent) - try - { - // Swaps out any variables with values in the DSN - $this->dsn = str_replace( - ['[[hostname]]', '[[port]]', '[[socket]]', '[[username]]', '[[password]]', '[[database]]'], - [$this->hostname, $this->port, $this->socket, $this->username, $this->password, $this->database], - $this->dsn - ); + // Swaps out any variables with values in the DSN + $this->dsn = str_replace( + ['[[hostname]]', '[[port]]', '[[socket]]', '[[username]]', '[[password]]', '[[database]]'], + [$this->hostname, $this->port, $this->socket, $this->username, $this->password, $this->database], + $this->dsn + ); - // Strips any empty parameters in the DSN - $this->dsn = str_replace(['host=;', 'port=;', 'unix_socket=;'], '', $this->dsn); + // Strips any empty parameters in the DSN + $this->dsn = str_replace(['host=;', 'port=;', 'unix_socket=;'], '', $this->dsn); - // Attempts to establish a connection - $this->connection = new PDO($this->dsn, $this->username, $this->password, $this->attributes); - } - catch (PDOException $e) - { - throw new Exception($e); - } + // Attempts to establish a connection + $this->connection = new PDO($this->dsn, $this->username, $this->password, $this->attributes); } else { - throw new Exception('There was an error loading the database configuration'); + throw new Exception('There was an error loading the database configuration.'); } } @@ -308,9 +296,10 @@ class Database extends Object * * @param string $sql statement to execute * @param array $input_parameters optional key/values to be bound + * @param boolean $force_slow optional, force slow query logging * @return integer ID of the last inserted row or sequence number */ - public function execute($sql, $input_parameters = null) + public function execute($sql, $input_parameters = null, $force_slow = false) { $this->open(); @@ -347,68 +336,59 @@ class Database extends Object $sql .= "\n" . '/* [' . implode('|', $files) . '] */'; - try + // Establishes if we're working on an EXPLAIN + if (Profiler::enabled('explains')) { - // Establishes if we're working on an EXPLAIN - if (Profiler::enabled('explains') == true) - { - $explaining = preg_match('/^EXPLAIN /i', $sql); - $selecting = preg_match('/^SELECT /i', $sql); - } - else - { - $explaining = null; - $selecting = null; - } - - // Executes a standard query - if ($input_parameters === null) - { - // Explains the query - if ($selecting == true && $explaining == false) - { - $explain = $this->fetch('EXPLAIN ' . $sql); - } - - $start_time = microtime(true); - $this->results = $this->connection->query($sql); - } - // Executes a prepared statement - else - { - // Explains the query - if ($selecting == true && $explaining == false) - { - $explain = $this->fetch('EXPLAIN ' . $sql, $input_parameters); - } - - $start_time = microtime(true); - $this->results = $this->connection->prepare($sql); - $this->results->execute($input_parameters); - } - - $end_time = microtime(true); - $duration = $end_time - $start_time; - - if ($duration >= 1) - { - Log::slowQuery($duration . ' seconds: ' . $loggable_query); - } - - // Logs the information to the profiler - if ($explaining == false && Profiler::enabled('explains', 'queries')) - { - Profiler::logQuery($sql, $input_parameters, (isset($explain) ? $explain : false), $duration); - } + $explain = preg_match('/^SELECT /i', $sql); } - catch (PDOException $e) + else { - throw new Exception($e); + $explain = null; + } + + // Executes a standard query + if ($input_parameters === null) + { + // Explains the query + if ($explain) + { + $explain = $this->fetch('EXPLAIN ' . $sql); + } + + $start_time = microtime(true); + $this->results = $this->connection->query($sql); + } + // Executes a prepared statement + else + { + // Explains the query + if ($explain) + { + $explain = $this->fetch('EXPLAIN ' . $sql, $input_parameters); + } + + $start_time = microtime(true); + $this->results = $this->connection->prepare($sql); + $this->results->execute($input_parameters); + } + + $end_time = microtime(true); + $duration = $end_time - $start_time; + + if ($duration >= 1 || $force_slow) + { + Log::slowQuery($duration . ' seconds: ' . $loggable_query); + } + + // Logs the information to the profiler + if (Profiler::enabled('explains', 'queries')) + { + Profiler::logQuery($sql, $input_parameters, (isset($explain) ? $explain : false), $duration); } } else { - throw new Exception('No query to execute'); + throw new Exception('No query to execute.'); } return $this->connection->lastInsertId(); diff --git a/tests/classes/DatabaseTest.php b/tests/classes/DatabaseTest.php index 5c88f44..05bcff3 100644 --- a/tests/classes/DatabaseTest.php +++ b/tests/classes/DatabaseTest.php @@ -14,44 +14,182 @@ class DatabaseTest extends PHPUnit_Framework_TestCase public function testGetInstanceDatasourceNotDefined() { $config = Config::getInstance(); - $config->data['pickles']['datasource'] = 'mysql'; + $config->data['pickles']['datasource'] = 'bad'; Database::getInstance(); } -// /** -// * @expectedException Exception -// * @expectedExceptionMessage The specified datasource lacks a driver. -// */ -// public function testGetInstanceDatasourceLacksDriver() -// { -// $config = Config::getInstance(); -// $config->data['datasources'] = [ -// 'mysql' => [ -// 'type' => 'mysql', -// ], -// ]; -// $this->assertInstanceOf('Database', Database::getInstance()); -// } -// -// public function testGetInstanceDatasourcesArray() -// { -// $config = Config::getInstance(); -// $config->data['datasources'] = [ -// 'mysql' => [ -// 'type' => 'mysql', -// 'driver' => 'pdo_mysql', -// ], -// ]; -// $this->assertInstanceOf('Database', Database::getInstance()); -// } + /** + * @expectedException Exception + * @expectedExceptionMessage The specified datasource lacks a driver. + */ + public function testGetInstanceDatasourceLacksDriver() + { + $config = Config::getInstance(); + $config->data['datasources'] = [ + 'bad' => [ + 'type' => 'mysql', + ], + ]; + $this->assertInstanceOf('Database', Database::getInstance()); + } -// public function testGetInstanceFirstDatasource() -// { -// $config = Config::getInstance(); -// $config->data['pickles']['datasource'] = false; -// -// //$this->assertInstanceOf('Database', Database::getInstance()); -// } + /** + * @expectedException Exception + * @expectedExceptionMessage There was an error loading the database configuration. + */ + public function testOpenConfigError() + { + $config = Config::getInstance(); + $config->data['datasources'] = [ + 'bad' => [ + 'type' => 'mysql', + 'driver' => 'pdo_mysql', + 'database' => 'test', + ], + ]; + $db = Database::getInstance(); + $db->open(); + } + + public function testGetInstanceDatasourcesArray() + { + $config = Config::getInstance(); + $config->data['datasources'] = [ + 'mysql' => [ + 'type' => 'mysql', + 'driver' => 'pdo_mysql', + 'hostname' => 'localhost', + 'username' => '', + 'password' => '', + 'database' => 'test', + ], + ]; + $this->assertInstanceOf('Database', Database::getInstance()); + } + + // Also tests the datasource being missing and selecting the first one + public function testGetInstanceMySQL() + { + $config = Config::getInstance(); + unset($config->data['pickles']['datasource']); + $this->assertInstanceOf('Database', Database::getInstance()); + } + + public function testOpenMySQL() + { + $config = Config::getInstance(); + $config->data['pickles']['datasource'] = 'mysql'; + $db = Database::getInstance(); + $db->open(); + } + + public function testExecute() + { + $db = Database::getInstance(); + $this->assertEquals('0', $db->execute('SHOW TABLES')); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage No query to execute. + */ + public function testExecuteNoQuery() + { + $db = Database::getInstance(); + $db->execute(' '); + } + + public function testFetch() + { + $config = Config::getInstance(); + $config->data['pickles']['logging'] = true; + $config->data['pickles']['profiler'] = true; + $db = Database::getInstance(); + $this->assertEquals([], $db->fetch('SELECT * FROM pickles WHERE id != ?', ['0'])); + } + + public function testExplainNoInput() + { + $config = Config::getInstance(); + $db = Database::getInstance(); + $this->assertEquals([], $db->fetch('SELECT * FROM pickles WHERE id != 0')); + } + + public function testSlowQuery() + { + $db = Database::getInstance(); + $this->assertEquals('0', $db->execute('SHOW DATABASES', null, true)); + } + + public function testCloseMySQL() + { + $db = Database::getInstance(); + $db->open(); + + $this->assertTrue($db->close()); + } + + public function testGetInstancePostgreSQL() + { + $config = Config::getInstance(); + $config->data['pickles']['datasource'] = 'pgsql'; + $config->data['datasources']['pgsql'] = [ + 'type' => 'pgsql', + 'driver' => 'pdo_pgsql', + 'hostname' => 'localhost', + 'username' => '', + 'password' => '', + 'database' => 'test', + ]; + $this->assertInstanceOf('Database', Database::getInstance()); + } + + /** + * @expectedException PDOException + * @expectedExceptionMessage SQLSTATE[08006] [7] could not connect to server + * @expectedExceptionCode 7 + */ + public function testOpenPostgreSQL() + { + // Also throws an exception since I don't have PostgreSQL set up + $config = Config::getInstance(); + $db = Database::getInstance(); + $db->open(); + } + + public function testGetInstanceSQLite() + { + $config = Config::getInstance(); + $config->data['pickles']['datasource'] = 'sqlite'; + $config->data['datasources']['sqlite'] = [ + 'type' => 'sqlite', + 'driver' => 'pdo_sqlite', + 'hostname' => 'localhost', + 'username' => '', + 'password' => '', + 'database' => 'test', + ]; + $this->assertInstanceOf('Database', Database::getInstance()); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage Datasource driver "pdo_invalid" is invalid + */ + public function testGetInstanceInvalidDriver() + { + $config = Config::getInstance(); + $config->data['pickles']['datasource'] = 'invalid'; + $config->data['datasources']['invalid'] = [ + 'type' => 'invalid', + 'driver' => 'pdo_invalid', + 'hostname' => 'localhost', + 'username' => '', + 'password' => '', + 'database' => 'test', + ]; + Database::getInstance(); + } } ?>