├── .travis.yml ├── tests ├── bootstrap.php └── OneDBTest.php ├── phpunit_mysql.xml ├── LICENSE ├── README.md └── src └── OneDB.php /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.5 5 | - 5.4 6 | 7 | env: 8 | - DB=mysql 9 | 10 | before_script: 11 | - mysql -e 'create database onedb_test;' 12 | 13 | script: phpunit --configuration phpunit_mysql.xml --coverage-text --debug -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ./tests/ 13 | 14 | 15 | 16 | 17 | 18 | ./ 19 | 20 | ./tests 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Christoph von Gellhorn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/OneDBTest.php: -------------------------------------------------------------------------------- 1 | $GLOBALS['db_database'], 30 | 'user' => $GLOBALS['db_user'], 31 | 'password' => $GLOBALS['db_password'] 32 | )); 33 | 34 | // Init test data and perform test on query method 35 | self::$_db->query( 36 | 'CREATE TABLE IF NOT EXISTS ' . self::$_table . ' (' 37 | . 'id INT(9) NOT NULL PRIMARY KEY AUTO_INCREMENT,' 38 | . 'name VARCHAR(50) NOT NULL,' 39 | . 'email VARCHAR(50) NOT NULL,' 40 | . 'tel VARCHAR(30) NOT NULL' 41 | . ') ENGINE = InnoDB' 42 | ); 43 | } 44 | 45 | public static function tearDownAfterClass() 46 | { 47 | self::$_db->query('DROP TABLE IF EXISTS ' . self::$_table); 48 | } 49 | 50 | public function testGetPDO() 51 | { 52 | $this->assertInstanceOf('PDO', self::$_db->getPDO()); 53 | } 54 | 55 | public function testQuote() 56 | { 57 | $this->assertEquals("'test'", self::$_db->quote('test')); 58 | } 59 | 60 | public function testBtick() 61 | { 62 | $this->assertEquals("`test`", self::$_db->btick('test')); 63 | } 64 | 65 | public function testInsert() 66 | { 67 | $aID = self::$_db->insert(self::$_table, array( 68 | 'name' => 'John Doe', 69 | 'email' => 'jd@jd.com', 70 | 'tel' => 55555555 71 | )); 72 | 73 | $this->assertTrue(is_int($aID) && $aID > 0); 74 | 75 | $bID = self::$_db->insert(self::$_table, array( 76 | 'name' => 'Skywalker', 77 | 'email' => 'sw@sw.com', 78 | 'tel' => 44444444 79 | )); 80 | 81 | $this->assertTrue(is_int($bID) && $bID > 0); 82 | } 83 | 84 | public function testMultiInsert() 85 | { 86 | self::$_db->multiInsert(self::$_table, 87 | array('name', 'email', 'tel'), 88 | array( 89 | array( 90 | 'John Doe', 91 | 'john@doe.com', 92 | 12345678 93 | ), 94 | array( 95 | 'John Smith', 96 | 'john@smith.com', 97 | 11223344 98 | ), 99 | array( 100 | 'Jack Smith', 101 | 'jack@smith.com', 102 | 87654321 103 | ) 104 | ) 105 | ); 106 | 107 | $result = self::$_db->fetchRow( 108 | 'SELECT * FROM ' . self::$_table . ' WHERE tel = 87654321' 109 | ); 110 | 111 | // Check if last value was inserted successfully 112 | $this->assertEquals('jack@smith.com', $result['email']); 113 | } 114 | 115 | public function testSave() 116 | { 117 | $testTel = '22222222'; 118 | 119 | $tmpId = self::$_db->save(self::$_table, array( 120 | 'name' => 'Bill Gates', 121 | 'email' => 'bg@microsoft.com', 122 | 'tel' => '11111111' 123 | )); 124 | 125 | $id = self::$_db->save(self::$_table, array( 126 | 'id' => $tmpId, 127 | 'name' => 'Bill Gates', 128 | 'email' => 'bg@microsoft.com', 129 | 'tel' => $testTel 130 | )); 131 | 132 | $this->assertSame($tmpId, $id); 133 | 134 | $tel = self::$_db->fetchOne( 135 | 'SELECT tel FROM ' . self::$_table . ' WHERE id = ' . $tmpId 136 | ); 137 | 138 | $this->assertEquals($tel, $testTel); 139 | } 140 | 141 | public function testUpdate() 142 | { 143 | $testName = 'Steve Jobs'; 144 | 145 | self::$_db->update( 146 | self::$_table, 147 | array('name' => $testName), 148 | array('id = ?' => 1) 149 | ); 150 | 151 | $result = self::$_db->fetchRow( 152 | 'SELECT * FROM ' . self::$_table . ' WHERE id = 1' 153 | ); 154 | 155 | $this->assertEquals($testName, $result['name']); 156 | } 157 | 158 | public function testFetchAll() 159 | { 160 | $result = self::$_db->fetchAll( 161 | 'SELECT * FROM ' . self::$_table 162 | ); 163 | 164 | $this->assertTrue(is_array($result[0])); 165 | $this->assertArrayHasKey('name', $result[0]); 166 | } 167 | 168 | public function testFetchAssoc() 169 | { 170 | $result = self::$_db->fetchAssoc( 171 | 'SELECT * FROM ' . self::$_table 172 | ); 173 | 174 | $this->assertTrue(count($result) > 0); 175 | 176 | foreach ($result as $id => $row) { 177 | // Compare int with string 178 | $this->assertTrue($id == $row['id']); 179 | } 180 | } 181 | 182 | public function testFetchRow() 183 | { 184 | $result = self::$_db->fetchRow( 185 | 'SELECT * FROM ' . self::$_table . ' WHERE id = 1' 186 | ); 187 | 188 | $this->assertArrayHasKey('name', $result); 189 | } 190 | 191 | public function testFetchOne() 192 | { 193 | $name = 'Steve Jobs'; 194 | 195 | $result = self::$_db->fetchOne( 196 | 'SELECT name FROM ' . self::$_table . ' WHERE id = 1' 197 | ); 198 | 199 | $this->assertEquals($name, $result); 200 | } 201 | 202 | public function testQuery() 203 | { 204 | $testName = 'Steve Jobs'; 205 | 206 | // Perform tests on fetching modes 207 | $fetchAll = self::$_db->query( 208 | 'SELECT * FROM ' . self::$_table 209 | ); 210 | $fetchRow = self::$_db->query( 211 | 'SELECT * FROM ' . self::$_table . ' WHERE id = 1' 212 | ); 213 | $fetchOne = self::$_db->query( 214 | 'SELECT name FROM ' . self::$_table . ' WHERE id = 1' 215 | ); 216 | 217 | $this->assertTrue(is_array($fetchAll[0])); 218 | $this->assertArrayHasKey('name', $fetchAll[0]); 219 | $this->assertEquals($testName, $fetchRow['name']); 220 | $this->assertEquals($testName, $fetchOne); 221 | } 222 | 223 | public function testDelete() 224 | { 225 | self::$_db->delete( 226 | self::$_table, 227 | array('name = ?' => 'Skywalker') 228 | ); 229 | 230 | $result = self::$_db->fetchOne( 231 | 'SELECT name FROM ' . self::$_table . ' WHERE id = 2' 232 | ); 233 | 234 | $this->assertNull($result); 235 | } 236 | 237 | public function testTruncte() 238 | { 239 | self::$_db->truncate(self::$_table); 240 | 241 | $result = self::$_db->fetchAll('SELECT * FROM ' . self::$_table); 242 | $this->assertEmpty($result); 243 | } 244 | 245 | public function testDescribe() 246 | { 247 | $result = self::$_db->describe(self::$_table); 248 | 249 | $realKeys = array('id', 'name', 'email', 'tel'); 250 | $resultKeys = array_keys($result); 251 | 252 | $this->assertSame( 253 | array_diff($realKeys, $resultKeys), 254 | array_diff($resultKeys, $realKeys) 255 | ); 256 | } 257 | 258 | public function testDrop() 259 | { 260 | self::$_db->drop(self::$_table); 261 | } 262 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OneDB [![Build Status](https://travis-ci.org/cvgellhorn/OneDB.svg?branch=master)](https://travis-ci.org/cvgellhorn/OneDB) 2 | =========== 3 | 4 | > A lightweight/single file PHP database framework 5 | 6 | ## Overview 7 | OneDB is using the PDO_MYSQL extension and is based on three classes: 8 | 9 | * OneDB - Main database framework 10 | * OneExpr - Database expression 11 | * OneException - Exception 12 | 13 | All tests are based on the [PHPUnit](http://phpunit.de/) testing framework. You can easily set up your own phpunit.xml, for local unit testing. It's also very lightweight, only around 13 kb and all packed in a single PHP file. 14 | 15 | ### Server Requirements: 16 | 17 | * PHP >= 5.4 18 | * PDO_MYSQL extension 19 | 20 | ## Getting started 21 | ```php 22 | // Include OneDB 23 | require_once 'OneDB.php'; 24 | 25 | // Create OneDB instance and have fun 26 | $database = OneDB::load([ 27 | 'database' => 'application', 28 | 'user' => 'root', 29 | 'password' => 'admin123#' 30 | ]); 31 | 32 | // After initializing, you can always get the current instance with 33 | $database = OneDB::load(); 34 | 35 | 36 | // Or create a new connection by name (for multiple connections) 37 | $dbWrite = OneDB::getConnection('write', [ 38 | 'database' => 'application', 39 | 'user' => 'root', 40 | 'password' => 'admin123#' 41 | ]); 42 | 43 | // Reload connection again later 44 | $dbWrite = OneDB::getConnection('write'); 45 | ``` 46 | 47 | ## Configuration 48 | You can also set the database host, port and charset. 49 | ```php 50 | $database = OneDB::load([ 51 | 'host' => 'sql.mydomain.com', 52 | 'port' => '3307', 53 | 'charset' => 'utf16', 54 | 'database' => 'application', 55 | 'user' => 'root', 56 | 'password' => 'admin123#' 57 | ]); 58 | ``` 59 | 60 | Default settings 61 | ```php 62 | 'host' => 'localhost' 63 | 'port' => '[default_mysql_port]' 64 | 'charset' => 'utf8' 65 | ``` 66 | 67 | ## Basic Usage 68 | ### Insert 69 | Insert new records in table, returns LAST_INSERT_ID. 70 | 71 | ```php 72 | insert($table : string, $data : array) 73 | ``` 74 | 75 | Example: 76 | ```php 77 | $lastInsertId = $database->insert('user', [ 78 | 'name' => 'John Doe', 79 | 'email' => 'john@doe.com', 80 | 'tel' => 12345678 81 | ]); 82 | ``` 83 | 84 | ### Update 85 | Edit data in table. You can use any given operator in the WHERE clause to filter the records. The ? represents the placeholder for the given param. 86 | 87 | ```php 88 | update($table : string, $data : array, [$where : array]) 89 | ``` 90 | 91 | Example: 92 | ```php 93 | $database->update('user', 94 | [ 95 | 'name' => 'John Smith', 96 | 'email' => 'john@smith.com', 97 | 'tel' => 87654321 98 | ], 99 | [ 100 | 'id = ?' => 23 101 | ] 102 | ); 103 | ``` 104 | 105 | ### Delete 106 | Remove data from table. Just as update, the ? represents the placeholder for the given param. 107 | 108 | ```php 109 | delete($table : string, [$where : array]) 110 | ``` 111 | 112 | Example: 113 | ```php 114 | $database->delete('user', [ 115 | 'id = ?' => 23 116 | ]); 117 | ``` 118 | 119 | ### Fetch All 120 | Retrieve all the rows of the result set in one step as an array. 121 | ```php 122 | fetchAll($sql : string) 123 | ``` 124 | 125 | Example: 126 | ```php 127 | $database->fetchAll('SELECT * FROM `user`'); 128 | ``` 129 | 130 | ### Fetch Assoc 131 | Retrieve all the rows of the result set in one step as an array, using the first column or the given key as the array index. 132 | ```php 133 | fetchAssoc($sql : string, [$key : string]) 134 | ``` 135 | 136 | Example: 137 | ```php 138 | $database->fetchAssoc('SELECT * FROM `user`', 'username'); 139 | ``` 140 | 141 | ### Fetch Row 142 | Retrieve a single row of the result set as an array. 143 | ```php 144 | fetchRow($sql : string) 145 | ``` 146 | 147 | Example: 148 | ```php 149 | $database->fetchRow('SELECT * FROM `user` WHERE `id` = 1'); 150 | ``` 151 | 152 | ### Fetch One 153 | Retrieve a single result value. 154 | ```php 155 | fetchOne($sql : string) 156 | ``` 157 | 158 | Example: 159 | ```php 160 | $database->fetchOne('SELECT `username` FROM `user` WHERE `id` = 1'); 161 | ``` 162 | 163 | ### Query 164 | Send an SQL query. If there is a result, you will automatically get the matched result type: fetch all, fetch row or fetch one. 165 | ```php 166 | query($sql : string) 167 | ``` 168 | 169 | Example: 170 | ```php 171 | $database->query('DELETE FROM `user` WHERE `id` = 1'); 172 | 173 | // With result 174 | $result = $database->query('SELECT * FROM `user`'); 175 | ``` 176 | 177 | ### Last Insert ID 178 | Returns the ID of the last inserted row. 179 | ```php 180 | lastInsertId() 181 | ``` 182 | 183 | Example: 184 | ```php 185 | $database->lastInsertId(); 186 | ``` 187 | 188 | 189 | ## Advanced Usage 190 | ### Expression 191 | You can also use database expressions in your statement, by using the OneExpr object. 192 | ```php 193 | $lastInsertId = $database->insert('user', [ 194 | 'name' => 'John Doe', 195 | 'email' => 'john@doe.com', 196 | 'tel' => 12345678, 197 | 'created' => new OneExpr('NOW()') 198 | ]); 199 | ``` 200 | 201 | ### Truncate 202 | Truncate database table. 203 | ```php 204 | truncate($table : string) 205 | ``` 206 | 207 | Example: 208 | ```php 209 | $database->truncate('user'); 210 | ``` 211 | 212 | ### Drop 213 | Drop database table. 214 | ```php 215 | drop($table : string) 216 | ``` 217 | 218 | Example: 219 | ```php 220 | $database->drop('user'); 221 | ``` 222 | 223 | ### Describe 224 | Describe database table, returns the table attributes as array keys. 225 | ```php 226 | describe($table : string) 227 | ``` 228 | 229 | Example: 230 | ```php 231 | $database->describe('user'); 232 | ``` 233 | 234 | ### Transaction 235 | Run a database transaction. 236 | ```php 237 | try { 238 | // Start transaction 239 | $database->beginTransaction(); 240 | 241 | // Do stuff 242 | $database->insert('user', [ 243 | 'name' => 'Skywalker' 244 | ]); 245 | $database->delete('user', [ 246 | 'id = ?' => 3 247 | ]); 248 | 249 | // Check transaction status, returns bool 250 | $status = $database->inTransaction(); 251 | 252 | // Commit transaction if no error occurred 253 | $database->commit(); 254 | } catch (OneException $e) { 255 | // Rollback on error 256 | $database->rollBack(); 257 | } 258 | ``` 259 | 260 | ### Quote 261 | Add quotes to the given value. 262 | ```php 263 | quote($val : string) 264 | ``` 265 | 266 | Example: 267 | ```php 268 | $database->quote($value); 269 | ``` 270 | 271 | ### Backtick 272 | Add backticks to the given field name. 273 | ```php 274 | btick($val : string) 275 | ``` 276 | 277 | Example: 278 | ```php 279 | $database->btick('user'); 280 | ``` 281 | 282 | ### PDO 283 | Returns the current PDO object. 284 | ```php 285 | getPDO() 286 | ``` 287 | 288 | Example: 289 | ```php 290 | $database->getPDO(); 291 | ``` 292 | 293 | 294 | ## Special Usage 295 | ### Multi Insert 296 | Insert multiple records into database table. 297 | ```php 298 | multiInsert($table : string, $keys : array, $data : array) 299 | ``` 300 | 301 | Example: 302 | ```php 303 | $database->multiInsert('user', 304 | ['name', 'email', 'tel'], 305 | [ 306 | [ 307 | 'John Doe', 308 | 'john@doe.com', 309 | 12345678 310 | ], 311 | [ 312 | 'John Smith', 313 | 'john@smith.com', 314 | 11223344 315 | ), 316 | [ 317 | 'Jack Smith', 318 | 'jack@smith.com', 319 | 87654321 320 | ] 321 | ] 322 | ); 323 | ``` 324 | 325 | ### Save 326 | Update data if exist, otherwise insert new data. Using the ON DUPLICATE KEY UPDATE expression. Returns the ID of the last inserted or updated row. 327 | ```php 328 | save($table : string, $data : array) 329 | ``` 330 | Example: 331 | ```php 332 | $id = $database->save('user', [ 333 | 'id' => 1, 334 | 'name' => 'John Doe', 335 | 'email' => 'john@doe.com', 336 | 'tel' => 12345678 337 | ]); 338 | ``` 339 | 340 | 341 | ## Debug 342 | You can activate the debug mode by using the following statement. It will show you all executed SQL queries and the parameter bindings. 343 | ```php 344 | $database->debug(); 345 | ``` 346 | 347 | It's also possible to change the debug style with the debugStyle attribute. 348 | ```php 349 | $database->debugStyle = [ 350 | 'border: 2px solid #d35400', 351 | 'border-radius: 3px', 352 | 'background-color: #e67e22', 353 | 'margin: 5px 0 5px 0', 354 | 'color: #ffffff', 355 | 'padding: 5px' 356 | ]; 357 | ``` 358 | -------------------------------------------------------------------------------- /src/OneDB.php: -------------------------------------------------------------------------------- 1 | 'mysql', 52 | 'host' => 'localhost', 53 | 'charset' => 'utf8', 54 | 'database' => null, 55 | 'user' => null, 56 | 'password' => null 57 | ]; 58 | 59 | /** 60 | * Debug style 61 | * 62 | * @var array 63 | */ 64 | public $debugStyle = [ 65 | 'border: 2px solid #d35400', 66 | 'border-radius: 3px', 67 | 'background-color: #e67e22', 68 | 'margin: 5px 0 5px 0', 69 | 'color: #ffffff', 70 | 'padding: 5px' 71 | ]; 72 | 73 | /** 74 | * Single pattern implementation 75 | * 76 | * @param array $config Connection configs 77 | * @return OneDB 78 | */ 79 | public static function load($config = []) 80 | { 81 | if (null === self::$_instance) { 82 | self::$_instance = self::_create($config); 83 | } 84 | return self::$_instance; 85 | } 86 | 87 | /** 88 | * Handle database connections 89 | * 90 | * @param string $name Connection name 91 | * @param array $config Connection configs 92 | * @return OneDB 93 | */ 94 | public static function getConnection($name = null, $config = []) 95 | { 96 | if (null === $name) { 97 | return self::_create($config); 98 | } else { 99 | if (!isset(self::$_connections[$name])) { 100 | self::$_connections[$name] = self::_create($config); 101 | } 102 | return self::$_connections[$name]; 103 | } 104 | } 105 | 106 | /** 107 | * Create new OneDB connection 108 | * 109 | * @param array $config Connection configs 110 | * @return OneDB 111 | * @throws OneException 112 | */ 113 | protected static function _create($config) 114 | { 115 | if (!empty($config)) { 116 | return new self($config); 117 | } else { 118 | throw new OneException('OneDB configuration is not set'); 119 | } 120 | } 121 | 122 | /** 123 | * Create DB object and connect to database 124 | * 125 | * @throws OneException 126 | */ 127 | protected function __construct($config) 128 | { 129 | try { 130 | if (!extension_loaded('pdo_mysql')) { 131 | throw new OneException('pdo_mysql extension is not installed'); 132 | } 133 | 134 | // Prepare database configuration 135 | $config = $this->_prepareConfig($config); 136 | 137 | $this->_pdo = new PDO( 138 | $config['pdo_type'] . ':' . $config['dsn'], 139 | $config['user'], 140 | $config['password'] 141 | ); 142 | 143 | // Always use exceptions 144 | $this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 145 | 146 | // Set character encoding 147 | $this->_pdo->exec('SET CHARACTER SET ' . $config['charset']); 148 | } catch (PDOException $e) { 149 | throw new OneException($e->getMessage()); 150 | } 151 | } 152 | 153 | /** 154 | * Prepare database configuration 155 | * 156 | * @param array $config Connection configs 157 | * @return array Matched connection configs 158 | * @throws OneException 159 | */ 160 | protected function _prepareConfig($config) 161 | { 162 | $config = array_merge($this->_config, $config); 163 | foreach ($config as $key => $val) { 164 | if (null === $val) { 165 | throw new OneException('Could not connect to database, missing parameter: ' . $key); 166 | } 167 | } 168 | 169 | $dsn = [ 170 | 'host=' . $config['host'], 171 | 'dbname=' . $config['database'], 172 | 'charset=' . $config['charset'] 173 | ]; 174 | 175 | if (isset($config['port'])) { 176 | $dsn[] = 'port=' . $config['port']; 177 | } 178 | 179 | $config['dsn'] = implode(';', $dsn); 180 | return $config; 181 | } 182 | 183 | /** 184 | * Prepare SQL statement for executing 185 | * 186 | * @param string $sql SQL statement 187 | * @return OneDB 188 | */ 189 | protected function _prepare($sql) 190 | { 191 | $this->_stmt = $this->_pdo->prepare($sql); 192 | return $this; 193 | } 194 | 195 | /** 196 | * Build where clause 197 | * 198 | * @param array $where Where conditions 199 | * @param string $query Query string 200 | */ 201 | protected function _buildWhere(&$where, &$query) 202 | { 203 | if (!empty($where)) { 204 | $expr = []; 205 | foreach ($where as $key => $val) { 206 | if ($val instanceof OneExpr) { 207 | $expr[] = str_replace('?', $val, $key); 208 | unset($where[$key]); 209 | } 210 | } 211 | $query .= ' WHERE ' . implode(' AND ', array_keys($where)) 212 | . ((!empty($expr)) ? ' AND ' . implode(' AND ', $expr) : ''); 213 | } 214 | } 215 | 216 | /** 217 | * Bind SQL query params to PDO statement object 218 | * 219 | * @param array $data SQL query params 220 | * @return OneDB 221 | */ 222 | protected function _bindParams($data) 223 | { 224 | if ($this->_debugMode) $this->dump(print_r($data, true)); 225 | 226 | $count = count($data); 227 | for ($i = 0; $i < $count; $i++) { 228 | $this->_stmt->bindParam($i + 1, $data[$i]); 229 | } 230 | 231 | return $this; 232 | } 233 | 234 | /** 235 | * Execute SQL statement 236 | * 237 | * @return PDOStatement 238 | * @throws OneException 239 | */ 240 | protected function _execute() 241 | { 242 | try { 243 | if ($this->_debugMode) $this->dump($this->_stmt->queryString); 244 | $this->_stmt->execute(); 245 | } catch (PDOException $e) { 246 | throw new OneException('PDO Mysql execution error: ' . $e->getMessage()); 247 | } 248 | 249 | return $this->_stmt; 250 | } 251 | 252 | /** 253 | * Get the current PDO object 254 | * 255 | * @return PDO 256 | */ 257 | public function getPDO() 258 | { 259 | return $this->_pdo; 260 | } 261 | 262 | /** 263 | * Return given value with quotes 264 | * 265 | * @param string $val Value 266 | * @return string Value with quotes 267 | */ 268 | public function quote($val) 269 | { 270 | return "'$val'"; 271 | } 272 | 273 | /** 274 | * Return given value with backticks 275 | * 276 | * @param string $val Value 277 | * @return string Value with backticks 278 | */ 279 | public function btick($val) 280 | { 281 | return "`$val`"; 282 | } 283 | 284 | /** 285 | * Set debug mode 286 | * 287 | * @param bool $status Debug mode status 288 | * @return $this 289 | */ 290 | public function debug($status = true) 291 | { 292 | $this->_debugMode = $status; 293 | return $this; 294 | } 295 | 296 | /** 297 | * Debug dump 298 | * 299 | * @param mixed $val Value to dump 300 | */ 301 | public function dump($val) 302 | { 303 | echo '
' . $val . '
'; 304 | } 305 | 306 | /** 307 | * Initiates a transaction 308 | * 309 | * @return bool TRUE on success or FALSE on failure 310 | */ 311 | public function beginTransaction() 312 | { 313 | return $this->_pdo->beginTransaction(); 314 | } 315 | 316 | /** 317 | * Commits a transaction 318 | * 319 | * @return bool TRUE on success or FALSE on failure 320 | */ 321 | public function commit() 322 | { 323 | return $this->_pdo->commit(); 324 | } 325 | 326 | /** 327 | * Rolls back a transaction 328 | * 329 | * @return bool TRUE on success or FALSE on failure 330 | */ 331 | public function rollBack() 332 | { 333 | return $this->_pdo->rollBack(); 334 | } 335 | 336 | /** 337 | * Checks if inside a transaction 338 | * 339 | * @return bool TRUE on success or FALSE on failure 340 | */ 341 | public function inTransaction() 342 | { 343 | return $this->_pdo->inTransaction(); 344 | } 345 | 346 | /** 347 | * Get last insert ID 348 | * 349 | * @return int Last insert ID 350 | */ 351 | public function lastInsertId() 352 | { 353 | return (int) $this->_pdo->lastInsertId(); 354 | } 355 | 356 | /** 357 | * Fetch all data by SQL statement 358 | * 359 | * @param string $sql SQL statement 360 | * @return array SQL result 361 | */ 362 | public function fetchAll($sql) 363 | { 364 | return $this->_prepare($sql)->_execute()->fetchAll(PDO::FETCH_ASSOC); 365 | } 366 | 367 | /** 368 | * Fetch all data by SQL statement and merge by field 369 | * 370 | * @param string $sql SQL statement 371 | * @param string $key Optional | array key 372 | * @return array SQL result 373 | */ 374 | public function fetchAssoc($sql, $key = null) 375 | { 376 | // Raw result data 377 | $data = $this->_prepare($sql)->_execute()->fetchAll(PDO::FETCH_ASSOC); 378 | 379 | $result = []; 380 | if (!empty($data)) { 381 | $key = ($key && isset($data[0][$key])) ? $key : key($data[0]); 382 | foreach ($data as $d) { 383 | $result[$d[$key]] = $d; 384 | } 385 | } 386 | 387 | return $result; 388 | } 389 | 390 | /** 391 | * Fetch row by SQL statement 392 | * 393 | * @param string $sql SQL statement 394 | * @return array SQL result 395 | */ 396 | public function fetchRow($sql) 397 | { 398 | return $this->_prepare($sql)->_execute()->fetch(PDO::FETCH_ASSOC); 399 | } 400 | 401 | /** 402 | * Fetch single value by SQL statement 403 | * 404 | * @param string $sql SQL statement 405 | * @return mixed Result value 406 | */ 407 | public function fetchOne($sql) 408 | { 409 | $result = $this->_prepare($sql)->_execute()->fetch(PDO::FETCH_NUM); 410 | return isset($result[0]) ? $result[0] : null; 411 | } 412 | 413 | /** 414 | * Executes an SQL statement 415 | * 416 | * @param string $sql SQL statement 417 | * @return array|bool|mixed|null SQL result 418 | * @throws OneException 419 | */ 420 | public function query($sql) 421 | { 422 | try { 423 | /*** @var $result PDOStatement */ 424 | $result = $this->_pdo->query($sql); 425 | } catch (PDOException $e) { 426 | throw new OneException('PDO Mysql statement error: ' . $e->getMessage()); 427 | } 428 | 429 | $columnCount = $result->columnCount(); 430 | $rowCount = $result->rowCount(); 431 | 432 | // If statment is as SELECT statement 433 | if ($columnCount > 0) { 434 | // Equal to fetchOne 435 | if ($columnCount === 1 && $rowCount === 1) { 436 | $res = $result->fetch(PDO::FETCH_NUM); 437 | return isset($res[0]) ? $res[0] : null; 438 | 439 | // Equal to fetchRow 440 | } else if ($columnCount > 1 && $rowCount === 1) { 441 | return $result->fetch(PDO::FETCH_ASSOC); 442 | 443 | // Equal to fetchAll 444 | } else { 445 | return $result->fetchAll(PDO::FETCH_ASSOC); 446 | } 447 | } else { 448 | // No result 449 | return true; 450 | } 451 | } 452 | 453 | /** 454 | * Insert given data into database 455 | * 456 | * @param string $table DB table name 457 | * @param array $data Data to insert 458 | * @return int Last insert ID 459 | */ 460 | public function insert($table, $data) 461 | { 462 | $keys = []; 463 | $values = []; 464 | foreach ($data as $key => $val) { 465 | $keys[] = $this->btick($key); 466 | if ($val instanceof OneExpr) { 467 | $values[] = $val; 468 | unset($data[$key]); 469 | } else { 470 | $values[] = '?'; 471 | } 472 | } 473 | 474 | $query = 'INSERT INTO ' . $this->btick($table) 475 | . ' (' . implode(', ', $keys) . ')' 476 | . ' VALUES (' . implode(', ', $values) . ')'; 477 | 478 | $this->_prepare($query)->_bindParams(array_values($data))->_execute(); 479 | return $this->lastInsertId(); 480 | } 481 | 482 | /** 483 | * Do a multi insert 484 | * 485 | * @param string $table DB table name 486 | * @param array $keys DB table columns 487 | * @param array $data Data to insert 488 | */ 489 | public function multiInsert($table, $keys, $data) 490 | { 491 | foreach ($keys as &$key) { 492 | $key = $this->btick($key); 493 | } 494 | 495 | $values = []; 496 | foreach ($data as $vals) { 497 | foreach ($vals as &$val) { 498 | $val = $this->quote($val); 499 | } 500 | $values[] = '(' . implode(',', $vals) . ')'; 501 | } 502 | 503 | $query = 'INSERT INTO ' . $this->btick($table) 504 | . ' (' . implode(',', $keys) . ')' 505 | . ' VALUES ' . implode(',', $values); 506 | 507 | $this->_prepare($query)->_execute(); 508 | } 509 | 510 | /** 511 | * Update data if exist, otherwise insert new data 512 | * 513 | * @param string $table DB table name 514 | * @param array $data Data to insert or update 515 | * @return int ID of the last inserted or updated row 516 | */ 517 | public function save($table, $data) 518 | { 519 | $keys = []; 520 | $values = []; 521 | $updateVals = []; 522 | 523 | foreach ($data as $key => $val) { 524 | $keys[] = $field = $this->btick($key); 525 | if ($val instanceof OneExpr) { 526 | $values[] = $val; 527 | $updateVals[] = $field . '=' . $val; 528 | unset($data[$key]); 529 | } else { 530 | $values[] = '?'; 531 | $updateVals[] = $field . '=?'; 532 | } 533 | } 534 | 535 | $query = 'INSERT INTO ' . $this->btick($table) 536 | . ' (' . implode(', ', $keys) . ')' 537 | . ' VALUES (' . implode(', ', $values) . ')' 538 | . ' ON DUPLICATE KEY UPDATE ' . implode(',', $updateVals); 539 | 540 | $vals = array_values($data); 541 | $this->_prepare($query)->_bindParams(array_merge($vals, $vals))->_execute(); 542 | 543 | return $this->lastInsertId(); 544 | } 545 | 546 | /** 547 | * Update data by given condition 548 | * 549 | * @param string $table DB table name 550 | * @param array $data Data to update 551 | * @param array $where Update condition 552 | */ 553 | public function update($table, $data, $where = []) 554 | { 555 | $values = []; 556 | foreach ($data as $key => $val) { 557 | if ($val instanceof OneExpr) { 558 | $values[] = $this->btick($key) . ' = ' . $val; 559 | unset($data[$key]); 560 | } else { 561 | $values[] = $this->btick($key) . ' = ?'; 562 | } 563 | } 564 | 565 | $query = 'UPDATE ' . $this->btick($table) . ' SET ' . implode(', ', $values); 566 | $this->_buildWhere($where, $query); 567 | 568 | $params = array_merge( 569 | array_values($data), 570 | array_values($where) 571 | ); 572 | 573 | $this->_prepare($query)->_bindParams($params)->_execute(); 574 | } 575 | 576 | /** 577 | * Delete from database table 578 | * 579 | * @param string $table DB table name 580 | * @param array $where Delete condition 581 | */ 582 | public function delete($table, $where = []) 583 | { 584 | $query = 'DELETE FROM ' . $this->btick($table); 585 | $this->_buildWhere($where, $query); 586 | 587 | $this->_prepare($query); 588 | if (!empty($where)) { 589 | $this->_bindParams(array_values($where)); 590 | } 591 | 592 | $this->_execute(); 593 | } 594 | 595 | /** 596 | * Truncate database table 597 | * 598 | * @param string $table DB table name 599 | */ 600 | public function truncate($table) 601 | { 602 | $this->_prepare('TRUNCATE TABLE ' . $this->btick($table))->_execute(); 603 | } 604 | 605 | /** 606 | * Drop database table 607 | * 608 | * @param string $table DB table name 609 | */ 610 | public function drop($table) 611 | { 612 | $this->_prepare('DROP TABLE ' . $this->btick($table))->_execute(); 613 | } 614 | 615 | /** 616 | * Describe database table 617 | * 618 | * @param string $table DB table name 619 | * @return array Table structure 620 | */ 621 | public function describe($table) 622 | { 623 | return $this->fetchAssoc('DESCRIBE ' . $this->btick($table)); 624 | } 625 | } 626 | 627 | 628 | /** 629 | * OneDB database expression 630 | */ 631 | class OneExpr 632 | { 633 | /** 634 | * @var string Database expression 635 | */ 636 | public $expr; 637 | 638 | /** 639 | * Expression constructor 640 | * 641 | * @param string $expr Database expression 642 | */ 643 | public function __construct($expr) 644 | { 645 | $this->expr = $expr; 646 | } 647 | 648 | /** 649 | * Magic to string method 650 | * 651 | * @return string Database expression 652 | */ 653 | public function __toString() 654 | { 655 | return $this->expr; 656 | } 657 | } 658 | 659 | 660 | /** 661 | * OneDB Exception class 662 | */ 663 | class OneException extends Exception 664 | {} --------------------------------------------------------------------------------