Commit 6cd7b5e0 authored by Alexander Butenko's avatar Alexander Butenko

Merge pull request #357 from tommyknocker/master

PSR 1&2 code refactoring and exceptions instead of die()
parents e6189a92 1c46e232
<?php <?php
/** /**
* MysqliDb Class * MysqliDb Class
* *
...@@ -11,71 +12,83 @@ ...@@ -11,71 +12,83 @@
* @license http://opensource.org/licenses/gpl-3.0.html GNU Public License * @license http://opensource.org/licenses/gpl-3.0.html GNU Public License
* @link http://github.com/joshcam/PHP-MySQLi-Database-Class * @link http://github.com/joshcam/PHP-MySQLi-Database-Class
* @version 2.6-master * @version 2.6-master
**/ */
class MysqliDb class MysqliDb
{ {
/** /**
* Static instance of self * Static instance of self
* *
* @var MysqliDb * @var MysqliDb
*/ */
protected static $_instance; protected static $_instance;
/** /**
* Table prefix * Table prefix
* *
* @var string * @var string
*/ */
public static $prefix = ''; public static $prefix = '';
/** /**
* MySQLi instance * MySQLi instance
* *
* @var mysqli * @var mysqli
*/ */
protected $_mysqli; protected $_mysqli;
/** /**
* The SQL query to be prepared and executed * The SQL query to be prepared and executed
* *
* @var string * @var string
*/ */
protected $_query; protected $_query;
/** /**
* The previously executed SQL query * The previously executed SQL query
* *
* @var string * @var string
*/ */
protected $_lastQuery; protected $_lastQuery;
/** /**
* The SQL query options required after SELECT, INSERT, UPDATE or DELETE * The SQL query options required after SELECT, INSERT, UPDATE or DELETE
* *
* @var string * @var string
*/ */
protected $_queryOptions = array(); protected $_queryOptions = array();
/** /**
* An array that holds where joins * An array that holds where joins
* *
* @var array * @var array
*/ */
protected $_join = array(); protected $_join = array();
/** /**
* An array that holds where conditions * An array that holds where conditions
* *
* @var array * @var array
*/ */
protected $_where = array(); protected $_where = array();
/** /**
* An array that holds having conditions * An array that holds having conditions
* *
* @var array * @var array
*/ */
protected $_having = array(); protected $_having = array();
/** /**
* Dynamic type list for order by condition value * Dynamic type list for order by condition value
*/ */
protected $_orderBy = array(); protected $_orderBy = array();
/** /**
* Dynamic type list for group by condition value * Dynamic type list for group by condition value
*/ */
protected $_groupBy = array(); protected $_groupBy = array();
/** /**
* Dynamic array that holds a combination of where condition/table data value types and parameter references * Dynamic array that holds a combination of where condition/table data value types and parameter references
* *
...@@ -88,12 +101,14 @@ class MysqliDb ...@@ -88,12 +101,14 @@ class MysqliDb
* @var string * @var string
*/ */
public $count = 0; public $count = 0;
/** /**
* Variable which holds an amount of returned rows during get/getOne/select queries with withTotalCount() * Variable which holds an amount of returned rows during get/getOne/select queries with withTotalCount()
* *
* @var string * @var string
*/ */
public $totalCount = 0; public $totalCount = 0;
/** /**
* Variable which holds last statement error * Variable which holds last statement error
* *
...@@ -180,20 +195,22 @@ class MysqliDb ...@@ -180,20 +195,22 @@ class MysqliDb
* @param string $db * @param string $db
* @param int $port * @param int $port
*/ */
public function __construct($host = NULL, $username = NULL, $password = NULL, $db = NULL, $port = NULL, $charset = 'utf8') public function __construct($host = null, $username = null, $password = null, $db = null, $port = null, $charset = 'utf8')
{ {
$isSubQuery = false; $isSubQuery = false;
// if params were passed as array // if params were passed as array
if (is_array ($host)) { if (is_array($host)) {
foreach ($host as $key => $val) foreach ($host as $key => $val) {
$$key = $val; $$key = $val;
} }
}
// if host were set as mysqli socket // if host were set as mysqli socket
if (is_object ($host)) if (is_object($host)) {
$this->_mysqli = $host; $this->_mysqli = $host;
else } else {
$this->host = $host; $this->host = $host;
}
$this->username = $username; $this->username = $username;
$this->password = $password; $this->password = $password;
...@@ -205,38 +222,48 @@ class MysqliDb ...@@ -205,38 +222,48 @@ class MysqliDb
$this->isSubQuery = true; $this->isSubQuery = true;
return; return;
} }
if (isset ($prefix))
$this->setPrefix ($prefix); if (isset($prefix)) {
$this->setPrefix($prefix);
}
self::$_instance = $this; self::$_instance = $this;
} }
/** /**
* A method to connect to the database * A method to connect to the database
* *
* @throws Exception
*/ */
public function connect() public function connect()
{ {
if ($this->isSubQuery) if ($this->isSubQuery) {
return; return;
}
if (empty($this->host)) {
throw new Exception('Mysql host is not set');
}
if (empty ($this->host)) $this->_mysqli = new mysqli($this->host, $this->username, $this->password, $this->db, $this->port);
die ('Mysql host is not set');
$this->_mysqli = new mysqli ($this->host, $this->username, $this->password, $this->db, $this->port); if ($this->_mysqli->connect_error) {
if ($this->_mysqli->connect_error) throw new Exception('Connect Error ' . $this->_mysqli->connect_errno . ': ' . $this->_mysqli->connect_error);
throw new Exception ('Connect Error ' . $this->_mysqli->connect_errno . ': ' . $this->_mysqli->connect_error); }
if ($this->charset) if ($this->charset) {
$this->_mysqli->set_charset ($this->charset); $this->_mysqli->set_charset($this->charset);
}
} }
/** /**
* A method to get mysqli object or create it in case needed * A method to get mysqli object or create it in case needed
*/ */
public function mysqli () public function mysqli()
{ {
if (!$this->_mysqli) if (!$this->_mysqli) {
$this->connect(); $this->connect();
}
return $this->_mysqli; return $this->_mysqli;
} }
...@@ -261,8 +288,9 @@ class MysqliDb ...@@ -261,8 +288,9 @@ class MysqliDb
*/ */
protected function reset() protected function reset()
{ {
if ($this->traceEnabled) if ($this->traceEnabled) {
$this->trace[] = array ($this->_lastQuery, (microtime(true) - $this->traceStartQ) , $this->_traceGetCaller()); $this->trace[] = array($this->_lastQuery, (microtime(true) - $this->traceStartQ), $this->_traceGetCaller());
}
$this->_where = array(); $this->_where = array();
$this->_having = array(); $this->_having = array();
...@@ -285,9 +313,10 @@ class MysqliDb ...@@ -285,9 +313,10 @@ class MysqliDb
/** /**
* Helper function to create dbObject with Json return type * Helper function to create dbObject with Json return type
* *
* @return dbObject * @return object
*/ */
public function JsonBuilder () { public function JsonBuilder()
{
$this->returnType = 'Json'; $this->returnType = 'Json';
return $this; return $this;
} }
...@@ -296,9 +325,10 @@ class MysqliDb ...@@ -296,9 +325,10 @@ class MysqliDb
* Helper function to create dbObject with Array return type * Helper function to create dbObject with Array return type
* Added for consistency as thats default output type * Added for consistency as thats default output type
* *
* @return dbObject * @return object
*/ */
public function ArrayBuilder () { public function ArrayBuilder()
{
$this->returnType = 'Array'; $this->returnType = 'Array';
return $this; return $this;
} }
...@@ -306,9 +336,10 @@ class MysqliDb ...@@ -306,9 +336,10 @@ class MysqliDb
/** /**
* Helper function to create dbObject with Object return type. * Helper function to create dbObject with Object return type.
* *
* @return dbObject * @return object
*/ */
public function ObjectBuilder () { public function ObjectBuilder()
{
$this->returnType = 'Object'; $this->returnType = 'Object';
return $this; return $this;
} }
...@@ -317,6 +348,7 @@ class MysqliDb ...@@ -317,6 +348,7 @@ class MysqliDb
* Method to set a prefix * Method to set a prefix
* *
* @param string $prefix Contains a tableprefix * @param string $prefix Contains a tableprefix
* @return object
*/ */
public function setPrefix($prefix = '') public function setPrefix($prefix = '')
{ {
...@@ -332,26 +364,25 @@ class MysqliDb ...@@ -332,26 +364,25 @@ class MysqliDb
* *
* @return array Contains the returned rows from the query. * @return array Contains the returned rows from the query.
*/ */
public function rawQuery ($query, $bindParams = null) public function rawQuery($query, $bindParams = null)
{ {
$params = array(''); // Create the empty 0 index $params = array(''); // Create the empty 0 index
$this->_query = $query; $this->_query = $query;
$stmt = $this->_prepareQuery(); $stmt = $this->_prepareQuery();
if (is_array ($bindParams) === true) { if (is_array($bindParams) === true) {
foreach ($bindParams as $prop => $val) { foreach ($bindParams as $prop => $val) {
$params[0] .= $this->_determineType($val); $params[0] .= $this->_determineType($val);
array_push($params, $bindParams[$prop]); array_push($params, $bindParams[$prop]);
} }
call_user_func_array(array($stmt, 'bind_param'), $this->refValues($params)); call_user_func_array(array($stmt, 'bind_param'), $this->refValues($params));
} }
$stmt->execute(); $stmt->execute();
$this->count = $stmt->affected_rows; $this->count = $stmt->affected_rows;
$this->_stmtError = $stmt->error; $this->_stmtError = $stmt->error;
$this->_lastQuery = $this->replacePlaceHolders ($this->_query, $params); $this->_lastQuery = $this->replacePlaceHolders($this->_query, $params);
$res = $this->_dynamicBindResults($stmt); $res = $this->_dynamicBindResults($stmt);
$this->reset(); $this->reset();
...@@ -368,10 +399,12 @@ class MysqliDb ...@@ -368,10 +399,12 @@ class MysqliDb
* *
* @return array Contains the returned row from the query. * @return array Contains the returned row from the query.
*/ */
public function rawQueryOne ($query, $bindParams = null) { public function rawQueryOne($query, $bindParams = null)
$res = $this->rawQuery ($query, $bindParams); {
if (is_array ($res) && isset ($res[0])) $res = $this->rawQuery($query, $bindParams);
if (is_array($res) && isset($res[0])) {
return $res[0]; return $res[0];
}
return null; return null;
} }
...@@ -386,21 +419,26 @@ class MysqliDb ...@@ -386,21 +419,26 @@ class MysqliDb
* *
* @return mixed Contains the returned rows from the query. * @return mixed Contains the returned rows from the query.
*/ */
public function rawQueryValue ($query, $bindParams = null) { public function rawQueryValue($query, $bindParams = null)
$res = $this->rawQuery ($query, $bindParams); {
if (!$res) $res = $this->rawQuery($query, $bindParams);
if (!$res) {
return null; return null;
}
$limit = preg_match ('/limit\s+1;?$/i', $query); $limit = preg_match('/limit\s+1;?$/i', $query);
$key = key ($res[0]); $key = key($res[0]);
if (isset($res[0][$key]) && $limit == true) if (isset($res[0][$key]) && $limit == true) {
return $res[0][$key]; return $res[0][$key];
}
$newRes = Array (); $newRes = Array();
for ($i = 0; $i < $this->count; $i++) for ($i = 0; $i < $this->count; $i++) {
$newRes[] = $res[$i][$key]; $newRes[] = $res[$i][$key];
}
return $newRes; return $newRes;
} }
/** /**
* *
* @param string $query Contains a user-provided select query. * @param string $query Contains a user-provided select query.
...@@ -426,30 +464,35 @@ class MysqliDb ...@@ -426,30 +464,35 @@ class MysqliDb
* @uses $MySqliDb->setQueryOption('name'); * @uses $MySqliDb->setQueryOption('name');
* *
* @param string/array $options The optons name of the query. * @param string/array $options The optons name of the query.
* * @throws Exception
* @return MysqliDb * @return MysqliDb
*/ */
public function setQueryOption ($options) { public function setQueryOption($options)
$allowedOptions = Array ('ALL','DISTINCT','DISTINCTROW','HIGH_PRIORITY','STRAIGHT_JOIN','SQL_SMALL_RESULT', {
'SQL_BIG_RESULT','SQL_BUFFER_RESULT','SQL_CACHE','SQL_NO_CACHE', 'SQL_CALC_FOUND_ROWS', $allowedOptions = Array('ALL', 'DISTINCT', 'DISTINCTROW', 'HIGH_PRIORITY', 'STRAIGHT_JOIN', 'SQL_SMALL_RESULT',
'LOW_PRIORITY','IGNORE','QUICK', 'MYSQLI_NESTJOIN', 'FOR UPDATE', 'LOCK IN SHARE MODE'); 'SQL_BIG_RESULT', 'SQL_BUFFER_RESULT', 'SQL_CACHE', 'SQL_NO_CACHE', 'SQL_CALC_FOUND_ROWS',
if (!is_array ($options)) 'LOW_PRIORITY', 'IGNORE', 'QUICK', 'MYSQLI_NESTJOIN', 'FOR UPDATE', 'LOCK IN SHARE MODE');
$options = Array ($options);
if (!is_array($options)) {
$options = Array($options);
}
foreach ($options as $option) { foreach ($options as $option) {
$option = strtoupper ($option); $option = strtoupper($option);
if (!in_array ($option, $allowedOptions)) if (!in_array($option, $allowedOptions)) {
die ('Wrong query option: '.$option); throw new Exception('Wrong query option: ' . $option);
}
if ($option == 'MYSQLI_NESTJOIN') if ($option == 'MYSQLI_NESTJOIN') {
$this->_nestJoin = true; $this->_nestJoin = true;
else if ($option == 'FOR UPDATE') } elseif ($option == 'FOR UPDATE') {
$this->_forUpdate = true; $this->_forUpdate = true;
else if ($option == 'LOCK IN SHARE MODE') } elseif ($option == 'LOCK IN SHARE MODE') {
$this->_lockInShareMode = true; $this->_lockInShareMode = true;
else } else {
$this->_queryOptions[] = $option; $this->_queryOptions[] = $option;
} }
}
return $this; return $this;
} }
...@@ -459,8 +502,9 @@ class MysqliDb ...@@ -459,8 +502,9 @@ class MysqliDb
* *
* @return MysqliDb * @return MysqliDb
*/ */
public function withTotalCount () { public function withTotalCount()
$this->setQueryOption ('SQL_CALC_FOUND_ROWS'); {
$this->setQueryOption('SQL_CALC_FOUND_ROWS');
return $this; return $this;
} }
...@@ -475,21 +519,25 @@ class MysqliDb ...@@ -475,21 +519,25 @@ class MysqliDb
*/ */
public function get($tableName, $numRows = null, $columns = '*') public function get($tableName, $numRows = null, $columns = '*')
{ {
if (empty ($columns)) if (empty($columns)) {
$columns = '*'; $columns = '*';
}
$column = is_array($columns) ? implode(', ', $columns) : $columns; $column = is_array($columns) ? implode(', ', $columns) : $columns;
if (strpos ($tableName, '.') === false)
if (strpos($tableName, '.') === false) {
$this->_tableName = self::$prefix . $tableName; $this->_tableName = self::$prefix . $tableName;
else } else {
$this->_tableName = $tableName; $this->_tableName = $tableName;
}
$this->_query = 'SELECT ' . implode(' ', $this->_queryOptions) . ' ' . $this->_query = 'SELECT ' . implode(' ', $this->_queryOptions) . ' ' .
$column . " FROM " . $this->_tableName; $column . " FROM " . $this->_tableName;
$stmt = $this->_buildQuery($numRows); $stmt = $this->_buildQuery($numRows);
if ($this->isSubQuery) if ($this->isSubQuery) {
return $this; return $this;
}
$stmt->execute(); $stmt->execute();
$this->_stmtError = $stmt->error; $this->_stmtError = $stmt->error;
...@@ -508,14 +556,15 @@ class MysqliDb ...@@ -508,14 +556,15 @@ class MysqliDb
*/ */
public function getOne($tableName, $columns = '*') public function getOne($tableName, $columns = '*')
{ {
$res = $this->get ($tableName, 1, $columns); $res = $this->get($tableName, 1, $columns);
if ($res instanceof MysqliDb) if ($res instanceof MysqliDb) {
return $res; return $res;
else if (is_array ($res) && isset ($res[0])) } elseif (is_array($res) && isset($res[0])) {
return $res[0]; return $res[0];
else if ($res) } elseif ($res) {
return $res; return $res;
}
return null; return null;
} }
...@@ -528,22 +577,25 @@ class MysqliDb ...@@ -528,22 +577,25 @@ class MysqliDb
* *
* @return mixed Contains the value of a returned column / array of values * @return mixed Contains the value of a returned column / array of values
*/ */
public function getValue ($tableName, $column, $limit = 1) public function getValue($tableName, $column, $limit = 1)
{ {
$res = $this->ArrayBuilder()->get ($tableName, $limit, "{$column} AS retval"); $res = $this->ArrayBuilder()->get($tableName, $limit, "{$column} AS retval");
if (!$res) if (!$res) {
return null; return null;
}
if ($limit == 1) { if ($limit == 1) {
if (isset ($res[0]["retval"])) if (isset($res[0]["retval"])) {
return $res[0]["retval"]; return $res[0]["retval"];
}
return null; return null;
} }
$newRes = Array (); $newRes = Array();
for ($i = 0; $i < $this->count; $i++) for ($i = 0; $i < $this->count; $i++) {
$newRes[] = $res[$i]['retval']; $newRes[] = $res[$i]['retval'];
}
return $newRes; return $newRes;
} }
...@@ -555,8 +607,9 @@ class MysqliDb ...@@ -555,8 +607,9 @@ class MysqliDb
* *
* @return boolean Boolean indicating whether the insert query was completed succesfully. * @return boolean Boolean indicating whether the insert query was completed succesfully.
*/ */
public function insert ($tableName, $insertData) { public function insert($tableName, $insertData)
return $this->_buildInsert ($tableName, $insertData, 'INSERT'); {
return $this->_buildInsert($tableName, $insertData, 'INSERT');
} }
/** /**
...@@ -567,8 +620,9 @@ class MysqliDb ...@@ -567,8 +620,9 @@ class MysqliDb
* *
* @return boolean Boolean indicating whether the insert query was completed succesfully. * @return boolean Boolean indicating whether the insert query was completed succesfully.
*/ */
public function replace ($tableName, $insertData) { public function replace($tableName, $insertData)
return $this->_buildInsert ($tableName, $insertData, 'REPLACE'); {
return $this->_buildInsert($tableName, $insertData, 'REPLACE');
} }
/** /**
...@@ -595,12 +649,13 @@ class MysqliDb ...@@ -595,12 +649,13 @@ class MysqliDb
*/ */
public function update($tableName, $tableData) public function update($tableName, $tableData)
{ {
if ($this->isSubQuery) if ($this->isSubQuery) {
return; return;
}
$this->_query = "UPDATE " . self::$prefix . $tableName; $this->_query = "UPDATE " . self::$prefix . $tableName;
$stmt = $this->_buildQuery (null, $tableData); $stmt = $this->_buildQuery(null, $tableData);
$status = $stmt->execute(); $status = $stmt->execute();
$this->reset(); $this->reset();
$this->_stmtError = $stmt->error; $this->_stmtError = $stmt->error;
...@@ -620,14 +675,17 @@ class MysqliDb ...@@ -620,14 +675,17 @@ class MysqliDb
*/ */
public function delete($tableName, $numRows = null) public function delete($tableName, $numRows = null)
{ {
if ($this->isSubQuery) if ($this->isSubQuery) {
return; return;
}
$table = self::$prefix . $tableName; $table = self::$prefix . $tableName;
if (count ($this->_join))
$this->_query = "DELETE " . preg_replace ('/.* (.*)/', '$1', $table) . " FROM " . $table; if (count($this->_join)) {
else $this->_query = "DELETE " . preg_replace('/.* (.*)/', '$1', $table) . " FROM " . $table;
} else {
$this->_query = "DELETE FROM " . $table; $this->_query = "DELETE FROM " . $table;
}
$stmt = $this->_buildQuery($numRows); $stmt = $this->_buildQuery($numRows);
$stmt->execute(); $stmt->execute();
...@@ -650,13 +708,16 @@ class MysqliDb ...@@ -650,13 +708,16 @@ class MysqliDb
public function where($whereProp, $whereValue = 'DBNULL', $operator = '=', $cond = 'AND') public function where($whereProp, $whereValue = 'DBNULL', $operator = '=', $cond = 'AND')
{ {
// forkaround for an old operation api // forkaround for an old operation api
if (is_array ($whereValue) && ($key = key ($whereValue)) != "0") { if (is_array($whereValue) && ($key = key($whereValue)) != "0") {
$operator = $key; $operator = $key;
$whereValue = $whereValue[$key]; $whereValue = $whereValue[$key];
} }
if (count ($this->_where) == 0)
if (count($this->_where) == 0) {
$cond = ''; $cond = '';
$this->_where[] = Array ($cond, $whereProp, $operator, $whereValue); }
$this->_where[] = Array($cond, $whereProp, $operator, $whereValue);
return $this; return $this;
} }
...@@ -686,9 +747,8 @@ class MysqliDb ...@@ -686,9 +747,8 @@ class MysqliDb
*/ */
public function orWhere($whereProp, $whereValue = 'DBNULL', $operator = '=') public function orWhere($whereProp, $whereValue = 'DBNULL', $operator = '=')
{ {
return $this->where ($whereProp, $whereValue, $operator, 'OR'); return $this->where($whereProp, $whereValue, $operator, 'OR');
} }
/* /*
* This method allows you to specify multiple (method chaining optional) AND HAVING statements for SQL queries. * This method allows you to specify multiple (method chaining optional) AND HAVING statements for SQL queries.
* *
...@@ -699,12 +759,14 @@ class MysqliDb ...@@ -699,12 +759,14 @@ class MysqliDb
* *
* @return MysqliDb * @return MysqliDb
*/ */
public function having($havingProp, $havingValue = null, $operator = null) public function having($havingProp, $havingValue = null, $operator = null)
{ {
if ($operator) if ($operator) {
$havingValue = Array ($operator => $havingValue); $havingValue = Array($operator => $havingValue);
}
$this->_having[] = Array ("AND", $havingValue, $havingProp); $this->_having[] = Array("AND", $havingValue, $havingProp);
return $this; return $this;
} }
...@@ -720,10 +782,11 @@ class MysqliDb ...@@ -720,10 +782,11 @@ class MysqliDb
*/ */
public function orHaving($havingProp, $havingValue = null, $operator = null) public function orHaving($havingProp, $havingValue = null, $operator = null)
{ {
if ($operator) if ($operator) {
$havingValue = Array ($operator => $havingValue); $havingValue = Array($operator => $havingValue);
}
$this->_having[] = Array ("OR", $havingValue, $havingProp); $this->_having[] = Array("OR", $havingValue, $havingProp);
return $this; return $this;
} }
...@@ -735,24 +798,27 @@ class MysqliDb ...@@ -735,24 +798,27 @@ class MysqliDb
* @param string $joinTable The name of the table. * @param string $joinTable The name of the table.
* @param string $joinCondition the condition. * @param string $joinCondition the condition.
* @param string $joinType 'LEFT', 'INNER' etc. * @param string $joinType 'LEFT', 'INNER' etc.
* * @throws Exception
* @return MysqliDb * @return MysqliDb
*/ */
public function join($joinTable, $joinCondition, $joinType = '') public function join($joinTable, $joinCondition, $joinType = '')
{ {
$allowedTypes = array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'); $allowedTypes = array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER');
$joinType = strtoupper (trim ($joinType)); $joinType = strtoupper(trim($joinType));
if ($joinType && !in_array ($joinType, $allowedTypes)) if ($joinType && !in_array($joinType, $allowedTypes)) {
die ('Wrong JOIN type: '.$joinType); throw new Exception('Wrong JOIN type: ' . $joinType);
}
if (!is_object ($joinTable)) if (!is_object($joinTable)) {
$joinTable = self::$prefix . $joinTable; $joinTable = self::$prefix . $joinTable;
}
$this->_join[] = Array ($joinType, $joinTable, $joinCondition); $this->_join[] = Array($joinType, $joinTable, $joinCondition);
return $this; return $this;
} }
/** /**
* This method allows you to specify multiple (method chaining optional) ORDER BY statements for SQL queries. * This method allows you to specify multiple (method chaining optional) ORDER BY statements for SQL queries.
* *
...@@ -760,27 +826,29 @@ class MysqliDb ...@@ -760,27 +826,29 @@ class MysqliDb
* *
* @param string $orderByField The name of the database field. * @param string $orderByField The name of the database field.
* @param string $orderByDirection Order direction. * @param string $orderByDirection Order direction.
* * @throws Exception
* @return MysqliDb * @return MysqliDb
*/ */
public function orderBy($orderByField, $orderbyDirection = "DESC", $customFields = null) public function orderBy($orderByField, $orderbyDirection = "DESC", $customFields = null)
{ {
$allowedDirection = Array ("ASC", "DESC"); $allowedDirection = Array("ASC", "DESC");
$orderbyDirection = strtoupper (trim ($orderbyDirection)); $orderbyDirection = strtoupper(trim($orderbyDirection));
$orderByField = preg_replace ("/[^-a-z0-9\.\(\),_`\*\'\"]+/i",'', $orderByField); $orderByField = preg_replace("/[^-a-z0-9\.\(\),_`\*\'\"]+/i", '', $orderByField);
// Add table prefix to orderByField if needed. // Add table prefix to orderByField if needed.
//FIXME: We are adding prefix only if table is enclosed into `` to distinguish aliases //FIXME: We are adding prefix only if table is enclosed into `` to distinguish aliases
// from table names // from table names
$orderByField = preg_replace('/(\`)([`a-zA-Z0-9_]*\.)/', '\1' . self::$prefix. '\2', $orderByField); $orderByField = preg_replace('/(\`)([`a-zA-Z0-9_]*\.)/', '\1' . self::$prefix . '\2', $orderByField);
if (empty($orderbyDirection) || !in_array ($orderbyDirection, $allowedDirection)) if (empty($orderbyDirection) || !in_array($orderbyDirection, $allowedDirection)) {
die ('Wrong order direction: '.$orderbyDirection); throw new Exception('Wrong order direction: ' . $orderbyDirection);
}
if (is_array ($customFields)) { if (is_array($customFields)) {
foreach ($customFields as $key => $value) foreach ($customFields as $key => $value) {
$customFields[$key] = preg_replace ("/[^-a-z0-9\.\(\),_`]+/i",'', $value); $customFields[$key] = preg_replace("/[^-a-z0-9\.\(\),_`]+/i", '', $value);
}
$orderByField = 'FIELD (' . $orderByField . ', "' . implode('","', $customFields) . '")'; $orderByField = 'FIELD (' . $orderByField . ', "' . implode('","', $customFields) . '")';
} }
...@@ -800,7 +868,7 @@ class MysqliDb ...@@ -800,7 +868,7 @@ class MysqliDb
*/ */
public function groupBy($groupByField) public function groupBy($groupByField)
{ {
$groupByField = preg_replace ("/[^-a-z0-9\.\(\),_\*]+/i",'', $groupByField); $groupByField = preg_replace("/[^-a-z0-9\.\(\),_\*]+/i", '', $groupByField);
$this->_groupBy[] = $groupByField; $this->_groupBy[] = $groupByField;
return $this; return $this;
...@@ -836,7 +904,8 @@ class MysqliDb ...@@ -836,7 +904,8 @@ class MysqliDb
* *
* @return bool True if connection is up * @return bool True if connection is up
*/ */
public function ping() { public function ping()
{
return $this->mysqli()->ping(); return $this->mysqli()->ping();
} }
...@@ -879,9 +948,10 @@ class MysqliDb ...@@ -879,9 +948,10 @@ class MysqliDb
* *
* @param string Variable value * @param string Variable value
*/ */
protected function _bindParam($value) { protected function _bindParam($value)
$this->_bindParams[0] .= $this->_determineType ($value); {
array_push ($this->_bindParams, $value); $this->_bindParams[0] .= $this->_determineType($value);
array_push($this->_bindParams, $value);
} }
/** /**
...@@ -889,9 +959,10 @@ class MysqliDb ...@@ -889,9 +959,10 @@ class MysqliDb
* *
* @param Array Variable with values * @param Array Variable with values
*/ */
protected function _bindParams ($values) { protected function _bindParams($values)
{
foreach ($values as $value) foreach ($values as $value)
$this->_bindParam ($value); $this->_bindParam($value);
} }
/** /**
...@@ -901,14 +972,15 @@ class MysqliDb ...@@ -901,14 +972,15 @@ class MysqliDb
* *
* @param Array Variable with values * @param Array Variable with values
*/ */
protected function _buildPair ($operator, $value) { protected function _buildPair($operator, $value)
{
if (!is_object($value)) { if (!is_object($value)) {
$this->_bindParam ($value); $this->_bindParam($value);
return ' ' . $operator. ' ? '; return ' ' . $operator . ' ? ';
} }
$subQuery = $value->getSubQuery (); $subQuery = $value->getSubQuery();
$this->_bindParams ($subQuery['params']); $this->_bindParams($subQuery['params']);
return " " . $operator . " (" . $subQuery['query'] . ") " . $subQuery['alias']; return " " . $operator . " (" . $subQuery['query'] . ") " . $subQuery['alias'];
} }
...@@ -921,23 +993,26 @@ class MysqliDb ...@@ -921,23 +993,26 @@ class MysqliDb
* *
* @return boolean Boolean indicating whether the insert query was completed succesfully. * @return boolean Boolean indicating whether the insert query was completed succesfully.
*/ */
private function _buildInsert ($tableName, $insertData, $operation) private function _buildInsert($tableName, $insertData, $operation)
{ {
if ($this->isSubQuery) if ($this->isSubQuery) {
return; return;
}
$this->_query = $operation . " " . implode (' ', $this->_queryOptions) ." INTO " .self::$prefix . $tableName; $this->_query = $operation . " " . implode(' ', $this->_queryOptions) . " INTO " . self::$prefix . $tableName;
$stmt = $this->_buildQuery (null, $insertData); $stmt = $this->_buildQuery(null, $insertData);
$stmt->execute(); $stmt->execute();
$this->_stmtError = $stmt->error; $this->_stmtError = $stmt->error;
$this->reset(); $this->reset();
$this->count = $stmt->affected_rows; $this->count = $stmt->affected_rows;
if ($stmt->affected_rows < 1) if ($stmt->affected_rows < 1) {
return false; return false;
}
if ($stmt->insert_id > 0) if ($stmt->insert_id > 0) {
return $stmt->insert_id; return $stmt->insert_id;
}
return true; return true;
} }
...@@ -956,29 +1031,33 @@ class MysqliDb ...@@ -956,29 +1031,33 @@ class MysqliDb
protected function _buildQuery($numRows = null, $tableData = null) protected function _buildQuery($numRows = null, $tableData = null)
{ {
$this->_buildJoin(); $this->_buildJoin();
$this->_buildInsertQuery ($tableData); $this->_buildInsertQuery($tableData);
$this->_buildCondition('WHERE', $this->_where); $this->_buildCondition('WHERE', $this->_where);
$this->_buildGroupBy(); $this->_buildGroupBy();
$this->_buildCondition('HAVING', $this->_having); $this->_buildCondition('HAVING', $this->_having);
$this->_buildOrderBy(); $this->_buildOrderBy();
$this->_buildLimit ($numRows); $this->_buildLimit($numRows);
$this->_buildOnDuplicate($tableData); $this->_buildOnDuplicate($tableData);
if ($this->_forUpdate) if ($this->_forUpdate) {
$this->_query .= ' FOR UPDATE'; $this->_query .= ' FOR UPDATE';
if ($this->_lockInShareMode) }
if ($this->_lockInShareMode) {
$this->_query .= ' LOCK IN SHARE MODE'; $this->_query .= ' LOCK IN SHARE MODE';
}
$this->_lastQuery = $this->replacePlaceHolders ($this->_query, $this->_bindParams); $this->_lastQuery = $this->replacePlaceHolders($this->_query, $this->_bindParams);
if ($this->isSubQuery) if ($this->isSubQuery) {
return; return;
}
// Prepare query // Prepare query
$stmt = $this->_prepareQuery(); $stmt = $this->_prepareQuery();
// Bind parameters to statement if any // Bind parameters to statement if any
if (count ($this->_bindParams) > 1) if (count($this->_bindParams) > 1) {
call_user_func_array(array($stmt, 'bind_param'), $this->refValues($this->_bindParams)); call_user_func_array(array($stmt, 'bind_param'), $this->refValues($this->_bindParams));
}
return $stmt; return $stmt;
} }
...@@ -995,7 +1074,9 @@ class MysqliDb ...@@ -995,7 +1074,9 @@ class MysqliDb
{ {
$parameters = array(); $parameters = array();
$results = array(); $results = array();
// See http://php.net/manual/en/mysqli-result.fetch-fields.php /**
* @see http://php.net/manual/en/mysqli-result.fetch-fields.php
*/
$mysqlLongType = 252; $mysqlLongType = 252;
$shouldStoreResult = false; $shouldStoreResult = false;
...@@ -1003,16 +1084,17 @@ class MysqliDb ...@@ -1003,16 +1084,17 @@ class MysqliDb
// if $meta is false yet sqlstate is true, there's no sql error but the query is // if $meta is false yet sqlstate is true, there's no sql error but the query is
// most likely an update/insert/delete which doesn't produce any results // most likely an update/insert/delete which doesn't produce any results
if(!$meta && $stmt->sqlstate) if (!$meta && $stmt->sqlstate)
return array(); return array();
$row = array(); $row = array();
while ($field = $meta->fetch_field()) { while ($field = $meta->fetch_field()) {
if ($field->type == $mysqlLongType) if ($field->type == $mysqlLongType) {
$shouldStoreResult = true; $shouldStoreResult = true;
}
if ($this->_nestJoin && $field->table != $this->_tableName) { if ($this->_nestJoin && $field->table != $this->_tableName) {
$field->table = substr ($field->table, strlen (self::$prefix)); $field->table = substr($field->table, strlen(self::$prefix));
$row[$field->table][$field->name] = null; $row[$field->table][$field->name] = null;
$parameters[] = & $row[$field->table][$field->name]; $parameters[] = & $row[$field->table][$field->name];
} else { } else {
...@@ -1024,99 +1106,119 @@ class MysqliDb ...@@ -1024,99 +1106,119 @@ class MysqliDb
// avoid out of memory bug in php 5.2 and 5.3. Mysqli allocates lot of memory for long* // avoid out of memory bug in php 5.2 and 5.3. Mysqli allocates lot of memory for long*
// and blob* types. So to avoid out of memory issues store_result is used // and blob* types. So to avoid out of memory issues store_result is used
// https://github.com/joshcam/PHP-MySQLi-Database-Class/pull/119 // https://github.com/joshcam/PHP-MySQLi-Database-Class/pull/119
if ($shouldStoreResult) if ($shouldStoreResult) {
$stmt->store_result(); $stmt->store_result();
}
call_user_func_array(array($stmt, 'bind_result'), $parameters); call_user_func_array(array($stmt, 'bind_result'), $parameters);
$this->totalCount = 0; $this->totalCount = 0;
$this->count = 0; $this->count = 0;
while ($stmt->fetch()) { while ($stmt->fetch()) {
if ($this->returnType == 'Object') { if ($this->returnType == 'Object') {
$x = new stdClass (); $result = new stdClass ();
foreach ($row as $key => $val) { foreach ($row as $key => $val) {
if (is_array ($val)) { if (is_array($val)) {
$x->$key = new stdClass (); $result->$key = new stdClass ();
foreach ($val as $k => $v) foreach ($val as $k => $v) {
$x->$key->$k = $v; $result->$key->$k = $v;
}
} else } else
$x->$key = $val; $result->$key = $val;
} }
} else { } else {
$x = array(); $result = array();
foreach ($row as $key => $val) { foreach ($row as $key => $val) {
if (is_array($val)) { if (is_array($val)) {
foreach ($val as $k => $v) foreach ($val as $k => $v) {
$x[$key][$k] = $v; $result[$key][$k] = $v;
}
} else } else
$x[$key] = $val; $result[$key] = $val;
} }
} }
$this->count++; $this->count++;
if ($this->_mapKey) if ($this->_mapKey)
$results[$row[$this->_mapKey]] = count ($row) > 2 ? $x : end ($x); $results[$row[$this->_mapKey]] = count($row) > 2 ? $result : end($result);
else else
array_push ($results, $x); array_push($results, $result);
} }
if ($shouldStoreResult)
if ($shouldStoreResult) {
$stmt->free_result(); $stmt->free_result();
}
$stmt->close(); $stmt->close();
// stored procedures sometimes can return more then 1 resultset // stored procedures sometimes can return more then 1 resultset
if ($this->mysqli()->more_results()) if ($this->mysqli()->more_results()) {
$this->mysqli()->next_result(); $this->mysqli()->next_result();
}
if (in_array ('SQL_CALC_FOUND_ROWS', $this->_queryOptions)) { if (in_array('SQL_CALC_FOUND_ROWS', $this->_queryOptions)) {
$stmt = $this->mysqli()->query ('SELECT FOUND_ROWS()'); $stmt = $this->mysqli()->query('SELECT FOUND_ROWS()');
$totalCount = $stmt->fetch_row(); $totalCount = $stmt->fetch_row();
$this->totalCount = $totalCount[0]; $this->totalCount = $totalCount[0];
} }
if ($this->returnType == 'Json')
return json_encode ($results);
return $results; if ($this->returnType == 'Json') {
return json_encode($results);
} }
return $results;
}
/** /**
* Abstraction method that will build an JOIN part of the query * Abstraction method that will build an JOIN part of the query
*/ */
protected function _buildJoin () { protected function _buildJoin()
if (empty ($this->_join)) {
if (empty($this->_join)) {
return; return;
}
foreach ($this->_join as $data) { foreach ($this->_join as $data) {
list ($joinType, $joinTable, $joinCondition) = $data; list ($joinType, $joinTable, $joinCondition) = $data;
if (is_object ($joinTable)) if (is_object($joinTable)) {
$joinStr = $this->_buildPair ("", $joinTable); $joinStr = $this->_buildPair("", $joinTable);
else } else {
$joinStr = $joinTable; $joinStr = $joinTable;
}
$this->_query .= " " . $joinType. " JOIN " . $joinStr ." on " . $joinCondition; $this->_query .= " " . $joinType . " JOIN " . $joinStr . " on " . $joinCondition;
} }
} }
public function _buildDataPairs ($tableData, $tableColumns, $isInsert) { /**
*
* @throws Exception
*/
public function _buildDataPairs($tableData, $tableColumns, $isInsert)
{
foreach ($tableColumns as $column) { foreach ($tableColumns as $column) {
$value = $tableData[$column]; $value = $tableData[$column];
if (!$isInsert)
if (!$isInsert) {
$this->_query .= "`" . $column . "` = "; $this->_query .= "`" . $column . "` = ";
}
// Subquery value // Subquery value
if ($value instanceof MysqliDb) { if ($value instanceof MysqliDb) {
$this->_query .= $this->_buildPair ("", $value) . ", "; $this->_query .= $this->_buildPair("", $value) . ", ";
continue; continue;
} }
// Simple value // Simple value
if (!is_array ($value)) { if (!is_array($value)) {
$this->_bindParam($value); $this->_bindParam($value);
$this->_query .= '?, '; $this->_query .= '?, ';
continue; continue;
} }
// Function value // Function value
$key = key ($value); $key = key($value);
$val = $value[$key]; $val = $value[$key];
switch ($key) { switch ($key) {
case '[I]': case '[I]':
...@@ -1124,8 +1226,9 @@ class MysqliDb ...@@ -1124,8 +1226,9 @@ class MysqliDb
break; break;
case '[F]': case '[F]':
$this->_query .= $val[0] . ", "; $this->_query .= $val[0] . ", ";
if (!empty ($val[1])) if (!empty($val[1])) {
$this->_bindParams ($val[1]); $this->_bindParams($val[1]);
}
break; break;
case '[N]': case '[N]':
if ($val == null) if ($val == null)
...@@ -1134,7 +1237,7 @@ class MysqliDb ...@@ -1134,7 +1237,7 @@ class MysqliDb
$this->_query .= "!" . $val . ", "; $this->_query .= "!" . $val . ", ";
break; break;
default: default:
die ("Wrong operation"); throw new Exception("Wrong operation");
} }
} }
$this->_query = rtrim($this->_query, ', '); $this->_query = rtrim($this->_query, ', ');
...@@ -1149,85 +1252,93 @@ class MysqliDb ...@@ -1149,85 +1252,93 @@ class MysqliDb
{ {
if (is_array($this->_updateColumns) && !empty($this->_updateColumns)) { if (is_array($this->_updateColumns) && !empty($this->_updateColumns)) {
$this->_query .= " on duplicate key update "; $this->_query .= " on duplicate key update ";
if ($this->_lastInsertId) if ($this->_lastInsertId) {
$this->_query .= $this->_lastInsertId . "=LAST_INSERT_ID (".$this->_lastInsertId."), "; $this->_query .= $this->_lastInsertId . "=LAST_INSERT_ID (" . $this->_lastInsertId . "), ";
}
foreach ($this->_updateColumns as $key => $val) { foreach ($this->_updateColumns as $key => $val) {
// skip all params without a value // skip all params without a value
if (is_numeric ($key)) { if (is_numeric($key)) {
$this->_updateColumns[$val] = ''; $this->_updateColumns[$val] = '';
unset ($this->_updateColumns[$key]); unset($this->_updateColumns[$key]);
} else } else
$tableData[$key] = $val; $tableData[$key] = $val;
} }
$this->_buildDataPairs ($tableData, array_keys ($this->_updateColumns), false); $this->_buildDataPairs($tableData, array_keys($this->_updateColumns), false);
} }
} }
/** /**
* Abstraction method that will build an INSERT or UPDATE part of the query * Abstraction method that will build an INSERT or UPDATE part of the query
*/ */
protected function _buildInsertQuery ($tableData) { protected function _buildInsertQuery($tableData)
if (!is_array ($tableData)) {
if (!is_array($tableData)) {
return; return;
}
$isInsert = preg_match ('/^[INSERT|REPLACE]/', $this->_query); $isInsert = preg_match('/^[INSERT|REPLACE]/', $this->_query);
$dataColumns = array_keys ($tableData); $dataColumns = array_keys($tableData);
if ($isInsert) if ($isInsert) {
$this->_query .= ' (`' . implode ($dataColumns, '`, `') . '`) VALUES ('; $this->_query .= ' (`' . implode($dataColumns, '`, `') . '`) VALUES (';
else } else {
$this->_query .= " SET "; $this->_query .= " SET ";
}
$this->_buildDataPairs ($tableData, $dataColumns, $isInsert); $this->_buildDataPairs($tableData, $dataColumns, $isInsert);
if ($isInsert) if ($isInsert) {
$this->_query .= ')'; $this->_query .= ')';
} }
}
/** /**
* Abstraction method that will build the part of the WHERE conditions * Abstraction method that will build the part of the WHERE conditions
*/ */
protected function _buildCondition ($operator, &$conditions) { protected function _buildCondition($operator, &$conditions)
if (empty ($conditions)) {
if (empty($conditions)) {
return; return;
}
//Prepare the where portion of the query //Prepare the where portion of the query
$this->_query .= ' ' . $operator; $this->_query .= ' ' . $operator;
foreach ($conditions as $cond) { foreach ($conditions as $cond) {
list ($concat, $varName, $operator, $val) = $cond; list ($concat, $varName, $operator, $val) = $cond;
$this->_query .= " " . $concat ." " . $varName; $this->_query .= " " . $concat . " " . $varName;
switch (strtolower ($operator)) { switch (strtolower($operator)) {
case 'not in': case 'not in':
case 'in': case 'in':
$comparison = ' ' . $operator. ' ('; $comparison = ' ' . $operator . ' (';
if (is_object ($val)) { if (is_object($val)) {
$comparison .= $this->_buildPair ("", $val); $comparison .= $this->_buildPair("", $val);
} else { } else {
foreach ($val as $v) { foreach ($val as $v) {
$comparison .= ' ?,'; $comparison .= ' ?,';
$this->_bindParam ($v); $this->_bindParam($v);
} }
} }
$this->_query .= rtrim($comparison, ',').' ) '; $this->_query .= rtrim($comparison, ',') . ' ) ';
break; break;
case 'not between': case 'not between':
case 'between': case 'between':
$this->_query .= " $operator ? AND ? "; $this->_query .= " $operator ? AND ? ";
$this->_bindParams ($val); $this->_bindParams($val);
break; break;
case 'not exists': case 'not exists':
case 'exists': case 'exists':
$this->_query.= $operator . $this->_buildPair ("", $val); $this->_query.= $operator . $this->_buildPair("", $val);
break; break;
default: default:
if (is_array ($val)) if (is_array($val)) {
$this->_bindParams ($val); $this->_bindParams($val);
else if ($val === null) } elseif ($val === null) {
$this->_query .= $operator . " NULL"; $this->_query .= $operator . " NULL";
else if ($val != 'DBNULL' || $val == '0') } elseif ($val != 'DBNULL' || $val == '0') {
$this->_query .= $this->_buildPair ($operator, $val); $this->_query .= $this->_buildPair($operator, $val);
}
} }
} }
} }
...@@ -1236,13 +1347,17 @@ class MysqliDb ...@@ -1236,13 +1347,17 @@ class MysqliDb
* Abstraction method that will build the GROUP BY part of the WHERE statement * Abstraction method that will build the GROUP BY part of the WHERE statement
* *
*/ */
protected function _buildGroupBy () { protected function _buildGroupBy()
if (empty ($this->_groupBy)) {
if (empty($this->_groupBy)) {
return; return;
}
$this->_query .= " GROUP BY "; $this->_query .= " GROUP BY ";
foreach ($this->_groupBy as $key => $value)
foreach ($this->_groupBy as $key => $value) {
$this->_query .= $value . ", "; $this->_query .= $value . ", ";
}
$this->_query = rtrim($this->_query, ', ') . " "; $this->_query = rtrim($this->_query, ', ') . " ";
} }
...@@ -1251,19 +1366,22 @@ class MysqliDb ...@@ -1251,19 +1366,22 @@ class MysqliDb
* Abstraction method that will build the LIMIT part of the WHERE statement * Abstraction method that will build the LIMIT part of the WHERE statement
* *
*/ */
protected function _buildOrderBy () { protected function _buildOrderBy()
if (empty ($this->_orderBy)) {
if (empty($this->_orderBy)) {
return; return;
}
$this->_query .= " ORDER BY "; $this->_query .= " ORDER BY ";
foreach ($this->_orderBy as $prop => $value) { foreach ($this->_orderBy as $prop => $value) {
if (strtolower (str_replace (" ", "", $prop)) == 'rand()') if (strtolower(str_replace(" ", "", $prop)) == 'rand()') {
$this->_query .= "rand(), "; $this->_query .= "rand(), ";
else } else {
$this->_query .= $prop . " " . $value . ", "; $this->_query .= $prop . " " . $value . ", ";
} }
}
$this->_query = rtrim ($this->_query, ', ') . " "; $this->_query = rtrim($this->_query, ', ') . " ";
} }
/** /**
...@@ -1272,14 +1390,17 @@ class MysqliDb ...@@ -1272,14 +1390,17 @@ class MysqliDb
* @param integer|array $numRows Array to define SQL limit in format Array ($count, $offset) * @param integer|array $numRows Array to define SQL limit in format Array ($count, $offset)
* or only $count * or only $count
*/ */
protected function _buildLimit ($numRows) { protected function _buildLimit($numRows)
if (!isset ($numRows)) {
if (!isset($numRows)) {
return; return;
}
if (is_array ($numRows)) if (is_array($numRows)) {
$this->_query .= ' LIMIT ' . (int)$numRows[0] . ', ' . (int)$numRows[1]; $this->_query .= ' LIMIT ' . (int) $numRows[0] . ', ' . (int) $numRows[1];
else } else {
$this->_query .= ' LIMIT ' . (int)$numRows; $this->_query .= ' LIMIT ' . (int) $numRows;
}
} }
/** /**
...@@ -1290,10 +1411,13 @@ class MysqliDb ...@@ -1290,10 +1411,13 @@ class MysqliDb
*/ */
protected function _prepareQuery() protected function _prepareQuery()
{ {
if (!$stmt = $this->mysqli()->prepare($this->_query)) if (!$stmt = $this->mysqli()->prepare($this->_query)) {
throw new Exception ("Problem preparing query ($this->_query) " . $this->mysqli()->error); throw new Exception("Problem preparing query ($this->_query) " . $this->mysqli()->error);
if ($this->traceEnabled) }
$this->traceStartQ = microtime (true);
if ($this->traceEnabled) {
$this->traceStartQ = microtime(true);
}
return $stmt; return $stmt;
} }
...@@ -1303,8 +1427,10 @@ class MysqliDb ...@@ -1303,8 +1427,10 @@ class MysqliDb
*/ */
public function __destruct() public function __destruct()
{ {
if ($this->isSubQuery) if ($this->isSubQuery) {
return; return;
}
if ($this->_mysqli) { if ($this->_mysqli) {
$this->_mysqli->close(); $this->_mysqli->close();
$this->_mysqli = null; $this->_mysqli = null;
...@@ -1321,10 +1447,11 @@ class MysqliDb ...@@ -1321,10 +1447,11 @@ class MysqliDb
//Reference in the function arguments are required for HHVM to work //Reference in the function arguments are required for HHVM to work
//https://github.com/facebook/hhvm/issues/5155 //https://github.com/facebook/hhvm/issues/5155
//Referenced data array is required by mysqli since PHP 5.3+ //Referenced data array is required by mysqli since PHP 5.3+
if (strnatcmp (phpversion(), '5.3') >= 0) { if (strnatcmp(phpversion(), '5.3') >= 0) {
$refs = array(); $refs = array();
foreach ($arr as $key => $value) foreach ($arr as $key => $value) {
$refs[$key] = & $arr[$key]; $refs[$key] = & $arr[$key];
}
return $refs; return $refs;
} }
return $arr; return $arr;
...@@ -1337,21 +1464,25 @@ class MysqliDb ...@@ -1337,21 +1464,25 @@ class MysqliDb
* *
* @return string * @return string
*/ */
protected function replacePlaceHolders ($str, $vals) { protected function replacePlaceHolders($str, $vals)
{
$i = 1; $i = 1;
$newStr = ""; $newStr = "";
if (empty ($vals)) if (empty($vals)) {
return $str; return $str;
}
while ($pos = strpos ($str, "?")) { while ($pos = strpos($str, "?")) {
$val = $vals[$i++]; $val = $vals[$i++];
if (is_object ($val)) if (is_object($val)) {
$val = '[object]'; $val = '[object]';
if ($val === NULL) }
if ($val === null) {
$val = 'NULL'; $val = 'NULL';
$newStr .= substr ($str, 0, $pos) . "'". $val . "'"; }
$str = substr ($str, $pos + 1); $newStr .= substr($str, 0, $pos) . "'" . $val . "'";
$str = substr($str, $pos + 1);
} }
$newStr .= $str; $newStr .= $str;
return $newStr; return $newStr;
...@@ -1362,7 +1493,8 @@ class MysqliDb ...@@ -1362,7 +1493,8 @@ class MysqliDb
* *
* @return string * @return string
*/ */
public function getLastQuery () { public function getLastQuery()
{
return $this->_lastQuery; return $this->_lastQuery;
} }
...@@ -1371,10 +1503,12 @@ class MysqliDb ...@@ -1371,10 +1503,12 @@ class MysqliDb
* *
* @return string * @return string
*/ */
public function getLastError () { public function getLastError()
if (!$this->_mysqli) {
if (!$this->_mysqli) {
return "mysqli is null"; return "mysqli is null";
return trim ($this->_stmtError . " " . $this->mysqli()->error); }
return trim($this->_stmtError . " " . $this->mysqli()->error);
} }
/** /**
...@@ -1383,20 +1517,22 @@ class MysqliDb ...@@ -1383,20 +1517,22 @@ class MysqliDb
* *
* @return array * @return array
*/ */
public function getSubQuery () { public function getSubQuery()
if (!$this->isSubQuery) {
if (!$this->isSubQuery) {
return null; return null;
}
array_shift ($this->_bindParams); array_shift($this->_bindParams);
$val = Array ('query' => $this->_query, $val = Array('query' => $this->_query,
'params' => $this->_bindParams, 'params' => $this->_bindParams,
'alias' => $this->host 'alias' => $this->host
); );
$this->reset(); $this->reset();
return $val; return $val;
} }
/* Helper functions */ /* Helper functions */
/** /**
* Method returns generated interval function as a string * Method returns generated interval function as a string
* *
...@@ -1408,23 +1544,35 @@ class MysqliDb ...@@ -1408,23 +1544,35 @@ class MysqliDb
* *
* @return string * @return string
*/ */
public function interval ($diff, $func = "NOW()") { public function interval($diff, $func = "NOW()")
$types = Array ("s" => "second", "m" => "minute", "h" => "hour", "d" => "day", "M" => "month", "Y" => "year"); {
$types = Array("s" => "second", "m" => "minute", "h" => "hour", "d" => "day", "M" => "month", "Y" => "year");
$incr = '+'; $incr = '+';
$items = ''; $items = '';
$type = 'd'; $type = 'd';
if ($diff && preg_match('/([+-]?) ?([0-9]+) ?([a-zA-Z]?)/',$diff, $matches)) { if ($diff && preg_match('/([+-]?) ?([0-9]+) ?([a-zA-Z]?)/', $diff, $matches)) {
if (!empty ($matches[1])) $incr = $matches[1]; if (!empty($matches[1])) {
if (!empty ($matches[2])) $items = $matches[2]; $incr = $matches[1];
if (!empty ($matches[3])) $type = $matches[3]; }
if (!in_array($type, array_keys($types)))
if (!empty($matches[2])) {
$items = $matches[2];
}
if (!empty($matches[3])) {
$type = $matches[3];
}
if (!in_array($type, array_keys($types))) {
throw new Exception("invalid interval type in '{$diff}'"); throw new Exception("invalid interval type in '{$diff}'");
$func .= " ".$incr ." interval ". $items ." ".$types[$type] . " ";
} }
return $func;
$func .= " " . $incr . " interval " . $items . " " . $types[$type] . " ";
} }
return $func;
}
/** /**
* Method returns generated interval function as an insert/update function * Method returns generated interval function as an insert/update function
* *
...@@ -1436,44 +1584,52 @@ class MysqliDb ...@@ -1436,44 +1584,52 @@ class MysqliDb
* *
* @return array * @return array
*/ */
public function now ($diff = null, $func = "NOW()") { public function now($diff = null, $func = "NOW()")
return Array ("[F]" => Array($this->interval($diff, $func))); {
return array("[F]" => Array($this->interval($diff, $func)));
} }
/** /**
* Method generates incremental function call * Method generates incremental function call
* @param int increment by int or float. 1 by default * @param int increment by int or float. 1 by default
* @throws Exception
*/ */
public function inc($num = 1) { public function inc($num = 1)
if(!is_numeric($num)) {
throw new Exception ('Argument supplied to inc must be a number'); if (!is_numeric($num)) {
return Array ("[I]" => "+" . $num); throw new Exception('Argument supplied to inc must be a number');
}
return array("[I]" => "+" . $num);
} }
/** /**
* Method generates decrimental function call * Method generates decrimental function call
* @param int increment by int or float. 1 by default * @param int increment by int or float. 1 by default
*/ */
public function dec ($num = 1) { public function dec($num = 1)
if(!is_numeric($num)) {
throw new Exception ('Argument supplied to dec must be a number'); if (!is_numeric($num)) {
return Array ("[I]" => "-" . $num); throw new Exception('Argument supplied to dec must be a number');
}
return array("[I]" => "-" . $num);
} }
/** /**
* Method generates change boolean function call * Method generates change boolean function call
* @param string column name. null by default * @param string column name. null by default
*/ */
public function not ($col = null) { public function not($col = null)
return Array ("[N]" => (string)$col); {
return array("[N]" => (string) $col);
} }
/** /**
* Method generates user defined function call * Method generates user defined function call
* @param string user function body * @param string user function body
*/ */
public function func ($expr, $bindParams = null) { public function func($expr, $bindParams = null)
return Array ("[F]" => Array($expr, $bindParams)); {
return array("[F]" => Array($expr, $bindParams));
} }
/** /**
...@@ -1481,7 +1637,7 @@ class MysqliDb ...@@ -1481,7 +1637,7 @@ class MysqliDb
*/ */
public static function subQuery($subQueryAlias = "") public static function subQuery($subQueryAlias = "")
{ {
return new MysqliDb (Array('host' => $subQueryAlias, 'isSubQuery' => true)); return new self(array('host' => $subQueryAlias, 'isSubQuery' => true));
} }
/** /**
...@@ -1489,9 +1645,9 @@ class MysqliDb ...@@ -1489,9 +1645,9 @@ class MysqliDb
* *
* @param object new mysqlidb object * @param object new mysqlidb object
*/ */
public function copy () public function copy()
{ {
$copy = unserialize (serialize ($this)); $copy = unserialize(serialize($this));
$copy->_mysqli = $this->_mysqli; $copy->_mysqli = $this->_mysqli;
return $copy; return $copy;
} }
...@@ -1502,10 +1658,11 @@ class MysqliDb ...@@ -1502,10 +1658,11 @@ class MysqliDb
* @uses mysqli->autocommit(false) * @uses mysqli->autocommit(false)
* @uses register_shutdown_function(array($this, "_transaction_shutdown_check")) * @uses register_shutdown_function(array($this, "_transaction_shutdown_check"))
*/ */
public function startTransaction () { public function startTransaction()
$this->mysqli()->autocommit (false); {
$this->mysqli()->autocommit(false);
$this->_transaction_in_progress = true; $this->_transaction_in_progress = true;
register_shutdown_function (array ($this, "_transaction_status_check")); register_shutdown_function(array($this, "_transaction_status_check"));
} }
/** /**
...@@ -1514,10 +1671,11 @@ class MysqliDb ...@@ -1514,10 +1671,11 @@ class MysqliDb
* @uses mysqli->commit(); * @uses mysqli->commit();
* @uses mysqli->autocommit(true); * @uses mysqli->autocommit(true);
*/ */
public function commit () { public function commit()
$this->mysqli()->commit (); {
$this->mysqli()->commit();
$this->_transaction_in_progress = false; $this->_transaction_in_progress = false;
$this->mysqli()->autocommit (true); $this->mysqli()->autocommit(true);
} }
/** /**
...@@ -1526,10 +1684,11 @@ class MysqliDb ...@@ -1526,10 +1684,11 @@ class MysqliDb
* @uses mysqli->rollback(); * @uses mysqli->rollback();
* @uses mysqli->autocommit(true); * @uses mysqli->autocommit(true);
*/ */
public function rollback () { public function rollback()
$this->mysqli()->rollback (); {
$this->mysqli()->rollback();
$this->_transaction_in_progress = false; $this->_transaction_in_progress = false;
$this->mysqli()->autocommit (true); $this->mysqli()->autocommit(true);
} }
/** /**
...@@ -1538,10 +1697,12 @@ class MysqliDb ...@@ -1538,10 +1697,12 @@ class MysqliDb
* *
* @uses mysqli->rollback(); * @uses mysqli->rollback();
*/ */
public function _transaction_status_check () { public function _transaction_status_check()
if (!$this->_transaction_in_progress) {
if (!$this->_transaction_in_progress) {
return; return;
$this->rollback (); }
$this->rollback();
} }
/** /**
...@@ -1549,25 +1710,29 @@ class MysqliDb ...@@ -1549,25 +1710,29 @@ class MysqliDb
* *
* @param bool $enabled Enable execution time tracking * @param bool $enabled Enable execution time tracking
* @param string $stripPrefix Prefix to strip from the path in exec log * @param string $stripPrefix Prefix to strip from the path in exec log
**/ * */
public function setTrace ($enabled, $stripPrefix = null) { public function setTrace($enabled, $stripPrefix = null)
{
$this->traceEnabled = $enabled; $this->traceEnabled = $enabled;
$this->traceStripPrefix = $stripPrefix; $this->traceStripPrefix = $stripPrefix;
return $this; return $this;
} }
/** /**
* Get where and what function was called for query stored in MysqliDB->trace * Get where and what function was called for query stored in MysqliDB->trace
* *
* @return string with information * @return string with information
*/ */
private function _traceGetCaller () { private function _traceGetCaller()
$dd = debug_backtrace (); {
$caller = next ($dd); $dd = debug_backtrace();
while (isset ($caller) && $caller["file"] == __FILE__ )
$caller = next($dd); $caller = next($dd);
while (isset($caller) && $caller["file"] == __FILE__) {
$caller = next($dd);
}
return __CLASS__ . "->" . $caller["function"] . "() >> file \"" . return __CLASS__ . "->" . $caller["function"] . "() >> file \"" .
str_replace ($this->traceStripPrefix, '', $caller["file"] ) . "\" line #" . $caller["line"] . " " ; str_replace($this->traceStripPrefix, '', $caller["file"]) . "\" line #" . $caller["line"] . " ";
} }
/** /**
...@@ -1577,16 +1742,20 @@ class MysqliDb ...@@ -1577,16 +1742,20 @@ class MysqliDb
* *
* @returns boolean True if table exists * @returns boolean True if table exists
*/ */
public function tableExists ($tables) { public function tableExists($tables)
$tables = !is_array ($tables) ? Array ($tables) : $tables; {
$count = count ($tables); $tables = !is_array($tables) ? Array($tables) : $tables;
if ($count == 0) $count = count($tables);
if ($count == 0) {
return false; return false;
}
array_walk ($tables, function (&$value, $key) { $value = self::$prefix . $value; }); array_walk($tables, function (&$value, $key) {
$this->where ('table_schema', $this->db); $value = self::$prefix . $value;
$this->where ('table_name', $tables, 'IN'); });
$this->get ('information_schema.tables', $count); $this->where('table_schema', $this->db);
$this->where('table_name', $tables, 'IN');
$this->get('information_schema.tables', $count);
return $this->count == $count; return $this->count == $count;
} }
...@@ -1597,8 +1766,11 @@ class MysqliDb ...@@ -1597,8 +1766,11 @@ class MysqliDb
* *
* @return Array Returns an array($k => $v) if get(.."param1, param2"), array ($k => array ($v, $v)) otherwise * @return Array Returns an array($k => $v) if get(.."param1, param2"), array ($k => array ($v, $v)) otherwise
*/ */
public function map ($idField) { public function map($idField)
{
$this->_mapKey = $idField; $this->_mapKey = $idField;
return $this; return $this;
} }
} // END class }
// END class
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment