754 lines
22 KiB
PHP
754 lines
22 KiB
PHP
<?php
|
|
|
|
namespace Franzz\Objects;
|
|
use \Settings;
|
|
|
|
/**
|
|
* MySql query manager and generator
|
|
* @author franzz
|
|
* @version 2.1
|
|
*/
|
|
class Db extends PhpObject
|
|
{
|
|
const DB_PEACHY = 'NO_ERR';
|
|
const DB_NO_CONN = 'ERR_1';
|
|
const DB_NO_DATA = 'ERR_2';
|
|
const DB_NO_TABLE = 'ERR_3';
|
|
const ID_TAG = 'id_';
|
|
|
|
//Database formats
|
|
const MONTH_FORMAT = 'Ym';
|
|
const DATE_FORMAT = 'Y-m-d';
|
|
const TIMESTAMP_FORMAT = 'Y-m-d H:i:s';
|
|
|
|
public $sDbState;
|
|
private $bTrace;
|
|
|
|
/**
|
|
* SQL connection Handle
|
|
* @var \mysqli
|
|
*/
|
|
private $oConnection;
|
|
private $asConf;
|
|
private $asOptions;
|
|
|
|
/**
|
|
* Tables & fields descriptions
|
|
* array( 'tables'=>array('table_name1'=>array('table_field1', 'table_field2', ...), 'table_name2'=>array(...)),
|
|
* 'types'=>array('field1'=>'field_type1', 'field2'=>'field_type2', ...)
|
|
* 'constraints'=>array('table_name1'=>'table_contraint1', 'table_name2'=>'table_contraint2', ...),
|
|
* 'cascading_delete'=>array('table_name1'=>array('linked_table1', 'linked_table2', ...), 'table_name2'=>...))
|
|
* @var Array
|
|
*/
|
|
public function __construct($asConf, $asOptions)
|
|
{
|
|
$this->asConf = $asConf;
|
|
$this->asOptions = $asOptions;
|
|
|
|
parent::__construct(__FILE__, Settings::DEBUG);
|
|
$this->oConnection = new \mysqli($this->getConf('server'), $this->getConf('user'), $this->getConf('pass'));
|
|
$this->syncPhpParams($this->getConf('encoding'));
|
|
|
|
$this->setTrace(false);
|
|
if($this->oConnection->connect_error)
|
|
{
|
|
$this->addError('bug connection : '.$this->oConnection->connect_error);
|
|
$this->sDbState = self::DB_NO_CONN;
|
|
}
|
|
else
|
|
{
|
|
if(!$this->oConnection->select_db($this->getConf('database')))
|
|
{
|
|
$this->addError('Could not find database "'.$this->sDatabase.'"');
|
|
$this->sDbState = self::DB_NO_DATA;
|
|
}
|
|
elseif(empty($this->getArrayQuery("SHOW TABLES")))
|
|
{
|
|
$this->sDbState = self::DB_NO_TABLE;
|
|
}
|
|
else $this->sDbState = self::DB_PEACHY;
|
|
}
|
|
}
|
|
|
|
private function getConf($sConf) {
|
|
return $this->asConf[$sConf] ?? null;
|
|
}
|
|
|
|
private function syncPhpParams($sEncoding)
|
|
{
|
|
//Characters encoding
|
|
$this->oConnection->set_charset($sEncoding); //SET NAMES
|
|
|
|
//Timezone
|
|
$this->setQuery("SET time_zone='".date_default_timezone_get()."'");
|
|
}
|
|
|
|
public function __destruct()
|
|
{
|
|
parent::__destruct();
|
|
$this->oConnection->close();
|
|
}
|
|
|
|
public function setTrace($bTrace=true)
|
|
{
|
|
$this->bTrace = $bTrace;
|
|
}
|
|
|
|
public function getTrace()
|
|
{
|
|
return $this->bTrace;
|
|
}
|
|
|
|
public function getTables()
|
|
{
|
|
return array_keys($this->asOptions['tables']);
|
|
}
|
|
|
|
public function install()
|
|
{
|
|
//Create Database
|
|
$this->setQuery("DROP DATABASE IF EXISTS ".$this->sDatabase);
|
|
$this->setQuery("CREATE DATABASE ".$this->sDatabase." DEFAULT CHARACTER SET ".$this->getConf('encoding')." DEFAULT COLLATE ".$this->getConf('encoding')."_general_ci");
|
|
$this->oConnection->select_db($this->sDatabase);
|
|
|
|
//Create tables
|
|
@array_walk($this->getInstallQueries(), array($this, 'setQuery'));
|
|
}
|
|
|
|
public function getBackup() {
|
|
$sBackupFile = uniqid('backup_').'.sql';
|
|
|
|
$sAppPath = '';
|
|
if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') $sAppPath = 'C:\ProgramData\xampp\mysql\bin\\';
|
|
exec($sAppPath.'mysqldump --user='.$this->getConf('user').' --password='.$this->getConf('pass').' '.$this->getConf('database').' --add-drop-table --result-file='.$sBackupFile);
|
|
if(file_exists($sBackupFile)) {
|
|
$sBackup = file_get_contents($sBackupFile);
|
|
unlink($sBackupFile);
|
|
return $sBackup;
|
|
}
|
|
else return false;
|
|
}
|
|
|
|
public function restoreBackup($sBackupFile) {
|
|
$sAppPath = '';
|
|
if(file_exists($sBackupFile)) {
|
|
if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') $sAppPath = 'C:\ProgramData\xampp\mysql\bin\\';
|
|
return exec($sAppPath.'mysql --user='.$this->getConf('user').' --password='.$this->getConf('pass').' '.$this->getConf('database').' < '.$sBackupFile);
|
|
}
|
|
else return false;
|
|
}
|
|
|
|
public function loadFile($sFilePath) {
|
|
set_time_limit(0);
|
|
$bResult = false;
|
|
|
|
if(file_exists($sFilePath))
|
|
{
|
|
$sContent = file_get_contents($sFilePath);
|
|
$sContent = ToolBox::fixEOL($sContent);
|
|
if(str_replace(ToolBox::FILE_EOL, '', $sContent)!='')
|
|
{
|
|
$asLines = explode(ToolBox::FILE_EOL, $sContent);
|
|
$sSql = '';
|
|
foreach ($asLines as $sLine)
|
|
{
|
|
$sSql .= trim($sLine);
|
|
if(substr($sSql, -1)==';') //Multi line SQL
|
|
{
|
|
$asResult = $this->setQuery($sSql);
|
|
if($asResult === false)
|
|
{
|
|
$this->addError('SQL failed with error: '.$this->db->error, $sSql);
|
|
$bResult = false;
|
|
break;
|
|
}
|
|
|
|
$bResult = true;
|
|
$sSql = '';
|
|
}
|
|
else $sSql .= " ";
|
|
}
|
|
}
|
|
else $this->addError('File is empty: '.basename($sFilePath));
|
|
}
|
|
else $this->addError('File not found: '.$sFilePath);
|
|
|
|
return $bResult;
|
|
}
|
|
|
|
//For debug purposes
|
|
public function getFullInstallQuery()
|
|
{
|
|
$asInstallQueries = $this->getInstallQueries();
|
|
return str_replace("\n", "<br />", implode(";\n\n", $asInstallQueries))."\n\n<!-- \n".implode(";\n\n", $asInstallQueries)."\n -->";
|
|
}
|
|
|
|
private function getInstallQueries()
|
|
{
|
|
$asTables = $this->getTables();
|
|
$asInstallQueries = array_map(array($this, 'getInstallQuery'), $asTables);
|
|
$asAlterQueries = $this->getForeignKeyQueries($asTables);
|
|
return array_merge($asInstallQueries, $asAlterQueries);
|
|
}
|
|
|
|
private function getInstallQuery($sTableName)
|
|
{
|
|
$asTableColumns = $this->getTableColumns($sTableName);
|
|
$sQuery = "\n".$this->implodeAll($asTableColumns, "` ", "\n", "`", ",")."\n".implode(", \n", $this->getTableConstraints($sTableName));
|
|
return "CREATE TABLE `{$sTableName}` ({$sQuery})";
|
|
}
|
|
|
|
private function getForeignKeyQueries($asTableNames)
|
|
{
|
|
$asForeignKeyQueries = array();
|
|
foreach($asTableNames as $sTableName)
|
|
{
|
|
$asTableColumns = $this->getTablecolumns($sTableName, false);
|
|
foreach($asTableColumns as $sColumnName)
|
|
{
|
|
if($this->isId($sColumnName) && $sColumnName!=self::getId($sTableName))
|
|
{
|
|
$asForeignKeyQueries[] = "ALTER TABLE ".$sTableName." ADD INDEX(`".$sColumnName."`)";
|
|
$asForeignKeyQueries[] = "ALTER TABLE ".$sTableName." ADD FOREIGN KEY (`".$sColumnName."`) REFERENCES ".self::getTable($sColumnName)."(`".$sColumnName."`)";
|
|
}
|
|
}
|
|
}
|
|
return $asForeignKeyQueries;
|
|
}
|
|
|
|
private function setQuery($sQuery, $sTypeQuery=__FUNCTION__)
|
|
{
|
|
$oResult = $this->getQuery($sQuery, $sTypeQuery);
|
|
return ($oResult!==false);
|
|
}
|
|
|
|
private function getQuery($sQuery, $sTypeQuery=__FUNCTION__)
|
|
{
|
|
$sQuery = str_replace(array("\n", "\t"), array(" ", ""), $sQuery);
|
|
|
|
if($this->getTrace()) $this->addNotice($sQuery.";");
|
|
|
|
if(!($oResult = $this->oConnection->query($sQuery)))
|
|
{
|
|
$this->addError("\nErreur SQL : \n".str_replace("\t", "", $sQuery.";")."\n\n".str_replace(array("\t", "\n"), "", $this->getLastError()));
|
|
}
|
|
return $oResult;
|
|
}
|
|
|
|
public function getLastError()
|
|
{
|
|
return $this->oConnection->error;
|
|
}
|
|
|
|
public function getArrayQuery($sQuery, $bStringOnly=false, $sGroupBy='', $sTypeQuery=__FUNCTION__)
|
|
{
|
|
$iIndex = 0;
|
|
$iColumnCount = 0;
|
|
$asResult = array();
|
|
$oResult = $this->getQuery($sQuery, true, $sTypeQuery);
|
|
if($oResult!==false)
|
|
{
|
|
while($asCurrentRow = $oResult->fetch_array())
|
|
{
|
|
if($bStringOnly) $asCurrentRow = $this->arrayKeyFilter($asCurrentRow, 'is_string');
|
|
|
|
//Add table reel keys
|
|
if($sGroupBy!='' && array_key_exists($sGroupBy, $asCurrentRow))
|
|
{
|
|
$iRowKey = $asCurrentRow[$sGroupBy];
|
|
unset($asCurrentRow[$sGroupBy]);
|
|
}
|
|
else $iRowKey = $iIndex;
|
|
|
|
//For first loop, check table width
|
|
if($iIndex==0) $iColumnCount = count($asCurrentRow);
|
|
|
|
//One column case : collapse a level
|
|
if($iColumnCount==1) $asCurrentRow = array_shift($asCurrentRow);
|
|
|
|
$asResult[$iRowKey] = $asCurrentRow;
|
|
$iIndex++;
|
|
}
|
|
}
|
|
return $asResult;
|
|
}
|
|
|
|
private function getMaxIncrementedValue($sTable)
|
|
{
|
|
return $this->selectValue($sTable, "MAX(".$this->getId($sTable).")");
|
|
}
|
|
|
|
public static function getId($sTableName, $bFull=false)
|
|
{
|
|
$sColumnName = self::ID_TAG.self::getText($sTableName);
|
|
return $bFull?self::getFullColumnName($sTableName, $sColumnName):$sColumnName;
|
|
}
|
|
|
|
public static function getText($sTableName, $bFull=false)
|
|
{
|
|
$sColumnName = mb_substr(str_replace('`', '', $sTableName), 0, -1);
|
|
$sColumnName = mb_substr($sColumnName, -2)=='ie'?mb_substr($sColumnName, 0, -2).'y':$sColumnName;
|
|
return $bFull?self::getFullColumnName($sTableName, $sColumnName):$sColumnName;
|
|
}
|
|
|
|
public static function getFullColumnName($sTableName, $sColumnName)
|
|
{
|
|
return $sTableName.".".$sColumnName;
|
|
}
|
|
|
|
private function isId($sColumnName, $sTableName='')
|
|
{
|
|
$asTables = ($sTableName=='')?$this->getTables():array($sTableName);
|
|
$asTableIds = array_map(array('self', 'getId'), $asTables);
|
|
return in_array($sColumnName, $asTableIds);
|
|
}
|
|
|
|
private function isField($sTableFieldName)
|
|
{
|
|
$asPath = explode('.', str_replace('`', '', $sTableFieldName));
|
|
return (
|
|
is_array($asPath)
|
|
&& count($asPath)==2
|
|
&& $this->isColumnInTable($asPath[0], $asPath[1])
|
|
);
|
|
}
|
|
|
|
private function getTable($sTableId)
|
|
{
|
|
$asTables = $this->getTables();
|
|
$asTableIds = array_map(array('self', 'getId'), $asTables);
|
|
if(in_array($sTableId, $asTableIds)) return $asTables[array_search($sTableId, $asTableIds)];
|
|
else
|
|
{
|
|
$this->addError('Id '.$sTableId.' présent dans aucune table');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public function getTablecolumns($sTableName, $bTypes=true)
|
|
{
|
|
if(!array_key_exists($sTableName, $this->asOptions['tables'])) return false;
|
|
|
|
$asTableColumns = array(self::getId($sTableName));
|
|
foreach($this->asOptions['tables'][$sTableName] as $sFieldName) $asTableColumns[] = $sFieldName;
|
|
$asTableColumns[] = 'led';
|
|
|
|
if(!$bTypes) return $asTableColumns;
|
|
|
|
$asTableName = array_fill(0, count($asTableColumns), $sTableName);
|
|
return array_combine($asTableColumns, array_map(array('self', 'getColumnType'), $asTableColumns, $asTableName));
|
|
}
|
|
|
|
public function isColumnInTable($sTableName, $sColName) {
|
|
$asCols = $this->getTablecolumns($sTableName, false);
|
|
return ($asCols && in_array($sColName, $asCols));
|
|
}
|
|
|
|
private function getColumnType($sColumnName, $sTableName)
|
|
{
|
|
$sColumnType = '';
|
|
switch($sColumnName)
|
|
{
|
|
case array_key_exists($sColumnName, $this->asOptions['types']):
|
|
$sColumnType = $this->asOptions['types'][$sColumnName];
|
|
break;
|
|
case 'led':
|
|
$sColumnType = "TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP";
|
|
break;
|
|
case $this->isId($sColumnName, $sTableName):
|
|
$sColumnType = "int(10) UNSIGNED auto_increment";
|
|
break;
|
|
case $this->isId($sColumnName):
|
|
$sColumnType = "int(10) UNSIGNED";
|
|
break;
|
|
}
|
|
return $sColumnType;
|
|
}
|
|
|
|
private function getTableConstraints($sTableName)
|
|
{
|
|
//Primary key
|
|
$asTableConstraints = array("PRIMARY KEY (`".self::getId($sTableName)."`)");
|
|
|
|
//Foreign keys: applied using ALTER TABLE syntax at the end to prevent scheduling CREATE TABLE queries
|
|
|
|
//Other constraints
|
|
if(array_key_exists($sTableName, $this->asOptions['constraints'])) {
|
|
if(is_array($this->asOptions['constraints'][$sTableName])) $asTableConstraints = array_merge($asTableConstraints, $this->asOptions['constraints'][$sTableName]);
|
|
else $asTableConstraints[] = $this->asOptions['constraints'][$sTableName];
|
|
}
|
|
return $asTableConstraints;
|
|
}
|
|
|
|
private function addQuotes($oData)
|
|
{
|
|
//TODO remake
|
|
$asTrustedFunc = array('CURDATE()', 'NOW()', 'NULL');
|
|
$sChar = "'";
|
|
if(is_array($oData))
|
|
{
|
|
$asChar = array_fill(1, count($oData), $sChar);
|
|
return array_combine(array_keys($oData), array_map(array($this, 'addQuotes'), $oData, $asChar));
|
|
}
|
|
else
|
|
{
|
|
if(in_array($oData, $asTrustedFunc) || $this->isField($oData)) return $oData;
|
|
else return $sChar.$oData.$sChar;
|
|
}
|
|
}
|
|
|
|
private function getLastId()
|
|
{
|
|
return $this->oConnection->insert_id;
|
|
}
|
|
|
|
private function getLastImpact()
|
|
{
|
|
return ($this->oConnection->affected_rows > 0);
|
|
}
|
|
|
|
public function insertRow($sTableName, $asData)
|
|
{
|
|
$this->cleanSql($sTableName);
|
|
$this->cleanSql($asData);
|
|
|
|
$asQueryValues = $this->addQuotes($asData);
|
|
$sQuery = "INSERT INTO ".$sTableName." (`".implode("`, `", array_keys($asQueryValues))."`) VALUES (".implode(", ", $asQueryValues).")";
|
|
return $this->setQuery($sQuery)?$this->getLastId():0;
|
|
}
|
|
|
|
public function updateRow($sTableName, $asConstraints, $asData, $bLedUpdate=true)
|
|
{
|
|
return $this->updateRows($sTableName, $asConstraints, $asData, 1, $bLedUpdate);
|
|
}
|
|
|
|
public function updateRows($sTableName, $asConstraints, $asData, $iLimit=0, $bLedUpdate=true)
|
|
{
|
|
if(!is_array($asConstraints))
|
|
{
|
|
$asConstraints = array($this->getId($sTableName)=>$asConstraints);
|
|
}
|
|
|
|
//Cleaning values
|
|
$this->cleanSql($sTableName);
|
|
$this->cleanSql($asData);
|
|
$this->cleanSql($asConstraints);
|
|
$asQueryValues = $this->addQuotes($asData);
|
|
$asConstraintsValues = $this->addQuotes($asConstraints);
|
|
$this->addColumnSelectors($asQueryValues);
|
|
$this->addColumnSelectors($asConstraintsValues);
|
|
|
|
//Building query
|
|
if(!$bLedUpdate) $asQueryValues['led'] = 'led';
|
|
$sLimit = $iLimit>0?" LIMIT $iLimit":"";
|
|
$sQuery = "UPDATE {$sTableName} ".
|
|
"SET ".$this->implodeAll($asQueryValues, " = ", ", ")." ".
|
|
"WHERE ".$this->implodeAll($asConstraintsValues, " = ", " AND ").$sLimit;
|
|
|
|
$iResult = false;
|
|
if($this->setQuery($sQuery))
|
|
{
|
|
if(!$this->getLastImpact()) $this->addNotice('Last query had no effect on db: "'.$sQuery.';"');
|
|
$iResult = ($iLimit==1)?$this->selectValue($sTableName, $this->getId($sTableName), $asConstraints):true;
|
|
}
|
|
return $iResult;
|
|
}
|
|
|
|
public function insertUpdateRow($sTableName, $asData, $asKeys=array(), $bUpdate=true)
|
|
{
|
|
$sTableIdName = self::getId($sTableName);
|
|
|
|
//check for data in the db
|
|
if($asKeys==array())
|
|
{
|
|
$asKeys[] = $sTableIdName;
|
|
}
|
|
$asValues = array_intersect_key($asData, array_flip($asKeys));
|
|
$iTableId = $this->selectValue($sTableName, $sTableIdName, $asValues);
|
|
|
|
//insert
|
|
if(!$iTableId)
|
|
{
|
|
$iTableId = $this->insertRow($sTableName, $asData);
|
|
}
|
|
//Update
|
|
elseif($bUpdate)
|
|
{
|
|
if(array_key_exists($sTableIdName, $asData))
|
|
{
|
|
unset($asData[$sTableIdName]);
|
|
}
|
|
$iTableId = $this->updateRow($sTableName, $iTableId, $asData);
|
|
}
|
|
return $iTableId;
|
|
}
|
|
|
|
public function selectInsert($sTableName, $asData, $asKeys=array())
|
|
{
|
|
return $this->insertUpdateRow($sTableName, $asData, $asKeys, false);
|
|
}
|
|
|
|
public function deleteRow($sTableName, $iTableId)
|
|
{
|
|
$this->cleanSql($sTableName);
|
|
$this->cleanSql($iTableId);
|
|
|
|
$bSuccess = true;
|
|
|
|
//linked tables
|
|
switch($sTableName)
|
|
{
|
|
case (array_key_exists('cascading_delete', $this->asOptions) && array_key_exists($sTableName, $this->asOptions['cascading_delete'])) :
|
|
$asTables = array_merge(is_array($sTableName)?array_values($sTableName):array($sTableName), array_values($this->asOptions['cascading_delete'][$sTableName]));
|
|
break;
|
|
case is_string($sTableName) :
|
|
$asTables = array($sTableName);
|
|
break;
|
|
case is_array($sTableName):
|
|
$asTables = $sTableName;
|
|
break;
|
|
default:
|
|
$asTables = array();
|
|
}
|
|
foreach($asTables as $sTable)
|
|
{
|
|
$bSuccess = $bSuccess && $this->setQuery("DELETE FROM ".$sTable." WHERE ".$this->getId($sTableName)." = ".$iTableId);
|
|
}
|
|
return $bSuccess;
|
|
}
|
|
|
|
public function emptyTable($sTableName)
|
|
{
|
|
$this->cleanSql($sTableName);
|
|
return $this->setQuery("TRUNCATE ".$sTableName);
|
|
}
|
|
|
|
public function selectList($sTableName, $sColumnName='', $asConstraints=array())
|
|
{
|
|
$sColumnName = $sColumnName==''?self::getText($sTableName):$sColumnName;
|
|
$sIdColumnName = self::getId($sTableName);
|
|
return $this->selectRows( array( 'select' => array($sIdColumnName, $sColumnName),
|
|
'from' => $sTableName,
|
|
'constraint'=> $asConstraints),
|
|
true,
|
|
$sIdColumnName);
|
|
}
|
|
|
|
public function selectRows($asInfo, $sGroupBy='', $bStringOnly=true)
|
|
{
|
|
$asAttributes = array('select'=>"SELECT", 'from'=>"FROM", 'join'=>"LEFT JOIN", 'joinOn'=>"LEFT JOIN", 'constraint'=>"WHERE", 'groupBy'=>"GROUP BY", 'orderBy'=>"ORDER BY", 'limit'=>'LIMIT');
|
|
$asRowSeparators = array('select'=>", ", 'from'=>"", 'join'=>" LEFT JOIN ", 'joinOn'=>" LEFT JOIN ", 'constraint'=>" AND ", 'groupBy'=>", ", 'orderBy'=>", ", 'limit'=>"");
|
|
$asOperators = array('constraint'=>" = ", 'orderBy'=>" ", 'join'=>" USING(", 'joinOn'=>" ON ");
|
|
$asEndOfStatement = array('constraint'=>"", 'orderBy'=>"", 'join'=>")", 'joinOn'=>"");
|
|
|
|
//Simple selectRows
|
|
if(!is_array($asInfo)) $asInfo = array('from'=>$asInfo);
|
|
|
|
//Get table by key
|
|
if($sGroupBy===true)
|
|
{
|
|
$sGroupBy = self::getId($asInfo['from']);
|
|
|
|
//Add id to selection
|
|
if(isset($asInfo['select']) && $asInfo['select'][0]!="*") $asInfo['select'][] = $sGroupBy;
|
|
}
|
|
|
|
$sQuery = "";
|
|
foreach($asAttributes as $sStatement => $sKeyWord)
|
|
{
|
|
$asSelection = array_key_exists($sStatement, $asInfo)?$asInfo[$sStatement]:array();
|
|
if(!is_array($asSelection))
|
|
{
|
|
$asSelection = array($asSelection);
|
|
}
|
|
|
|
//if provided values
|
|
if(!empty($asSelection))
|
|
{
|
|
$this->cleanSql($asSelection);
|
|
|
|
if($sStatement=='constraint' && !array_key_exists('constVar', $asInfo))
|
|
{
|
|
$asSelection = $this->addQuotes($asSelection);
|
|
foreach($asSelection as $sField=>$asConstraints)
|
|
{
|
|
if(is_array($asConstraints))
|
|
{
|
|
if(array_key_exists('constOpe', $asInfo) && array_key_exists($sField, $asInfo['constOpe']) && $asInfo['constOpe'][$sField]=='BETWEEN') {
|
|
//Between
|
|
$asSelection[$sField] = $asConstraints['from'].' AND '.$asConstraints['to'];
|
|
$asInfo['constOpe'][$sField] = " BETWEEN ";
|
|
}
|
|
else {
|
|
//Multiple values (IN)
|
|
$asSelection[$sField] = "(".implode(', ', $asConstraints).")";
|
|
$asInfo['constOpe'][$sField] = " IN ";
|
|
}
|
|
}
|
|
elseif(!array_key_exists('constOpe', $asInfo) || !array_key_exists($sField, $asInfo['constOpe'])) $asInfo['constOpe'][$sField] = " = ";
|
|
}
|
|
}
|
|
$this->addColumnSelectors($asSelection);
|
|
|
|
$sQuery .= " ".$sKeyWord." ";
|
|
|
|
//in case of double value input
|
|
if(array_key_exists($sStatement, $asOperators))
|
|
{
|
|
if($sStatement=='constraint' && array_key_exists('constOpe', $asInfo))
|
|
{
|
|
$asOperators[$sStatement] = $asInfo['constOpe'];
|
|
}
|
|
elseif($sStatement=='joinOn')
|
|
{
|
|
$asSimplifiedSelection = array();
|
|
foreach($asSelection as $sTable => $asJoinFields)
|
|
{
|
|
$asJoinFields = $this->addQuotes($asJoinFields);
|
|
$asSimplifiedSelection[$sTable] = $this->implodeAll($asJoinFields, " = ", " AND ");
|
|
}
|
|
$asSelection = $asSimplifiedSelection;
|
|
}
|
|
$sQuery .= $this->implodeAll($asSelection, $asOperators[$sStatement], $asRowSeparators[$sStatement], "", $asEndOfStatement[$sStatement]);
|
|
}
|
|
else
|
|
{
|
|
$sQuery .= implode($asRowSeparators[$sStatement], $asSelection);
|
|
}
|
|
}
|
|
//default value for select
|
|
elseif($sStatement=='select')
|
|
{
|
|
$sQuery .= " ".$sKeyWord." * ";
|
|
}
|
|
}
|
|
|
|
return $this->getArrayQuery(trim($sQuery), $bStringOnly, $sGroupBy);
|
|
}
|
|
|
|
private function addColumnSelectors(&$asSelection)
|
|
{
|
|
//FIXME get rid of this
|
|
$sSqlWord = 'option';
|
|
$sKey = array_search($sSqlWord, $asSelection);
|
|
if($sKey!==false)
|
|
{
|
|
$asSelection[$sKey] = "`".$asSelection[$sKey]."`";
|
|
}
|
|
elseif(array_key_exists($sSqlWord, $asSelection))
|
|
{
|
|
$asSelection["`".$sSqlWord."`"] = $asSelection[$sSqlWord];
|
|
unset($asSelection[$sSqlWord]);
|
|
}
|
|
}
|
|
|
|
public function selectRow($sTableName, $asConstraints=array(), $sColumnName='*')
|
|
{
|
|
//Table ID directly
|
|
if(!is_array($asConstraints)) $asConstraints = array($this->getId($sTableName)=>$asConstraints);
|
|
|
|
$asRows = $this->selectRows(array('select'=>$sColumnName, 'from'=>$sTableName, 'constraint'=>$asConstraints));
|
|
$iCountNb = count($asRows);
|
|
switch($iCountNb)
|
|
{
|
|
case 0 :
|
|
$asResult = array();
|
|
break;
|
|
case $iCountNb > 1 :
|
|
$this->addError('More than 1 result for a selectRow(): '.$iCountNb.' results. Table: '.$sTableName.', constraint: '.self::implodeAll($asConstraints, '=', ' '));
|
|
default:
|
|
$asResult = array_shift($asRows);
|
|
}
|
|
return $asResult;
|
|
}
|
|
|
|
public function selectColumn($sTableName, $asColumnNames, $asConstraints)
|
|
{
|
|
$sGroupBy = '';
|
|
if(!is_array($asColumnNames)) $asColumnNames = array($asColumnNames);
|
|
else $sGroupBy = $asColumnNames[0];
|
|
|
|
return $this->selectRows(
|
|
array(
|
|
'select' => $asColumnNames,
|
|
'from' => $sTableName,
|
|
'constraint'=> $asConstraints
|
|
),
|
|
$sGroupBy
|
|
);
|
|
}
|
|
|
|
public function selectValue($sTableName, $sColumnName, $oConstraints=array())
|
|
{
|
|
if(!is_array($oConstraints))
|
|
{
|
|
$oConstraints = array($this->getId($sTableName)=>$oConstraints);
|
|
}
|
|
$oResult = $this->selectRow($sTableName, $oConstraints, $sColumnName);
|
|
return empty($oResult)?false:$oResult;
|
|
}
|
|
|
|
public function selectId($sTableName, $oConstraints)
|
|
{
|
|
return $this->selectValue($sTableName, self::getId($sTableName), $oConstraints);
|
|
}
|
|
|
|
public function pingValue($sTableName, $oConstraints)
|
|
{
|
|
return $this->selectValue($sTableName, 'COUNT(1)', $oConstraints);
|
|
}
|
|
|
|
public function cleanSql(&$oData)
|
|
{
|
|
$this->cleanData($oData);
|
|
$oData = $this->cleanData($oData);
|
|
}
|
|
|
|
//TODO déplacer dans ToolBox::implodeAll
|
|
public static function implodeAll($asText, $asKeyValueSeparator='', $sRowSeparator='', $sKeyPre='', $sValuePost=false)
|
|
{
|
|
if($sValuePost===false)
|
|
{
|
|
$sValuePost = $sKeyPre;
|
|
}
|
|
$asCombinedText = array();
|
|
|
|
//if unique value for key value separator
|
|
if(!is_array($asKeyValueSeparator) && !empty($asText))
|
|
{
|
|
$asKeyValueSeparator = array_combine(array_keys($asText), array_fill(0, count($asText), $asKeyValueSeparator));
|
|
}
|
|
|
|
$asFrom = array('[/KEY\]', '[/VALUE\]');
|
|
foreach($asText as $sKey=>$sValue)
|
|
{
|
|
$asTo = array($sKey, $sValue);
|
|
$sRepKeyPre = str_replace($asFrom, $asTo, $sKeyPre);
|
|
$asRepKeyValueSeparator = str_replace($asFrom, $asTo, $asKeyValueSeparator[$sKey]);
|
|
$sRepValuePost = str_replace($asFrom, $asTo, $sValuePost);
|
|
$asCombinedText[] = $sRepKeyPre.$sKey.$asRepKeyValueSeparator.(is_array($sValue)?implode($sValue):$sValue).$sRepValuePost;
|
|
}
|
|
return implode($sRowSeparator, $asCombinedText);
|
|
}
|
|
|
|
public static function arrayKeyFilter($asArray, $sCallBack)
|
|
{
|
|
$asValidKeys = array_flip(array_filter(array_keys($asArray), $sCallBack));
|
|
return array_intersect_key($asArray, $asValidKeys);
|
|
}
|
|
|
|
public function cleanData($oData)
|
|
{
|
|
if(!is_array($oData))
|
|
{
|
|
return $this->oConnection->real_escape_string($oData);
|
|
}
|
|
elseif(count($oData)>0)
|
|
{
|
|
$asKeys = array_map(array($this, 'cleanData'), array_keys($oData));
|
|
$asValues = array_map(array($this, 'cleanData'), $oData);
|
|
return array_combine($asKeys, $asValues);
|
|
}
|
|
}
|
|
}
|