Neevo Public API
  • Namespace
  • Class
  • Tree

Namespaces

  • Neevo
    • Cache
    • Drivers
    • Nette
  • PHP

Classes

  • MySQLDriver
  • MySQLiDriver
  • PDODriver
  • PgSQLDriver
  • SQLite2Driver
  • SQLite3Driver
  1 <?php
  2 /**
  3  * Neevo - Tiny database layer for PHP. (http://neevo.smasty.net)
  4  *
  5  * This source file is subject to the MIT license that is bundled
  6  * with this package in the file license.txt.
  7  *
  8  * Copyright (c) 2012 Smasty (http://smasty.net)
  9  *
 10  */
 11 
 12 namespace Neevo\Drivers;
 13 
 14 use DateTime;
 15 use InvalidArgumentException;
 16 use mysqli;
 17 use mysqli_result;
 18 use Neevo\BaseStatement;
 19 use Neevo\DriverException;
 20 use Neevo\DriverInterface;
 21 use Neevo\Manager;
 22 use Neevo\Parser;
 23 
 24 
 25 /**
 26  * Neevo MySQLi driver (PHP extension 'mysqli')
 27  *
 28  * Driver configuration:
 29  * - host => MySQL server name or address
 30  * - port (int) => MySQL server port
 31  * - socket
 32  * - username
 33  * - password
 34  * - database => database to select
 35  * - charset => Character encoding to set (defaults to utf8)
 36  * - peristent (bool) => Try to find a persistent link
 37  * - unbuffered (bool) => Sends query without fetching and buffering the result
 38  *
 39  * - resource (instance of mysqli) => Existing MySQLi link
 40  * - lazy, table_prefix... => see {@see Neevo\Connection}
 41  *
 42  * @author Smasty
 43  */
 44 class MySQLiDriver extends Parser implements DriverInterface {
 45 
 46 
 47     /** @var mysqli_result */
 48     private $resource;
 49 
 50     /** @var bool */
 51     private $unbuffered;
 52 
 53     /** @var int */
 54     private $affectedRows;
 55 
 56 
 57     /**
 58      * Checks for required PHP extension.
 59      * @throws DriverException
 60      */
 61     public function __construct(BaseStatement $statement = null){
 62         if(!extension_loaded("mysqli"))
 63             throw new DriverException("Cannot instantiate Neevo MySQLi driver - PHP extension 'mysqli' not loaded.");
 64         if($statement instanceof BaseStatement)
 65             parent::__construct($statement);
 66     }
 67 
 68 
 69     /**
 70      * Creates connection to database.
 71      * @param array $config Configuration options
 72      * @throws DriverException
 73      */
 74     public function connect(array $config){
 75 
 76         // Defaults
 77         $defaults = array(
 78             'resource' => null,
 79             'charset' => 'utf8',
 80             'username' => ini_get('mysqli.default_user'),
 81             'password' => ini_get('mysqli.default_pw'),
 82             'database' => '',
 83             'socket' => ini_get('mysqli.default_socket'),
 84             'port' => ini_get('mysqli.default_port'),
 85             'host' => ini_get('mysqli.default_host'),
 86             'persistent' => false,
 87             'unbuffered' => false
 88         );
 89 
 90         $config += $defaults;
 91 
 92         // Connect
 93         if($config['resource'] instanceof mysqli)
 94             $this->resource = $config['resource'];
 95         else
 96             $this->resource = new mysqli($config['host'], $config['username'], $config['password'], $config['database'], $config['port'], $config['socket']);
 97 
 98         if($this->resource->connect_errno)
 99             throw new DriverException($this->resource->connect_error, $this->resource->connect_errno);
100 
101         // Set charset
102         if($this->resource instanceof mysqli){
103             $ok = @$this->resource->set_charset($config['charset']);
104             if(!$ok)
105                 $this->runQuery("SET NAMES " . $config['charset']);
106         }
107 
108         $this->unbuffered = $config['unbuffered'];
109     }
110 
111 
112     /**
113      * Closes the connection.
114      */
115     public function closeConnection(){
116         @$this->resource->close();
117     }
118 
119 
120     /**
121      * Frees memory used by given result set.
122      * @param mysqli_result $resultSet
123      * @return bool
124      */
125     public function freeResultSet($resultSet){
126         if($resultSet instanceof mysqli_result)
127             $resultSet->free();
128     }
129 
130 
131     /**
132      * Executes given SQL statement.
133      * @param string $queryString
134      * @return mysqli_result|bool
135      * @throws DriverException
136      */
137     public function runQuery($queryString){
138 
139         $this->affectedRows = false;
140         $result = $this->resource->query($queryString, $this->unbuffered ? MYSQLI_USE_RESULT : MYSQLI_STORE_RESULT);
141 
142         $error = str_replace('You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use', 'Syntax error', $this->resource->error);
143         if($error && $result === false)
144             throw new DriverException($error, $this->resource->errno, $queryString);
145 
146         $this->affectedRows = $this->resource->affected_rows;
147         return $result;
148     }
149 
150 
151     /**
152      * Begins a transaction if supported.
153      * @param string $savepoint
154      */
155     public function beginTransaction($savepoint = null){
156         $this->runQuery($savepoint ? "SAVEPOINT $savepoint" : 'START TRANSACTION');
157     }
158 
159 
160     /**
161      * Commits statements in a transaction.
162      * @param string $savepoint
163      */
164     public function commit($savepoint = null){
165         $this->runQuery($savepoint ? "RELEASE SAVEPOINT $savepoint" : 'COMMIT');
166     }
167 
168 
169     /**
170      * Rollbacks changes in a transaction.
171      * @param string $savepoint
172      */
173     public function rollback($savepoint = null){
174         $this->runQuery($savepoint ? "ROLLBACK TO SAVEPOINT $savepoint" : 'ROLLBACK');
175     }
176 
177 
178     /**
179      * Fetches row from given result set as an associative array.
180      * @param mysqli_result $resultSet
181      * @return array
182      */
183     public function fetch($resultSet){
184         return $resultSet->fetch_assoc();
185     }
186 
187 
188     /**
189      * Moves internal result pointer.
190      * @param mysqli_result $resultSet
191      * @param int
192      * @return bool
193      * @throws DriverException
194      */
195     public function seek($resultSet, $offset){
196         if($this->unbuffered)
197             throw new DriverException('Cannot seek on unbuffered result.');
198         return $resultSet->data_seek($offset);
199     }
200 
201 
202     /**
203      * Returns the ID generated in the INSERT statement.
204      * @return int
205      */
206     public function getInsertId(){
207         return $this->resource->insert_id;
208     }
209 
210 
211     /**
212      * Randomizes result order.
213      * @param BaseStatement $statement
214      */
215     public function randomizeOrder(BaseStatement $statement){
216         $statement->order('RAND()');
217     }
218 
219 
220     /**
221      * Returns the number of rows in the given result set.
222      * @param mysqli_result $resultSet
223      * @return int|bool
224      * @throws DriverException
225      */
226     public function getNumRows($resultSet){
227         if($this->unbuffered)
228             throw new DriverException('Cannot count rows on unbuffered result.');
229         if($resultSet instanceof mysqli_result)
230             return $resultSet->num_rows;
231         return false;
232     }
233 
234 
235     /**
236      * Returns the number of affected rows in previous operation.
237      * @return int
238      */
239     public function getAffectedRows(){
240         return $this->affectedRows;
241     }
242 
243 
244     /**
245      * Escapes given value.
246      * @param mixed $value
247      * @param string $type
248      * @return mixed
249      * @throws InvalidArgumentException
250      */
251     public function escape($value, $type){
252         switch($type){
253             case Manager::BOOL:
254                 return $value ? 1 : 0;
255 
256             case Manager::TEXT:
257                 return "'" . $this->resource->real_escape_string($value) . "'";
258 
259             case Manager::IDENTIFIER:
260                 return str_replace('`*`', '*', '`' . str_replace('.', '`.`', str_replace('`', '``', $value)) . '`');
261 
262             case Manager::BINARY:
263                 return "_binary'" . mysqli_real_escape_string($this->resource, $value) . "'";
264 
265             case Manager::DATETIME:
266                 return ($value instanceof DateTime) ? $value->format("'Y-m-d H:i:s'") : date("'Y-m-d H:i:s'", $value);
267 
268             default:
269                 throw new InvalidArgumentException('Unsupported data type.');
270                 break;
271         }
272     }
273 
274 
275     /**
276      * Decodes given value.
277      * @param mixed $value
278      * @param string $type
279      * @return mixed
280      * @throws InvalidArgumentException
281      */
282     public function unescape($value, $type){
283         if($type === Manager::BINARY)
284             return $value;
285         throw new InvalidArgumentException('Unsupported data type.');
286     }
287 
288 
289     /**
290      * Returns the PRIMARY KEY column for given table.
291      * @param string $table
292      * @return string
293      */
294     public function getPrimaryKey($table){
295         $key = '';
296         $q = $this->runQuery('SHOW FULL COLUMNS FROM ' . $table);
297         while($col = $this->fetch($q)){
298             if(strtolower($col['Key']) === 'pri' && $key === '')
299                 $key = $col['Field'];
300         }
301         return $key;
302     }
303 
304 
305     /**
306      * Returns types of columns in given result set.
307      * @param mysqli_result $resultset
308      * @param string $table
309      * @return array
310      */
311     public function getColumnTypes($resultSet, $table){
312         static $colTypes;
313         if(empty($colTypes)){
314             $constants = get_defined_constants(true);
315             foreach($constants['mysqli'] as $type => $code){
316                 if(strncmp($type, 'MYSQLI_TYPE_', 12) === 0)
317                     $colTypes[$code] = strtolower(substr($type, 12));
318             }
319             $colTypes[MYSQLI_TYPE_LONG] = $colTypes[MYSQLI_TYPE_SHORT] = $colTypes[MYSQLI_TYPE_TINY] = 'int';
320         }
321 
322         $cols = array();
323         while($field = $resultSet->fetch_field()){
324             $cols[$field->name] = $colTypes[$field->type];
325         }
326         return $cols;
327     }
328 
329 
330     /**
331      * Parses UPDATE statement.
332      * @return string
333      */
334     protected function parseUpdateStmt(){
335         $sql = parent::parseUpdateStmt();
336         return $this->applyLimit($sql . $this->clauses[3]);
337     }
338 
339 
340     /**
341      * Parses DELETE statement.
342      * @return string
343      */
344     protected function parseDeleteStmt(){
345         $sql = parent::parseDeleteStmt();
346         return $this->applyLimit($sql . $this->clauses[3]);
347     }
348 
349 
350 }
351 
Neevo Public API API documentation generated by ApiGen 2.8.0