maison_alexandra/www/system-brs-core/library/cDb/cDb.php

1647 lines
61 KiB
PHP

<?php
namespace BRSystems\Core\Library\cDb;
use BRSystems\Core\Library\cDbLog\cDbLog;
use BRSystems\Core\Library\cJSON\cJSON;
use BRSystems\Core\Library\cSysConsole\cSysConsole;
use mysqli;
/**
* A PHP class to access MySQLi database with convenient methods
*
* @version 1.1
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
*
*/
class cDb{
var $mtStart; // INTERNAL: The start time, in milliseconds.
var $nbQueries; // INTERNAL: The number of executed queries.
var $lastResult; // INTERNAL: The last result resource of a query().
var $link;
public $history = array();
private $debug = false;
public $mysqli = false;
/**
* @var cDbLog $oDBLog
*/
public $oDBLog = false;
private $bDBLogSkip = false;
private $sTransactionSql = "";
private $lTransactionCount = 0;
private $lMAxTransactionCount = 0;
private $bTransactionActive = false;
const OP = 'o';
const VAL = 'v';
const OP_IN = 'IN';
const DEF_WHERE = "1 = 1";
private $oConsole;
private static $callCounter = 0;
private static $instances = array();
/**
* Class singleton constructor
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param bool|string $host - Db host domain or IP
* @param bool|string $user - Connection user
* @param bool|string $password - Connection user password
* @param bool|string $dbName - Database name
* @param bool|string $port - Connection port to use or default 3306
* @param string $sKeyAddIn - instance key add-in
*
* @return cDb $this - instance of cDb class
*/
public static function getInstance($host = false, $user = false, $password = false, $port = false, $dbName = false, $sKeyAddIn = ''){
if(!($host || $user || $password || $dbName || $port)){
$host = ($host ? $host : DB_HOST);
$user = ($user ? $user : DB_USR);
$password = ($password ? $password : DB_PWD);
$port = ($port ? $port : DB_PORT);
$dbName = ($dbName ? $dbName : (defined('COMP_DB_NAME') ? COMP_DB_NAME : DB_NAME));
}
// Create key
$key = "{$host}|{$user}|{$password}|{$port}|{$dbName}" . ($sKeyAddIn ? "|{$sKeyAddIn}" : "");
// Singleton initiation
if(empty(self::$instances[$key])){
self::$instances[$key] = new self($host, $user, $password, $port, $dbName);
}
self::$callCounter++;
return self::$instances[$key];
}
/**
* Class constructor
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param bool|string $host - Db host domain or IP
* @param bool|string $user - Connection user
* @param bool|string $password - Connection user password
* @param bool|string $dbName - Database name
* @param bool|string $port - Connection port to use or default 3306
*/
public function __construct($host = false, $user = false, $password = false, $port = false, $dbName = false){
if(!($host || $user || $password || $dbName || $port)){
$host = ($host ? $host : DB_HOST);
$user = ($user ? $user : DB_USR);
$password = ($password ? $password : DB_PWD);
$port = ($port ? $port : DB_PORT);
$dbName = ($dbName ? $dbName : (defined('COMP_DB_NAME') ? COMP_DB_NAME : DB_NAME));
}
$this->debug = (defined('DB_DEBUG') ? DB_DEBUG : false);
$this->mtStart = $this->getMicroTime();
$this->nbQueries = 0;
$this->lastResult = NULL;
// Establish connection
$this->mysqli = new mysqli($host, $user, $password, $dbName, $port);
// check connection
if($this->mysqli->connect_errno) {
printf("Connect failed: %s\n", ($this->debug ? $this->mysqli->connect_error : 'Server connexion not possible.'));
exit();
}
// Charset
$this->mysqli->set_charset("utf8");
// Setup console output object - singleton
if($this->debug){
$this->oConsole = cSysConsole::getInstance();
$this->oConsole->addOutputLine(array(
'Connection established', "host: {$host}", "user: {$user}", "password: " . preg_replace("/./im","*",$password), "db: {$dbName}"
));
}
}
/**
* Convenient method for mysqli_multi_query().
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $query - The query.
* @param bool $bBufferForFurtherUser - buffer query.
* @param bool|string $sTable - logger set table for convenience
* @param bool|string $sWhere - logger set where statement for data shift
* @return Bool result of the query.
*/
public function executeMulti($query, $bBufferForFurtherUser = false, $sTable = false, $sWhere = false){
$this->queryMulti($query, $sTable, $sWhere);
return $this->freeMulti($bBufferForFurtherUser);
}
private function queryMulti($query, $sTable = false, $sWhere = false){
$iLogId = 0;
$this->nbQueries++;
// Log query
if(!$this->bDBLogSkip && $this->oDBLog)
$iLogId = $this->oDBLog->log($query, $sTable, $sWhere);
// Exec query
$iStart = microtime(true);
$this->mysqli->multi_query($query) or $this->debugAndDie($query);
$iEnd = microtime(true);
// Update exec time
if(!$this->bDBLogSkip && $this->oDBLog && $iLogId)
$this->oDBLog->updRecordData($iLogId, array('s' => ($iEnd - $iStart)));
$this->bDBLogSkip = false;
// Save history in debug mode
if($this->debug){
$this->history[] = array(
'query' => $query,
'time' => ($iEnd - $iStart) . 's'
);
$this->oConsole->addOutputLine(array(
'SQL', "Exec time: " . ($iEnd - $iStart) . "s", "<b class='sql'>{$query}</b>"
), 'sql');
}
return false;
}
/**
* Convenient method for mysqli_query().
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $query - The query.
* @param mixed $sTable - logger set table for convenience
* @param bool|string $sWhere - logger set where statement for data shift
* @return bool|array result of the query.
*/
public function execute($query, $sTable = false, $sWhere = false){
return $this->query($query, $sTable, $sWhere);
}
/**
* Convenient method for mysqli_query().
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $query - The query.
* @param mixed $sTable - logger set table for convenience
* @param bool|string $sWhere - logger set where statement for data shift
* @return bool|array result of the query.
*/
private $iLogId = false;
public function query($query, $sTable = false, $sWhere = false)
{
// Check if transaction active
if ($this->bTransactionActive) {
$this->addTransactionSql($query);
return true;
}
$this->iLogId = 0;
$this->nbQueries++;
// Log query
if (!$this->bDBLogSkip && $this->oDBLog) {
$this->iLogId = $this->oDBLog->log($query, $sTable, $sWhere);
}
// Exec query
$iStart = microtime(true);
$this->lastResult = $this->mysqli->query($query) or $this->debugAndDie($query);
$iEnd = microtime(true);
// Update exec time
if (!$this->bDBLogSkip && $this->oDBLog && $this->iLogId)
$this->oDBLog->updRecordData($this->iLogId, array('s' => ($iEnd - $iStart)));
$this->bDBLogSkip = false;
// Save history in debug mode
if ($this->debug) {
$this->history[] = array(
'query' => $query,
'time' => ($iEnd - $iStart) . 's'
);
$this->oConsole->addOutputLine(array(
'SQL', "Exec time: " . ($iEnd - $iStart) . "s", "<b class='sql'>{$query}</b>"
), 'sql');
}
return $this->lastResult;
}
/**
* Convenient method for clearing special characters from passed variables
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param mixed $data - data
* @param bool $pHtml - preserve html structure
* @return mixed $data - clean data
*/
public function prepData($data, $pHtml = false){
if(is_array($data) && !!$data){
foreach($data as &$v)
$v = $this->prepData($v, $pHtml);
unset($v);
}else if(!!$data){
if($pHtml)
$data = $this->mysqli->escape_string(trim($data));
else
$data = $this->mysqli->escape_string(htmlspecialchars(trim($data), ENT_QUOTES, 'UTF-8'));
}
return $data;
}
/**
* Convenient constants for query table field genaration
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @category CMS
* @version 1.1
*/
const TF_TITLE = 'title';
const TF_CTITLE = 'custom_title';
const TF_SORT = 'sort';
const TF_SEARCH = 'search';
const TF_TYPE = 'type';
const TF_T_DATE = 'date';
const TF_T_DROPBOX = 'dropBox';
const TF_T_AJAX_DROPBOX = 'ajaxDropBox';
const TF_T_SELECT = 'select';
const TF_T_INPUT = 'input';
const TF_DROPBOX_DATA = 'data';
const TF_CLASS = 'class';
const TF_DB_FIELD = 'db_field';
const TF_DB_UPDATE_FIELD = 'field';
const TF_BUTTONS = 'btnset';
const TF_DEFAULT_VALUE = 'default';
const TF_S_TYPE = 'searchType'; // SEARCH ARRAY TYPE
const TF_ST_BETWEEN = 1;
const TF_ST_FROM_TILL = 2;
const TF_S_LINK_FIELD = 'field'; // SEARCH ARRAY FIELD
const TF_S_OPTIONS = 'options'; // SEARCH ARRAY OPTIONS
const TF_SO_TILL = 1;
const TF_SO_FROM = 2;
/**
* Convenient method for building search field query
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @category CMS
* @param array $data - search value data array
* @param array $fields - all available search fields
* @param bool $startWithAND - start statement with AND
* @param bool $pHtml - preserve html structure
* @return string query
* @version 1.1
*/
public function genSearchFieldQuery(&$data, &$fields, $startWithAND = true, $pHtml = false){
if(count($data) && count($fields)){
$sql = "";
// Construct query
foreach($data as $k => $v){
if($v !=='' && isset($fields[$k])){
$v = $this->prepData($v, $pHtml);
switch ($fields[$k]['type']) {
case self::TF_T_INPUT :
if(!empty($fields[$k][self::TF_DB_FIELD])){
if(!is_array($fields[$k][self::TF_DB_FIELD])){
$fields[$k][self::TF_DB_FIELD] = array('0' => $fields[$k][self::TF_DB_FIELD]);
}
$for = "";
$flink = (!empty($fields[$k]['db_link']) ? $fields[$k]['db_link'] : 'AND');
$operation = (!empty($fields[$k]['operation']) ? $fields[$k]['operation'] : '');
// Search whole words
$bWholeWord = false;
$vTypes = array('\'', '"');
if(in_array(substr($v, 0, 1), $vTypes) && in_array(substr($v, -1), $vTypes)){
$bWholeWord = true;
$v = substr($v, 1, strlen($v)-2);
}
foreach($fields[$k][self::TF_DB_FIELD] as $db_f){
if($operation){
$for .= "{$flink} {$db_f} {$operation} '{$v}' \n";
}elseif($bWholeWord){
$for .= "{$flink} " . $db_f . " LIKE '{$v}' \n";
}else{
$for .= "{$flink} {$db_f} LIKE '%{$v}%' \n";
}
}
$sql .= "AND (" . substr($for, strlen($flink)) . ")";
}
break;
case self::TF_T_SELECT:
if(!empty($fields[$k]['data'][$v][self::TF_DB_FIELD])){
$sql .= "AND {$fields[$k]['data'][$v][self::TF_DB_FIELD]} = '{$v}' \n";
}else if(!empty($fields[$k][self::TF_DB_FIELD])){
$sql .= "AND {$fields[$k][self::TF_DB_FIELD]} LIKE '{$v}' \n";
}
break;
case self::TF_T_DROPBOX:
if(!empty($fields[$k]['data'][$v])){
$sql .= "AND {$fields[$k][self::TF_DB_FIELD]} = '{$v}' \n";
}
break;
case self::TF_T_AJAX_DROPBOX:
if(!is_array($fields[$k][self::TF_DB_FIELD]))
$fields[$k][self::TF_DB_FIELD] = array('0' => $fields[$k][self::TF_DB_FIELD]);
$for = '';
$flink = (!empty($fields[$k]['db_link']) ? $fields[$k]['db_link'] : 'AND');
$likePattern = (!empty($fields[$k]['db_like_pattern']) ? $fields[$k]['db_like_pattern'] : ''); // LIKE '%__VALUE__%' pattern is --> %__VALUE__%
$operation = (!empty($fields[$k]['operation']) ? $fields[$k]['operation'] : '');
foreach($fields[$k][self::TF_DB_FIELD] as $db_f){
if($operation){
$for .= "{$flink} {$db_f} {$operation} '{$v}' \n";
}else{
$for .= "{$flink} {$db_f} LIKE " . (strlen($likePattern) ? "'" . str_replace('__VALUE__',$v, $likePattern) . "'" : "'%{$v}%'") . " \n";
}
}
$sql .= "AND (" . substr($for, strlen($flink)) . ")";
break;
case self::TF_T_DATE:
$s = $fields[$k];
if(!!$s[self::TF_SEARCH] && is_array($s[self::TF_SEARCH]))
$s = &$s[self::TF_SEARCH];
// Check if db fields exists & data fields exists
if(!!$s && !empty($s[self::TF_DB_FIELD]) && !empty($s[self::TF_S_LINK_FIELD]) && isset($data[$s[self::TF_S_LINK_FIELD]])){
$sLinkFieldKey = $s[self::TF_S_LINK_FIELD];
$sLinkFieldValue = $data[$sLinkFieldKey];
switch($s[self::TF_S_TYPE]){
case self::TF_ST_BETWEEN:
$d1 = strtotime(str_replace("/", "-", $v));
$d2 = strtotime(str_replace("/", "-", $sLinkFieldValue));
if($d1 > $d2){
$t = $d2;
$d2 = $d1;
$d1 = $t;
}
// Set oldest date closest border
$d2 = strtotime(date("d-m-Y", $d2) . " 23:59:59");
//pr(date('d/m/Y H:i:s', $d1),date('d/m/Y h:i:s', $d2));
unset($data[$sLinkFieldKey]); // Remove linked 2nd field
$sql .= "AND ({$s[self::TF_DB_FIELD]} BETWEEN {$d1} AND {$d2}) \n";
break;
case self::TF_ST_FROM_TILL:
if(isset($s[self::TF_S_OPTIONS]) && $s[self::TF_S_OPTIONS] == self::TF_SO_FROM){
$d1 = strtotime(str_replace("/", "-", $v));
$d2 = strtotime(str_replace("/", "-", $sLinkFieldValue));
}else{
$d1 = strtotime(str_replace("/", "-", $sLinkFieldValue));
$d2 = strtotime(str_replace("/", "-", $v));
}
if($d1 > 0 && $d2 > 0){
if($d1 > $d2){
$t = $d2;
$d2 = $d1;
$d1 = $t;
}
}
// Set oldest date closest border
if($d2 > 0) $d2 = strtotime(date("d-m-Y", $d2) . " 23:59:59");
//pr(date('d/m/Y H:i:s', $d1) . "<-- \n",date('d/m/Y h:i:s', $d2) . "<-- \n");
unset($data[$sLinkFieldKey]); // Remove linked 2nd field
if($d1 > 0 && $d2 > 0)
$sql .= "AND ({$s[self::TF_DB_FIELD]} >= {$d1} OR {$fields[$s[self::TF_S_LINK_FIELD]][self::TF_DB_FIELD]} >= {$d1}) AND ({$fields[$s[self::TF_S_LINK_FIELD]][self::TF_DB_FIELD]} <= {$d2} OR {$s[self::TF_DB_FIELD]} <= {$d2})";
elseif($d1 > 0 && $s[self::TF_S_OPTIONS] == self::TF_SO_FROM)
$sql .= "AND ({$s[self::TF_DB_FIELD]} >= {$d1} OR {$fields[$s[self::TF_S_LINK_FIELD]][self::TF_DB_FIELD]} >= {$d1}) ";
elseif($d2 > 0 && $s[self::TF_S_OPTIONS] == self::TF_SO_TILL)
$sql .= "AND ({$fields[$s[self::TF_S_LINK_FIELD]][self::TF_DB_FIELD]} <= {$d2} OR {$s[self::TF_DB_FIELD]} <= {$d2})";
break;
}
}
break;
}
}
}
return $startWithAND ? ' ' . $sql : substr($sql, 3);
}
}
/**
* Convenient method for building sort by field query
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @category CMS
* @param string $sortBy - field key sort by
* @param bool $sortWay - field sort order true / false
* @param array $fieldData - fields available in table
* @return string query
* @version 1.1
*/
public function genOrderByQuery($sortBy, $sortWay, $fieldData){
if($sortBy && isset($fieldData[$sortBy][self::TF_DB_FIELD]) && !!$fieldData[$sortBy][self::TF_DB_FIELD]){
$sql = "";
$sortWay = ($sortWay ? ' ASC ' : ' DESC ');
if(!is_array($fieldData[$sortBy][self::TF_DB_FIELD]))
$fieldData[$sortBy][self::TF_DB_FIELD] = array($fieldData[$sortBy][self::TF_DB_FIELD]);
foreach($fieldData[$sortBy][self::TF_DB_FIELD] as $dbField){
$sql .= ", {$dbField} {$sortWay}";
}
return substr($sql, 1);
}
return false;
}
/**
* Convenient method for fetching one
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
* @param instance $result - The ressource returned by query()
* @return bool true / false or array with data
*/
public function getOne($vPrepCfg = false, $result = NULL){
if ($result == NULL)
$result = $this->lastResult;
if($result && $result->num_rows){
$row = $result->fetch_assoc();
$field = array_shift($row);
unset($row);
}else{
$field = false;
}
$this->free();
return $this->prepRespData($field, $vPrepCfg);
}
/**
* Convenient method for fetching row
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
* @param instance $result - The resource returned by query()
* @return mixed true / false / array with data
*/
public function getRow($vPrepCfg = false, $result = NULL){
if($result == NULL)
$result = $this->lastResult;
if($result == NULL || $result->num_rows < 1){
return NULL;
}else{
$row = $result->fetch_assoc();
$result->free();
return $this->prepRespData($row, $vPrepCfg);
}
}
/**
* Convenient method for fetching an array
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
* @param instance $result - The resource returned by query()
* @return bool|array true / false or array with data
*/
public function getArray($vPrepCfg = false, $result = NULL){
if($result == NULL)
$result = $this->lastResult;
if($result == NULL || $result->num_rows < 1){
return NULL;
}else{
$arr = array();
while($row = $result->fetch_assoc())
$arr[] = $row;
unset($row);
$this->free($result);
return $this->prepRespData($arr, $vPrepCfg);
}
}
/**
* Convenient method for fetching an field based array
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $field - field by which to group
* @param string|bool $subArrField - sub-field by which to group
* @param bool $simpleRewrite - simply rewrite each similar id
* @param string|bool $fieldKey - resource field to group by
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
* @param instance $result - The resource returned by query()
* @return bool|array true / false or array with data
*/
public function getFieldBasedArray($field, $subArrField = false, $simpleRewrite = true, $fieldKey = false, $vPrepCfg = false, $result = NULL){
if ($result == NULL)
$result = $this->lastResult;
if ($result == NULL || $result->num_rows < 1)
return NULL;
else {
$arr = array();
while ($row = $result->fetch_assoc()) {
if(!$subArrField){
if($simpleRewrite){
$arr[$row[$field]] = ($fieldKey ? @$row[$fieldKey] : $row);
}elseif($fieldKey){
$arr[$row[$field]][] = @$row[$fieldKey];
}else{
$arr[$row[$field]][] = $row;
}
}else{
if($simpleRewrite){
$arr[$row[$field]][$row[$subArrField]] = ($fieldKey ? @$row[$fieldKey] : $row);
}elseif($fieldKey){
$arr[$row[$field]][$row[$subArrField]][] = @$row[$fieldKey];
}else{
$arr[$row[$field]][$row[$subArrField]][] = $row;
}
}
}
unset($row);
$this->free($result);
return $this->prepRespData($arr, $vPrepCfg);
}
}
/**
* Convenient method for fetching an field based array NEW
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $key - field by which to group
* @param string|bool $subKey - sub-field by which to group
* @param array|string|bool $fields - resource field to select
* @param bool $simpleRewrite - simply rewrite each similar id
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
* @param instance $result - The resource returned by query()
* @return bool|array true / false or array with data
*/
public function getFieldBasedArrayFields($key, $subKey = false, $fields = false, $simpleRewrite = true, $vPrepCfg = false, $result = NULL){
if ($result == NULL)
$result = $this->lastResult;
if ($result == NULL || $result->num_rows < 1)
return NULL;
else {
$arr = array();
while ($row = $result->fetch_assoc()) {
if(!$subKey){
if($simpleRewrite){
if($simpleRewrite === true)
$arr[$row[$key]] = (!!$fields && is_array($fields) ? array_intersect_key($row, array_flip($fields)) : (isset($row[$fields]) ? $row[$fields] : $row));
else
$arr[$row[$key]][$row[$simpleRewrite]] = (!!$fields && is_array($fields) ? array_intersect_key($row, array_flip($fields)) : (isset($row[$fields]) ? $row[$fields] : $row));
}elseif(!!$fields && is_array($fields)){
$arr[$row[$key]][] = array_intersect_key($row, array_flip($fields));
}else{
$arr[$row[$key]][] = (isset($row[$fields]) ? $row[$fields] : $row);
}
}else{
if($simpleRewrite){
if($simpleRewrite === true)
$arr[$row[$key]][$row[$subKey]] = (!!$fields && is_array($fields) ? array_intersect_key($row, array_flip($fields)) : (isset($row[$fields]) ? $row[$fields] : $row));
else
$arr[$row[$key]][$row[$subKey]][$row[$simpleRewrite]] = (!!$fields && is_array($fields) ? array_intersect_key($row, array_flip($fields)) : (isset($row[$fields]) ? $row[$fields] : $row));
}elseif(!!$fields && is_array($fields)){
$arr[$row[$key]][$row[$subKey]][] = array_intersect_key($row, array_flip($fields));
}else{
$arr[$row[$key]][$row[$subKey]][] = (isset($row[$fields]) ? $row[$fields] : $row);
}
}
}
unset($row);
$this->free($result);
return $this->prepRespData($arr, $vPrepCfg);
}
}
/**
* Convenient method for fetching an field based array advanced & optimized
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string|array $keys - field/s by which to group
* @param array|string|bool $fields - resource field to select
* @param bool $simpleRewrite - simply rewrite each similar id
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
* @param instance $result - The resource returned by query()
* @return bool|array true / false or array with data
*/
public function getFieldBasedArrayFieldsAdv($keys, $fields = false, $simpleRewrite = true, $vPrepCfg = false, $result = NULL){
$bArray = false;
$keys = (is_array($keys) ? $keys : array($keys));
if(!!$fields && is_array($fields)){
$bArray = true;
$flipArray = array_flip($fields);
}
if ($result == NULL)
$result = $this->lastResult;
if ($result == NULL || $result->num_rows < 1)
return NULL;
else {
$arr = array();
while ($row = $result->fetch_assoc()){
$ref = &$arr;
foreach($keys as $key){
if(!isset($ref[$row[$key]]))
$ref[$row[$key]] = array();
$ref = &$ref[$row[$key]];
}
if($simpleRewrite){
$ref = ($bArray ? array_intersect_key($row, $flipArray) : ($fields ? @$row[$fields] : $row));
}elseif($bArray){
$ref[] = array_intersect_key($row, $flipArray);
}else{
$ref[] = ($fields ? @$row[$fields] : $row);
}
}
unset($row);
$this->free($result);
return $this->prepRespData($arr, $vPrepCfg);
}
}
/**
* Convenient method for manipulating globally data
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param mixed $vData - data to prepare
* @param mixed $vPrepData - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
* @return mixed manipulated data
*/
const PREP_DATA_ENCODE = 'bPrepData_encode';
const PREP_DATA_DECODE = 'bPrepData_decode';
const PREP_DATA_DECODE_ORIGINAL = 'bPrepData_decode_original';
public function prepRespData($vData = array(), $vPrepData){
if($vPrepData){
if($vPrepData === true)
$vPrepData = array('type' => self::PREP_DATA_ENCODE);
if(is_string($vPrepData))
$vPrepData = array('type' => $vPrepData);
// Data manipulations
if(!!$vData && !!$vPrepData){
switch($vPrepData['type']){
case self::PREP_DATA_ENCODE;
$vData = $this->prepData($vData);
break;
case self::PREP_DATA_DECODE;
$vData = prepForDisplayHtml($vData);
break;
case self::PREP_DATA_DECODE_ORIGINAL;
$vData = prepForOriginalHtml($vData);
break;
}
}
}
return $vData;
}
/**
* Convenient method for fetching key => value field based array.
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $keyF - result array field key
* @param string $valF - result array filed value key
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
* @param instance $result - The resource returned by query()
* @return array - containing select data
*/
public function getKeyValBasedArray($keyF, $valF, $vPrepCfg = false, $result = NULL){
if ($result == NULL)
$result = $this->lastResult;
if ($result == NULL || $result->num_rows < 1)
return NULL;
else {
$arr = array();
while ($row = $result->fetch_assoc()) {
$arr[@$row[$keyF]] = @$row[$valF];
}
unset($row);
$this->free($result);
return $this->prepRespData($arr, $vPrepCfg);
}
}
/**
* Convenient method for fetching data & return grouped.
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $gr_field - group field
* @param string $empty_key - empty other gr field
* @param mixed $vPrepCfg - encode/decode data for display - prepare data if saved in raw html format, or if encoded - decode
* @param instance $result - The resource returned by query()
* @return bool true / false or array with data
*/
public function getGroupArray($gr_field, $empty_key = 'Others', $vPrepCfg = false, $result = NULL){
if ($result == NULL)
$result = $this->lastResult;
if ($result == NULL || $result->num_rows < 1)
return NULL;
else {
$arr = array();
$curr_field = '';
while ($row = $result->fetch_assoc()) {
if($curr_field != $row[$gr_field]){
$curr_field = $row[$gr_field];
}
if(!$curr_field){
$curr_field = $empty_key;
}
$arr[$curr_field][] = $row;
}
unset($row);
$this->free($result);
return $this->prepRespData($arr, $vPrepCfg);
}
}
/**
* Convenient method for getting last select found row count
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param bool $debug - indicates debug mode
* @return cleared object value
*/
public function getSelectedRecordsCount($debug = false){
$this->bDBLogSkip = true;
$this->query("SELECT FOUND_ROWS()", $debug);
return $this->getOne();
}
/**
* Convenient method for setting logger class
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param mixed $loggerObject - logger class reference
* @returns void
*/
public function setLogger(&$loggerObject){
if(is_callable(array($loggerObject, 'log')))
$this->oDBLog = $loggerObject;
}
/**
* Convenient method for initializing logger class
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param int $iUserId - user id to link to log
* @returns void
*/
public function initLogger($iUserId = 0){
if($iUserId) $this->oDBLog = new cDbLog($iUserId);
}
/**
* Convenient method for mysqli_free_result()
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param instance $result - The resource returned by query()
* @return bool true / false or array with data
*/
public function free($result = NULL){
if ($result == NULL)
$result = $this->lastResult;
return ($result && is_callable(array($result, 'free'), true) ? $result->free() : false);
}
private function freeMulti($bBuffer = false){
// flush multi_queries
if(!$bBuffer){
while ($this->mysqli->more_results() && $this->mysqli->next_result()){
if (!$this->mysqli->more_results()) break;
}
}else{
do{
/* store first result set */
if($result = $this->mysqli->store_result()) {
/* while($row = $result->fetch_row()) {
// printf("%s\n", $row[0]);
}*/
$result->free_result();
}
/* print divider */
//if($this->mysqli->more_results()) {
// printf("-----------------\n");
// }
}while($this->mysqli->next_result());
}
return true;
}
/**
* Convenient method for getting id of the very last inserted row.
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @return int $rowId - the id of the very last inserted row (in any table).
*/
function lastInsertedId(){
return $this->mysqli->insert_id;
}
/**
* Convenient method for getting affected row count
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @return int $rowId - the id of the very last inserted row (in any table).
*/
function affectedRowCount(){
return $this->mysqli->affected_rows;
}
/**
* Function to get the number of queries executed from the begin of this object
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @return int $count - The number of queries executed
*/
function getQueriesCount(){
return $this->nbQueries;
}
/**
* Function to get current time.
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @return int $time - current time in seconds with microseconds (in float format).
*/
function getMicroTime(){
list($msec, $sec) = explode(' ', microtime());
return floor($sec / 1000) + $msec;
}
/**
* Function to get execution time since beginning of object creation.
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @return int $time - execution time in seconds.
*/
function getExecTime(){
return round(($this->getMicroTime() - $this->mtStart) * 1000) / 1000;
}
/*****************************************************************************************************************
* DEBUG FUNCTIONS
*
* Internal function to debug when MySQL encountered an error
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $query The SQL query to echo before dying.
*/
private function debugAndDie($query){
if($this->debug){
$this->debugQuery($query, "Error");
if(POST_REQ){
die("\n\n" . $this->mysqli->error);
}else{
die("<p style='margin: 14px;'>" . $this->mysqli->error . "</p></div>");
}
}
}
private function debugQuery($query, $reason = "Debug"){
$color = ($reason == "Error" ? "red" : "orange");
if(POST_REQ){
echo "$reason\n\n" .
"$query";
}else{
echo "<div style='border: solid $color 1px; margin: 2px;font-family: arial;line-height: 22px;'>" .
"<p style='margin: 0 0 2px 0; padding: 0;background-color: #DDDDFF;text-shadow: -1px 1px 0 rgba(255, 255, 255, 0.39);color: #1A1A1A;'>" .
"<strong style='padding: 0 8px; background-color: {$color}; color: white;display: inline-block;letter-spacing:2px;'>$reason:</strong> " .
"<span style='font-family: monospace;display: block;margin: 0 100px;padding-bottom: 18px;'>" . ($this->getFormattedSQL($query)) . "</span></p>";
}
}
private function getFormattedSQL($sql_raw){
if( empty($sql_raw) || !is_string($sql_raw) )
{
return false;
}
$sql_reserved_all = array (
'ACCESSIBLE', 'ACTION', 'ADD', 'AFTER', 'AGAINST', 'AGGREGATE', 'ALGORITHM', 'ALL', 'ALTER', 'ANALYSE', 'ANALYZE', 'AND', 'AS', 'ASC',
'AUTOCOMMIT', 'AUTO_INCREMENT', 'AVG_ROW_LENGTH', 'BACKUP', 'BEGIN', 'BETWEEN', 'BINLOG', 'BOTH', 'BY', 'CASCADE', 'CASE', 'CHANGE', 'CHANGED',
'CHARSET', 'CHECK', 'CHECKSUM', 'COLLATE', 'COLLATION', 'COLUMN', 'COLUMNS', 'COMMENT', 'COMMIT', 'COMMITTED', 'COMPRESSED', 'CONCURRENT',
'CONSTRAINT', 'CONTAINS', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT_TIMESTAMP', 'DATABASE', 'DATABASES', 'DAY', 'DAY_HOUR', 'DAY_MINUTE',
'DAY_SECOND', 'DEFINER', 'DELAYED', 'DELAY_KEY_WRITE', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV',
'DO', 'DROP', 'DUMPFILE', 'DUPLICATE', 'DYNAMIC', 'ELSE', 'ENCLOSED', 'END', 'ENGINE', 'ENGINES', 'ESCAPE', 'ESCAPED', 'EVENTS', 'EXECUTE',
'EXISTS', 'EXPLAIN', 'EXTENDED', 'FAST', 'FIELDS', 'FILE', 'FIRST', 'FIXED', 'FLUSH', 'FOR', 'FORCE', 'FOREIGN', 'FROM', 'FULL', 'FULLTEXT',
'FUNCTION', 'GEMINI', 'GEMINI_SPIN_RETRIES', 'GLOBAL', 'GRANT', 'GRANTS', 'GROUP', 'HAVING', 'HEAP', 'HIGH_PRIORITY', 'HOSTS', 'HOUR', 'HOUR_MINUTE',
'HOUR_SECOND', 'IDENTIFIED', 'IF', 'IGNORE', 'IN', 'INDEX', 'INDEXES', 'INFILE', 'INNER', 'INSERT', 'INSERT_ID', 'INSERT_METHOD', 'INTERVAL',
'INTO', 'INVOKER', 'IS', 'ISOLATION', 'JOIN', 'KEY', 'KEYS', 'KILL', 'LAST_INSERT_ID', 'LEADING', 'LEFT', 'LEVEL', 'LIKE', 'LIMIT', 'LINEAR',
'LINES', 'LOAD', 'LOCAL', 'LOCK', 'LOCKS', 'LOGS', 'LOW_PRIORITY', 'MARIA', 'MASTER', 'MASTER_CONNECT_RETRY', 'MASTER_HOST', 'MASTER_LOG_FILE',
'MASTER_LOG_POS', 'MASTER_PASSWORD', 'MASTER_PORT', 'MASTER_USER', 'MATCH', 'MAX_CONNECTIONS_PER_HOUR', 'MAX_QUERIES_PER_HOUR',
'MAX_ROWS', 'MAX_UPDATES_PER_HOUR', 'MAX_USER_CONNECTIONS', 'MEDIUM', 'MERGE', 'MINUTE', 'MINUTE_SECOND', 'MIN_ROWS', 'MODE', 'MODIFY',
'MONTH', 'MRG_MYISAM', 'MYISAM', 'NAMES', 'NATURAL', 'NOT', 'NULL', 'OFFSET', 'ON', 'OPEN', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OR',
'ORDER', 'OUTER', 'OUTFILE', 'PACK_KEYS', 'PAGE', 'PARTIAL', 'PARTITION', 'PARTITIONS', 'PASSWORD', 'PRIMARY', 'PRIVILEGES', 'PROCEDURE',
'PROCESS', 'PROCESSLIST', 'PURGE', 'QUICK', 'RAID0', 'RAID_CHUNKS', 'RAID_CHUNKSIZE', 'RAID_TYPE', 'RANGE', 'READ', 'READ_ONLY',
'READ_WRITE', 'REFERENCES', 'REGEXP', 'RELOAD', 'RENAME', 'REPAIR', 'REPEATABLE', 'REPLACE', 'REPLICATION', 'RESET', 'RESTORE', 'RESTRICT',
'RETURN', 'RETURNS', 'REVOKE', 'RIGHT', 'RLIKE', 'ROLLBACK', 'ROW', 'ROWS', 'ROW_FORMAT', 'SECOND', 'SECURITY', 'SELECT', 'SEPARATOR',
'SERIALIZABLE', 'SESSION', 'SET', 'SHARE', 'SHOW', 'SHUTDOWN', 'SLAVE', 'SONAME', 'SOUNDS', 'SQL', 'SQL_AUTO_IS_NULL', 'SQL_BIG_RESULT',
'SQL_BIG_SELECTS', 'SQL_BIG_TABLES', 'SQL_BUFFER_RESULT', 'SQL_CACHE', 'SQL_CALC_FOUND_ROWS', 'SQL_LOG_BIN', 'SQL_LOG_OFF',
'SQL_LOG_UPDATE', 'SQL_LOW_PRIORITY_UPDATES', 'SQL_MAX_JOIN_SIZE', 'SQL_NO_CACHE', 'SQL_QUOTE_SHOW_CREATE', 'SQL_SAFE_UPDATES',
'SQL_SELECT_LIMIT', 'SQL_SLAVE_SKIP_COUNTER', 'SQL_SMALL_RESULT', 'SQL_WARNINGS', 'START', 'STARTING', 'STATUS', 'STOP', 'STORAGE',
'STRAIGHT_JOIN', 'STRING', 'STRIPED', 'SUPER', 'TABLE', 'TABLES', 'TEMPORARY', 'TERMINATED', 'THEN', 'TO', 'TRAILING', 'TRANSACTIONAL',
'TRUNCATE', 'TYPE', 'TYPES', 'UNCOMMITTED', 'UNION', 'UNIQUE', 'UNLOCK', 'UPDATE', 'USAGE', 'USE', 'USING', 'VALUES', 'VARIABLES',
'VIEW', 'WHEN', 'WHERE', 'WITH', 'WORK', 'WRITE', 'XOR', 'YEAR_MONTH'
);
$sql_break_before = array('AND');
$sql_break_after = array('SELECT', 'ON', 'WHERE');
$sql_set_in_bold = array('ON', 'AS', 'AND');
$sql_skip_reserved_words = array('AS', 'ON', 'USING', 'AND');
$sql_special_reserved_words = array('(', ')');
$sql_raw = str_replace("\n", " ", $sql_raw);
$sql_formatted = "";
$prev_word = "";
$word = "";
$tab = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
for( $i=0, $j = strlen($sql_raw); $i < $j; $i++ )
{
$word .= $sql_raw[$i];
$word_trimmed = trim($word);
if($sql_raw[$i] == " " || in_array($sql_raw[$i], $sql_special_reserved_words))
{
$word_trimmed = trim($word);
$trimmed_special = false;
if( in_array($sql_raw[$i], $sql_special_reserved_words) )
{
$word_trimmed = substr($word_trimmed, 0, -1);
$trimmed_special = true;
}
$word_trimmed = strtoupper($word_trimmed);
if(in_array($word_trimmed, $sql_reserved_all) && !in_array($word_trimmed, $sql_skip_reserved_words)){
if(in_array($prev_word, $sql_reserved_all)){
$sql_formatted .= '<b>'.strtoupper(trim($word)).'</b>'.'&nbsp;';
}else{
$sql_formatted .= '<br/>&nbsp;';
$sql_formatted .= '<b>'.strtoupper(trim($word)).'</b>'.'&nbsp;';
}
$prev_word = $word_trimmed;
$word = "";
}else{
if(trim($word)){
// Add line breaks for subfields
if(in_array($word_trimmed, $sql_break_before)){
$sql_formatted .= "<br/>{$tab}";
}
if(substr($prev_word, strlen($prev_word)-1, 1) == ',' || in_array($prev_word, $sql_break_after)){
$sql_formatted .= "<br/>{$tab}";
}
// Set words in bold
if(in_array($word_trimmed, $sql_set_in_bold)){
$sql_formatted .= '<b>' . trim($word).'</b>&nbsp;';
}else{
$sql_formatted .= trim($word).'&nbsp;';
}
$prev_word = $word_trimmed;
$word = "";
}
}
}
}
$sql_formatted .= trim($word);
return $sql_formatted;
}
/*****************************************************************************************************************
* FAST QUERY REQUEST FUNCTIONS
*
*
* Function to build query based on passed data
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $table - table name
* @param array|bool $fields - fields to select
* @param array|bool $where - where clause
* @param array|bool $order - order clause
* @return bool true / false
*/
private function buildQuery($table, $fields = false, $where = false, $order = false){
if (is_array($fields)) {
$fields = implode(',', $fields);
} else {
$fields = "*";
}
$where = $this->buildWhereStatement($where);
if (is_array($order)) {
$d = '';
foreach($order as $k => $v){
$d .= ", " . $k . " " . $this->prepData($v) . " ";
}
$order = substr($d, 1);
} else {
$order = " 1 ";
}
return "
SELECT {$fields}
FROM {$table}
WHERE {$where}
ORDER BY {$order}";
}
/**
* Convenient function for building where statement for query
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param array|bool $where - where clause
* @return string - built query
*/
public function buildWhereStatement($where = false){
if (!!$where && is_array($where)) {
$d = '';
foreach($where as $k => $v){
if(is_array($v)){
if(!empty($v[self::OP])){
if(is_array($v[self::VAL]))
$d .= "AND `" . $k . "` {$v[self::OP]} ('" . implode("','", $this->prepData($v[self::VAL])) . "') ";
else
$d .= "AND `" . $k . "` {$v[self::OP]} '" . $this->prepData($v[self::VAL]) . "' ";
}else
$d .= "AND `" . $k . "` IN ('" . implode("','", $this->prepData($v)) . "') ";
}else{
$d .= "AND `" . $k . "` = '" . $this->prepData($v) . "' ";
}
}
$where = substr($d, 3);
} else {
$where = self::DEF_WHERE;
}
return $where;
}
/**
* Convenient function for loading row data from db connection by passing query data
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $table - table name
* @param array|bool $fields - fields to select
* @param array|bool $where - where clause
* @param array|bool $order - order clause
* @return bool|array true / false
*/
public function _querySelectRow($table, $fields = false, $where = false, $order = false){
if(!!$table){
// Build query
$query = $this->buildQuery($table, $fields, $where, $order);
$this->query($query, $table);
return $this->getRow();
}else{
return null;
}
}
/**
* Convenient function for loading array of data from db connection by passing query data
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $table - table name
* @param array|bool $fields - fields to select
* @param array|bool $where - where clause
* @param array|bool $order - order clause
* @param bool $debug - debug parameter
* @param bool $return - return parameter
* @return bool|array true / false
*/
public function _querySelect($table, $fields = false, $where = false, $order = false, $debug = false, $return = true){
if(!!$table){
// Build query
$query = $this->buildQuery($table, $fields, $where, $order);
$this->query($query, $table);
if($return)
return $this->getArray();
}else{
return null;
}
}
/**
* Convenient function for loading field from db connection by passing query data
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $table - table name
* @param array|bool $fields - fields to select
* @param array|bool $where - where clause
* @param array|bool $order - order clause
* @return bool true / false
*/
public function _querySelectOne($table, $fields = false, $where = false, $order = false){
if(!!$table){
// Build query
$query = $this->buildQuery($table, $fields, $where, $order);
$this->query($query, $table);
return $this->getOne();
}else{
return null;
}
}
/**
* Convenient method for truncate table
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $table - table to truncate
* @param bool $debug - indicates debug mode
* @return mixed - cleared object value
*/
public function _truncate($table ,$debug = false){
$query = "TRUNCATE TABLE {$table}";
$this->query($query, $table);
return $this->getOne();
}
/**
* Function to exec insert
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $table - table name
* @param array $data - fields to insert with key to field structure
* @param bool $debug - indicates debug mode
* @param bool $pHTML - preserver html
* @return int - last inserted id on exec else false
*/
public function _queryInsert($table, $data = array(), $debug = false, $pHTML = false){
if (count($data)) {
$sFields = '';
$sValues = '';
// Escaping insert values
foreach ($data as $k => $v) {
$sFields .= ",`" . $k . "`";
$sValues .= ",'" . $this->prepData($v, $pHTML) . "'";
}
// Create query
$query = 'INSERT INTO ' . $table . '(' . substr($sFields,1) . ') VALUES (' . substr($sValues, 1) . ')';
// Exec query
if($this->execute($query, $table)) {
$vResult = $this->getMultiInsertRowIds();
return array_pop($vResult);
}
} else {
return false;
}
return false;
}
/**
* Function to exec insert with data array
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $table - table name
* @param array $rowData - fields to insert with key to field structure
* @param bool $debug - indicates debug mode
* @param bool $pHTML - preserver html
* @return array|bool - array with ids
*/
public function _queryInsertArray($table, $rowData = array(), $debug = false, $pHTML = false){
if (count($rowData)) {
$sFields = '';
$sValues = '';
// Escaping insert values
$first_row = true;
foreach($rowData as $v) {
if(count($v)){
$sRow ='';
foreach($v as $kk => $vv) {
if($first_row){
$sFields .= ",`" . $kk . "`";
}
$sRow .= ",'" . $this->prepData($vv, $pHTML) . "'";
}
$sValues .= ',(' . substr($sRow, 1) . ')';
$first_row = false;
}
}
// Create query
$query = 'INSERT INTO ' . $table . '(' . substr($sFields,1) . ') VALUES ' . substr($sValues, 1) . ';';
// Exec query
if($this->execute($query, $table)){
return $this->getMultiInsertRowIds(count($rowData));
}
} else {
return false;
}
return false;
}
/**
* Function to get query || multi-query inserted ids
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param int $iInsertRowsCount - from insert row count
* @return array - inserted id on query's
*/
private function getMultiInsertRowIds($iInsertRowsCount = 0){
$vReturnD = array();
// Check upon inserted rows what to return
if($iInsertRowsCount == $this->mysqli->affected_rows){
//Generate id array
$i = 0;
while($i < $iInsertRowsCount) {
$vReturnD[] = $this->mysqli->insert_id + $i++;
}
}else{
$vReturnD[] = $this->mysqli->insert_id;
while($this->mysqli->more_results()){
$this->mysqli->next_result();
$vReturnD[] = $this->mysqli->insert_id;
}
}
// Update log affected ids
if(!$this->bDBLogSkip && $this->oDBLog && $this->iLogId){
$this->oDBLog->updRecordData($this->iLogId, array(
'json_data' => cJSON::encode(array('id' => $vReturnD))
));
}
return $vReturnD;
}
/**
* Function to exec delete
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $table - table name
* @param array $where - fields to match before delete
* @param bool $debug - indicates debug mode
* @return bool - last inserted id on exec else false
*/
public function _queryDelete($table, $where = array(), $debug = false): bool
{
if (count($where)) {
// Create where clause
if (is_array($where) && count($where)) {
$d = '';
foreach($where as $k => $v){
if(is_array($v)){
if(!empty($v[self::OP]))
$d .= "AND `" . $k . "` {$v[self::OP]} '" . $this->prepData($v[self::VAL]) . "' ";
else
$d .= "AND `" . $k . "` IN ('" . implode("','", $this->prepData($v)) . "') ";
}else
$d .= "AND `" . $k . "` = '" . $this->prepData($v) . "' ";
}
$sWhere = substr($d, 3);
// Create query
$query = 'DELETE FROM ' . $table . ' WHERE ' . $sWhere;
if($this->execute($query, $table, $sWhere)){
return true;
}
}
} else {
return false;
}
return false;
}
/**
* Function to exec update
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $table - table name
* @param array $data - fields to insert with key to field structure
* @param array|bool $where - fields to match the update
* @param bool $pHTML - indicates to preserve HTML
* @param bool $debug - indicates debug mode
* @return bool - last inserted id on exec else false
*/
public function _queryUpdate($table, $data = array(), $where = false, $pHTML = false, $debug = false): bool
{
$array = array();
if (count($data)) {
$sFields = '';
$sValues = '';
// Escaping update values
foreach ($data as $k => $v)
$sFields .= ",`" . $k . "` = '" . $this->prepData($v, $pHTML) . "'";
// Create where clause
if (is_array($where)){
$d = '';
foreach($where as $k => $v){
if(is_array($v) && count($v)){
if(!empty($v[self::OP]))
$d .= "AND `" . $k . "` {$v[self::OP]} '" . $this->prepData($v[self::VAL], $pHTML) . "' ";
else
$d .= "AND `" . $k . "` IN ('" . implode("','", $this->prepData($v, $pHTML)) . "')";
}else{
$d .= "AND `" . $k . "` = '" . $this->prepData($v, $pHTML) . "'";
}
}
$sWhere = substr($d, 3);
} else {
$sWhere = self::DEF_WHERE;
}
// Create query
$query = 'UPDATE ' . $table . ' SET ' . substr($sFields,1) . ' WHERE ' . $sWhere;
if($this->execute($query, $table, $sWhere)){
return true;
}
} else {
return false;
}
return false;
}
/**
* Function to exec update multi with case
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $table - table name
* @param array $data - fields to insert with key to field structure
* @param string $sKey - main key to look in $data array
* @param array $where - additional where condition
* @param boolean $pHTML - indicates to preserve HTML
* @return boolean - true if query executed else false;
*/
public function _queryUpdateMulti($table, $data = array(), $sKey, $where = array(), $pHTML = false){
$bIsString = false;
if (count($data) && $sKey) {
$sKey = $this->prepData($sKey, $pHTML);
$data = $this->prepData($data, $pHTML);
$where = $this->prepData($where, $pHTML);
$keys = array($sKey => 1) + (!!$where ? $where : array());
$fields = array();
$ids = array();
foreach($data as $v){
$temp = array_diff_key($v, $keys);
// gather all ids;
$ids[] = $v[$sKey];
if(!is_numeric($v[$sKey]))
$bIsString = true;
if(empty($fields)){
$fields = array_diff_key($temp, array());
foreach($fields as &$vv)
$vv = " WHEN '{$v[$sKey]}' THEN '{$vv}' ";
unset($vv);
}else{
foreach($temp as $k=>$vv)
$fields[$k] .= " WHEN '{$v[$sKey]}' THEN '{$vv}' ";
}
unset($vv);
}
// Create query
$sSql = "";
foreach($fields as $k=>$v)
$sSql .= ", `{$k}` = CASE `{$sKey}` {$v} END";
$sWhere = "`{$sKey}` IN (". ($bIsString ? "'" . implode("','", $ids) . "'" : implode(",", $ids)) .") ";
if(!empty($where)){
foreach($where as $k => $v)
$sWhere .= " AND `{$k}` = '{$v}'";
}
// Complete query
$sSql = "UPDATE `{$table}` SET " . substr($sSql, 1) . " WHERE " . $sWhere;
if($this->execute($sSql, $table, $sWhere))
return true;
}
return false;
}
/**
* Function to start transition
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param int $maxQueriesInBatch - count of transactions in send batch
* @return bool - status
*/
public function startTransaction($maxQueriesInBatch = 20){
$this->lMAxTransactionCount = $maxQueriesInBatch;
return $this->bTransactionActive = true;
}
/**
* Function to end transition and exec script
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @return bool - status
*/
public function endTransactionAndExec(){
if($this->bTransactionActive)
$this->chkExecSqlTransactionData(true);
$this->bTransactionActive = false;
return true;
}
/**
* Function to add sql to transaction
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param string $sSql - sql to add to transaction batch
* @return bool - status
*/
public function addTransactionSql($sSql){
if($this->bTransactionActive){
$sSql = trim($sSql);
// Add semicolon at the end if none found
if(substr($sSql,-1) != ';')
$sSql .= ';';
$this->lTransactionCount++;
$this->sTransactionSql .= "{$sSql}\n";
// Check if limit reached
$this->chkExecSqlTransactionData();
}
return true;
}
/**
* Function to check if transaction limit reached and exec sql batch
*
* @author Mareks Keišs <mareks.keiss@brsystems.lv>
* @param bool $bExec - exec sql data or check limit reach
* @return bool - status
*/
public function chkExecSqlTransactionData($bExec = false){
if($this->bTransactionActive){
if($this->lTransactionCount && strlen($this->sTransactionSql)){
if($bExec || ($this->lTransactionCount >= $this->lMAxTransactionCount)){
if($this->executeMulti($this->sTransactionSql)){
$this->sTransactionSql = "";
$this->lTransactionCount = 0;
return true;
}
}
}elseif($bExec){
// Clear data if sth went wrong
$this->sTransactionSql = "";
$this->lTransactionCount = 0;
return true;
}
}
return false;
}
}