1500 lines
60 KiB
PHP
1500 lines
60 KiB
PHP
<?php
|
|
namespace DynCom\mysyde\common\classes;
|
|
use DynCom\mysyde\common\interfaces\GenericDBQueryWrapperInterface;
|
|
use PDO;
|
|
use PDOException;
|
|
|
|
/**
|
|
* Created by PhpStorm.
|
|
* User: Micha
|
|
* Date: 16.01.2015
|
|
* Time: 23:38
|
|
*/
|
|
class PDOQueryWrapper implements GenericDBQueryWrapperInterface
|
|
{
|
|
|
|
protected $hostName = 'localhost';
|
|
protected $portNumber = '3306';
|
|
protected $dbName = 'dcshop';
|
|
protected $userName = 'root';
|
|
protected $password = '';
|
|
protected $optionsArray = array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION);
|
|
protected $dsn;
|
|
|
|
protected $allowedComparisonOperators = array('IS NULL', 'IS NOT NULL', '=', '!=', '<', '>', '>=', '<=', 'IN', 'LIKE');
|
|
protected $comparisonValidation;
|
|
|
|
protected $unfinishedQuery = [];
|
|
protected $unfinishedQueryGroups = array();
|
|
protected $currQueryGroup;
|
|
|
|
protected $connectionObject;
|
|
|
|
protected $query = '';
|
|
/**
|
|
* @var \PDOStatement
|
|
*/
|
|
protected $stmt;
|
|
|
|
/**
|
|
* @return mixed
|
|
*/
|
|
public function getStmt()
|
|
{
|
|
return $this->stmt;
|
|
}
|
|
|
|
/**
|
|
* @return mixed
|
|
*/
|
|
public function getResult()
|
|
{
|
|
return $this->result;
|
|
}
|
|
|
|
protected $result;
|
|
protected $resultIndex = 0;
|
|
|
|
protected $errorState = TRUE;
|
|
protected $errorMessage = 'No connection';
|
|
protected $errorCode = '-1';
|
|
|
|
|
|
/**
|
|
* @param string $hostName
|
|
* @param int $portNumber
|
|
* @param string $dbName
|
|
* @param string $userName
|
|
* @param string $password
|
|
* @param array $optionsArray
|
|
*/
|
|
public function __construct($hostName, $portNumber, $dbName, $userName, $password, array $optionsArray = NULL)
|
|
{
|
|
|
|
$this->hostName = ($hostName ? (string)$hostName : 'localhost');
|
|
$this->portNumber = ($portNumber ? (int)$portNumber : 3306);
|
|
$this->dbName = ($dbName ? (string)$dbName : 'dcshop');
|
|
$this->userName = ($userName ? (string)$userName : 'root');
|
|
$this->password = ($password ? (string)$password : '123');
|
|
$this->optionsArray = ((is_array($optionsArray) && count($optionsArray) > 0) ? $optionsArray : array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));
|
|
|
|
$this->dsn = 'mysql:dbname=' . $this->dbName . ';host=' . $this->hostName . ';port=' . (string)$this->portNumber . ';charset=utf8mb4';
|
|
|
|
$pdo = new \PDO($this->dsn, $this->userName, $this->password, $this->optionsArray);
|
|
|
|
if (!$pdo->exec('SET NAMES utf8mb4') || !$pdo->exec('SET CHARACTER SET utf8mb4')) {
|
|
$pdoErrorInfo = $pdo->errorInfo();
|
|
$this->errorState = TRUE;
|
|
$this->errorMessage = print_r($pdoErrorInfo, 1);
|
|
}
|
|
|
|
$this->connectionObject = $pdo;
|
|
$this->errorState = FALSE;
|
|
$this->errorMessage = '';
|
|
|
|
$this->_setComparisonValidationArray();
|
|
|
|
}
|
|
|
|
/**
|
|
* @param $hostName
|
|
* @return $this
|
|
*/
|
|
public function setHostName($hostName)
|
|
{
|
|
$this->hostName = $hostName;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $portNumber
|
|
* @return $this
|
|
*/
|
|
public function setPortNumber($portNumber)
|
|
{
|
|
$this->portNumber = $portNumber;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $dbName
|
|
* @return $this
|
|
*/
|
|
public function setDbName($dbName)
|
|
{
|
|
$this->dbName = $dbName;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $userName
|
|
* @return $this
|
|
*/
|
|
public function setUserName($userName)
|
|
{
|
|
$this->userName = $userName;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $password
|
|
* @return $this
|
|
*/
|
|
public function setPassword($password)
|
|
{
|
|
$this->password = $password;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param array $optionsArray
|
|
* @return $this
|
|
*/
|
|
public function setOptionsArray(array $optionsArray)
|
|
{
|
|
$this->optionsArray = $optionsArray;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $query
|
|
* @return $this
|
|
*/
|
|
public function setQuery($query)
|
|
{
|
|
$this->query = $query;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getHostName()
|
|
{
|
|
return $this->hostName;
|
|
}
|
|
|
|
/**
|
|
* @return int
|
|
*/
|
|
public function getPortNumber()
|
|
{
|
|
return $this->portNumber;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getDbName()
|
|
{
|
|
return $this->dbName;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getUserName()
|
|
{
|
|
return $this->userName;
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function getOptionsArray()
|
|
{
|
|
return $this->optionsArray;
|
|
}
|
|
|
|
/**
|
|
* @return mixed
|
|
*/
|
|
public function getQuery()
|
|
{
|
|
return $this->query;
|
|
}
|
|
|
|
/**
|
|
* @return boolean
|
|
*/
|
|
public function isErrorState()
|
|
{
|
|
return $this->errorState;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getErrorMessage()
|
|
{
|
|
return $this->errorMessage;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function reconnect()
|
|
{
|
|
|
|
$pdo = new \PDO($this->dsn, $this->userName, $this->password, $this->optionsArray);
|
|
|
|
if (!$pdo->exec('SET NAMES utf8') || !$pdo->exec('SET CHARACTER SET utf8')) {
|
|
$pdoErrorInfo = $pdo->errorInfo();
|
|
$this->query = '';
|
|
$this->stmt = NULL;
|
|
$this->result = NULL;
|
|
$this->errorState = TRUE;
|
|
$this->errorMessage = print_r($pdoErrorInfo, 1) . ' || ';
|
|
return FALSE;
|
|
}
|
|
|
|
$this->connectionObject = $pdo;
|
|
|
|
$this->errorState = FALSE;
|
|
$this->errorMessage = '';
|
|
|
|
$this->query = '';
|
|
$this->stmt = NULL;
|
|
$this->result = NULL;
|
|
$this->errorState = FALSE;
|
|
$this->errorMessage = '';
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
* @throws \ErrorException
|
|
*/
|
|
public function doQuery()
|
|
{
|
|
|
|
if (!($this->connectionObject instanceof \PDO)) {
|
|
throw new \ErrorException('No PDO Connection-object set');
|
|
}
|
|
|
|
if (empty($this->query)) {
|
|
throw new \ErrorException('Query is not set');
|
|
}
|
|
|
|
|
|
//Check env for logging directives
|
|
$logQueries = (bool)getenv('LOG_QUERIES');
|
|
$tableFilters = (string)getenv('QUERY_LOG_TABLES');
|
|
$methodFilters = (string)getenv('QUERY_LOG_METHODS');
|
|
|
|
$tablesToLog = explode(',',$tableFilters);
|
|
$methodsToLog = explode(',',$methodFilters);
|
|
|
|
if (count($tablesToLog) > 0) {
|
|
$logTable = false;
|
|
foreach($tablesToLog as $tableName) {
|
|
|
|
if ($tableName && strpos($this->query,$tableName) !== false) {
|
|
$logTable = true;
|
|
}
|
|
}
|
|
} else {
|
|
$logTable = true;
|
|
}
|
|
|
|
if (count($methodsToLog) > 0) {
|
|
$logMethod = false;
|
|
foreach($methodsToLog as $methodName) {
|
|
if ($methodName && strpos($this->query,$methodName) !== false) {
|
|
$logMethod = true;
|
|
}
|
|
}
|
|
} else {
|
|
$logMethod = true;
|
|
}
|
|
|
|
$logQuery = $logQueries && $logTable && $logMethod;
|
|
if ($logQuery) {
|
|
$filePath = rtrim($_SERVER['DOCUMENT_ROOT'],'/') . '/logs/query_log.txt';
|
|
$newContent = time() . ' - QUERY: ' . $this->query . PHP_EOL . generateCallTrace() . PHP_EOL . PHP_EOL;
|
|
file_put_contents($filePath,$newContent,FILE_APPEND);
|
|
}
|
|
|
|
try {
|
|
$pdoStatement = $this->connectionObject->query($this->query);
|
|
} catch (PDOException $e) {
|
|
$this->stmt = NULL;
|
|
$this->result = NULL;
|
|
$this->errorState = TRUE;
|
|
//echo "... QUERY ERROR!!! ...QUERY : $this->query";
|
|
$errorInfo = print_r($this->connectionObject->errorInfo(), 1);
|
|
$this->errorMessage .= $errorInfo . ' || ';
|
|
return FALSE;
|
|
}
|
|
|
|
$this->result = NULL;
|
|
$this->stmt = $pdoStatement;
|
|
$this->unfinishedQuery = [];
|
|
$this->errorMessage = '';
|
|
$this->errorState = false;
|
|
$this->errorCode = '0';
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
* @throws \ErrorException
|
|
*/
|
|
public function prepareQuery()
|
|
{
|
|
|
|
if (empty($this->query)) {
|
|
throw new \ErrorException('Query is not set.');
|
|
}
|
|
//FOR VALIDATION of calls, uncomment this:
|
|
// $this->connectionObject = new \PDO($this->dsn,$this->userName,$this->password,$this->optionsArray);
|
|
if (!($stmt = $this->connectionObject->prepare($this->query))) {
|
|
$this->stmt = NULL;
|
|
$this->result = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
$this->result = NULL;
|
|
$this->stmt = $stmt;
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @param array $array Parameter-Value-Type-Array
|
|
* array(
|
|
* array(ParameterName1,ParameterValue1,ParameterType1),
|
|
* array(ParameterName2,ParameterValue2,ParameterType2)
|
|
* ...
|
|
* )
|
|
*
|
|
* @return bool
|
|
* @throws \ErrorException
|
|
*/
|
|
public function bindParameters(array $array)
|
|
{
|
|
|
|
if(!($this->stmt instanceof \PDOStatement)) {
|
|
throw new \ErrorException('No Statement is set.');
|
|
}
|
|
if ($this->stmt->errorCode() > 0) {
|
|
throw new \ErrorException('Statement is in error. ' . print_r($this->stmt->errorInfo(),1));
|
|
}
|
|
|
|
$nameTestPattern = '/^(?:\:[a-zA-Z0-9_\-]+)|(?:[0-9]+)$/';
|
|
foreach ($array as $singleParameterArray) {
|
|
if (!is_array($singleParameterArray) || (count($singleParameterArray) !== 3)) {
|
|
throw new \ErrorException('At least one entry in the paramter-array does not contain an array of count 3
|
|
the required format [colon]parameterName');
|
|
}
|
|
$paramName = (string)$singleParameterArray[0];
|
|
$paramValue = $singleParameterArray[1];
|
|
$paramType = $singleParameterArray[2];
|
|
if (!preg_match($nameTestPattern, $paramName)) {
|
|
throw new \ErrorException('At least one parameterName is neither a question-mark nor a string with pattern [colon]parameterName');
|
|
}
|
|
if (!is_int($paramType)) {
|
|
throw new \ErrorException('At least one parameterType is not an integer');
|
|
}
|
|
if (is_numeric($paramName)) {
|
|
$paramIndex = (int)$paramName;
|
|
if (!$this->stmt->bindValue($paramIndex, $paramValue, $paramType)) {
|
|
throw new \ErrorException('Parameter \'' . $paramName . '\', Value \'' . $paramValue . '\', Type \'' . $paramType . ' could not be bound');
|
|
}
|
|
} else {
|
|
if (!$this->stmt->bindValue($paramName, $paramValue, $paramType)) {
|
|
throw new \ErrorException('Parameter \'' . $paramName . '\', Value \'' . $paramValue . '\', Type \'' . $paramType . ' could not be bound');
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
* @return bool
|
|
* @throws \ErrorException
|
|
*/
|
|
public function executePreparedStatement()
|
|
{
|
|
if (!$this->stmt instanceof \PDOStatement) {
|
|
throw new \ErrorException('No prepared statement set');
|
|
}
|
|
try {
|
|
$this->stmt->execute();
|
|
} catch (PDOException $e) {
|
|
$this->errorState = TRUE;
|
|
$this->errorMessage .= $e->getMessage() . ' || ';
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $params
|
|
* @return bool
|
|
* @throws \ErrorException
|
|
*/
|
|
public function bindResult(array $params)
|
|
{
|
|
|
|
if (!($this->stmt instanceof \PDOStatement) || ($this->stmt->errorCode() > 0)) {
|
|
throw new \ErrorException('Statement is not prepared or in error');
|
|
}
|
|
|
|
$numberMapping = FALSE;
|
|
foreach ($params as $key => $resultBinding) {
|
|
if (!is_array($resultBinding)) {
|
|
$numberMapping = TRUE;
|
|
if (!$this->stmt->bindColumn($key, $resultBinding)) {
|
|
throw new \ErrorException('At least one entry in the numeric column-binding array could not be bound');
|
|
}
|
|
} elseif ($numberMapping) {
|
|
throw new \ErrorException('Column-binding array is of mixed type. Array has to either contain sub-arrays with column-name - binding-reference structure or numeric array with only binding-reference');
|
|
} else {
|
|
if (count($resultBinding) !== 2) {
|
|
throw new \ErrorException('at least one sub-array of column-binding array does not have count 2');
|
|
}
|
|
if (!$this->stmt->bindColumn($resultBinding[0], $resultBinding[1])) {
|
|
throw new \ErrorException('At least one sub-array in column-binding array could not be bound');
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function startTransaction()
|
|
{
|
|
|
|
if (!$this->connectionObject->beginTransaction()) {
|
|
$this->errorState = TRUE;
|
|
$this->errorMessage .= print_r($this->connectionObject->errorInfo, 1) . ' || ';
|
|
return FALSE;
|
|
}
|
|
|
|
$this->stmt = NULL;
|
|
$this->result = NULL;
|
|
$this->errorState = FALSE;
|
|
$this->errorMessage = '';
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function commitTransaction()
|
|
{
|
|
|
|
if (!$this->connectionObject->commit()) {
|
|
$this->errorState = TRUE;
|
|
$this->errorMessage .= print_r($this->connectionObject->errorInfo, 1) . ' || ';
|
|
return FALSE;
|
|
}
|
|
|
|
$this->stmt = NULL;
|
|
$this->result = NULL;
|
|
$this->errorState = FALSE;
|
|
$this->errorMessage = '';
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function rollbackTransaction()
|
|
{
|
|
|
|
if (!$this->connectionObject->rollBack()) {
|
|
$this->errorState = TRUE;
|
|
$this->errorMessage .= print_r($this->connectionObject->errorInfo, 1) . ' || ';
|
|
return FALSE;
|
|
}
|
|
|
|
$this->stmt = NULL;
|
|
$this->result = NULL;
|
|
$this->errorState = FALSE;
|
|
$this->errorMessage = '';
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/**
|
|
* @return int
|
|
*/
|
|
public function getLastInsertId()
|
|
{
|
|
return $this->connectionObject->lastInsertId();
|
|
}
|
|
|
|
/**
|
|
* @return int
|
|
* @throws \ErrorException
|
|
*/
|
|
public function getNoOfAffectedRows()
|
|
{
|
|
|
|
if (!($this->stmt instanceof \PDOStatement) || ($this->stmt->errorCode() > 0)) {
|
|
throw new \ErrorException('Statement is not prepared or in error');
|
|
}
|
|
|
|
return $this->stmt->rowCount();
|
|
|
|
}
|
|
|
|
/**
|
|
* @return int
|
|
* @throws \ErrorException
|
|
*/
|
|
public function getNoOfReturnedRows()
|
|
{
|
|
|
|
if (is_array($this->result)) {
|
|
return count($this->result);
|
|
}
|
|
|
|
if(!($this->stmt instanceof \PDOStatement)) {
|
|
throw new \ErrorException('No Statement is set.');
|
|
}
|
|
if ($this->stmt->errorCode() > 0) {
|
|
throw new \ErrorException('Statement is in error. ' . print_r($this->stmt->errorInfo(),1));
|
|
}
|
|
|
|
if ($result = $this->stmt->fetchAll(PDO::FETCH_BOTH)) {
|
|
$this->result = $result;
|
|
return count($this->result);
|
|
}
|
|
|
|
if ($this->stmt->closeCursor() && $this->stmt->execute() && ($result = $this->stmt->fetchAll(PDO::FETCH_BOTH))) {
|
|
$this->result = $result;
|
|
return count($this->result);
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
* @throws \ErrorException
|
|
*/
|
|
public function getResultArray()
|
|
{
|
|
|
|
if (is_array($this->result) && (count($this->result) > 0)) {
|
|
return $this->result;
|
|
}
|
|
|
|
if ($this->stmt instanceof \PDOStatement) {
|
|
$result = $this->stmt->fetchAll(PDO::FETCH_BOTH);
|
|
if (is_array($result)) {
|
|
$this->result = $result;
|
|
return $this->result;
|
|
} else {
|
|
$this->stmt->closeCursor();
|
|
try {
|
|
$this->stmt->execute();
|
|
$result = $this->stmt->fetchAll();
|
|
if (count($result) > 0) {
|
|
$this->result = $result;
|
|
return $this->result;
|
|
}
|
|
} catch (\Exception $e) {
|
|
throw new \ErrorException('Result was not already set, fetchAll on $this->stmt didn\'t return a rowset, and resetting cursor and trying fetchAll again did not work');
|
|
}
|
|
}
|
|
}
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
* @throws \ErrorException
|
|
*/
|
|
public function getNextRow()
|
|
{
|
|
if (is_array($this->result) && is_array($this->result[$this->resultIndex])) {
|
|
$returnValue = $this->result[$this->resultIndex];
|
|
++$this->resultIndex;
|
|
return $returnValue;
|
|
}
|
|
if ($this->stmt instanceof \PDOStatement) {
|
|
if ($result = $this->stmt->fetchAll()) {
|
|
$this->result = $result;
|
|
++$this->resultIndex;
|
|
return $this->result[0];
|
|
}
|
|
$this->stmt->closeCursor();
|
|
try {
|
|
$this->stmt->execute();
|
|
$result = $this->stmt->fetchAll();
|
|
if (is_array($result) && (count($result) > 0)) {
|
|
++$this->resultIndex;
|
|
return $this->result[0];
|
|
}
|
|
} catch (\Exception $e) {
|
|
throw new \ErrorException('Result was not already set, fetchAll on $this->stmt didn\'t return a rowset, and resetting cursor and trying fetchAll again did not work');
|
|
}
|
|
}
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* @param string $string
|
|
*
|
|
* @return bool|string
|
|
*/
|
|
public function escapeString($string)
|
|
{
|
|
if (!($this->connectionObject instanceof \PDO)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return $this->connectionObject->quote($string);
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function closeStatement()
|
|
{
|
|
|
|
if (!($this->stmt instanceof \PDOStatement)) {
|
|
return FALSE;
|
|
}
|
|
$this->stmt->closeCursor();
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/**
|
|
* @return \PDO
|
|
*/
|
|
public function getConnectionObject()
|
|
{
|
|
return $this->connectionObject;
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function __sleep()
|
|
{
|
|
return array_diff(array_keys(get_object_vars($this)), array('connectionObject'));
|
|
}
|
|
|
|
public function __wakeup()
|
|
{
|
|
$pdo = new \PDO($this->dsn, $this->userName, $this->password, $this->optionsArray);
|
|
|
|
if (!$pdo->exec('SET NAMES utf8') || !$pdo->exec('SET CHARACTER SET utf8')) {
|
|
$pdoErrorInfo = $pdo->errorInfo();
|
|
$this->errorState = TRUE;
|
|
$this->errorMessage = print_r($pdoErrorInfo, 1);
|
|
}
|
|
|
|
$this->connectionObject = $pdo;
|
|
$this->errorState = FALSE;
|
|
$this->errorMessage = '';
|
|
}
|
|
|
|
/**
|
|
* @param $select
|
|
* @return $this
|
|
*/
|
|
public function select($select)
|
|
{
|
|
if (array_key_exists('lastElement',$this->unfinishedQuery) && null !== $this->unfinishedQuery['lastElement']) {
|
|
throw new \BadMethodCallException("'select' cannot be called if a query was already initialized." . print_r($this->unfinishedQuery,1));
|
|
}
|
|
if (!is_scalar($select) && !is_array($select)) {
|
|
throw new \InvalidArgumentException('The value entered is not a valid select expression. Only arrays and simple strings are allowed.');
|
|
}
|
|
if (is_array($select)) {
|
|
foreach ($select as $key => $selectExpression) {
|
|
if (!is_scalar($selectExpression)) {
|
|
throw new \InvalidArgumentException("Array-entry $key is not a valid select expression");
|
|
}
|
|
}
|
|
}
|
|
$this->unfinishedQuery['select'] = $select;
|
|
$this->unfinishedQuery['lastElement'] = 'select';
|
|
$this->unfinishedQuery['currJoinName'] = null;
|
|
$this->unfinishedQuery['join'] = [];
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $fromName
|
|
* @param string $fromAlias
|
|
* @return $this
|
|
*/
|
|
public function from($fromName, $fromAlias = '')
|
|
{
|
|
if ($this->unfinishedQuery['lastElement'] !== 'select') {
|
|
throw new \BadMethodCallException("'from' can only be called immediately after calling 'select'.");
|
|
}
|
|
if (!array_key_exists('select', $this->unfinishedQuery)) {
|
|
throw new \BadMethodCallException("'from' can only be called after 'select' has been called successfully.");
|
|
}
|
|
if (!is_scalar($fromName) || strip_tags($fromName) !== (string)$fromName) {
|
|
throw new \InvalidArgumentException('The given name is invalid.');
|
|
}
|
|
if (!is_scalar($fromAlias) || strip_tags($fromAlias) !== (string)$fromAlias) {
|
|
throw new \InvalidArgumentException('The given alias is invalid.');
|
|
}
|
|
$this->unfinishedQuery['from'][] = array('fromName' => $fromName, 'fromAlias' => $fromAlias);
|
|
$this->unfinishedQuery['lastElement'] = 'from';
|
|
$this->unfinishedQuery['currJoinName'] = null;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $joinType
|
|
* @param $joinName
|
|
* @param $joinAlias
|
|
* @return $this
|
|
*/
|
|
public function join($joinType, $joinName, $joinAlias)
|
|
{
|
|
if (!in_array($joinType, array('left', 'right', 'inner', 'straight'))) {
|
|
throw new \InvalidArgumentException("'joinType' must be either 'left', 'right', 'inner' or 'straight");
|
|
}
|
|
if (!in_array($this->unfinishedQuery['lastElement'], array('from', 'join', 'on', 'andOn', 'orOn'))) {
|
|
throw new \BadMethodCallException("'from' can only be called immediately after calling either 'from', 'join','on','andOn' or 'orOn'.");
|
|
}
|
|
if (!array_key_exists('select', $this->unfinishedQuery)) {
|
|
throw new \BadMethodCallException("'from' can only be called after 'select' has been called successfully.");
|
|
}
|
|
if (!is_scalar($joinName) || strip_tags($joinName) !== (string)$joinName) {
|
|
throw new \InvalidArgumentException('The given name is invalid.');
|
|
}
|
|
if (!is_scalar($joinAlias) || strip_tags($joinAlias) !== (string)$joinAlias) {
|
|
throw new \InvalidArgumentException('The given alias is invalid.');
|
|
}
|
|
$arr = array('joinType' => $joinType, 'joinName' => $joinName, 'joinAlias' => $joinAlias);
|
|
$this->unfinishedQuery['join'][$joinName] = $arr;
|
|
$this->unfinishedQuery['currJoinName'] = $joinName;
|
|
$this->unfinishedQuery['lastElement'] = 'join';
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $fieldName
|
|
* @param $operator
|
|
* @param null $fieldValue
|
|
* @param bool $fieldValueIsLiteral
|
|
* @return $this
|
|
*/
|
|
public function on($fieldName, $operator, $fieldValue = null, $fieldValueIsLiteral = false)
|
|
{
|
|
if (!isset($this->unfinishedQuery['currJoinName'])) {
|
|
throw new \BadMethodCallException('There is no join currently open.');
|
|
}
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('join', 'enterParen')))) {
|
|
throw new \BadMethodCallException("'on' can only be called immediately after calling 'join'.");
|
|
}
|
|
if (!in_array($operator, $this->allowedComparisonOperators)) {
|
|
throw new \InvalidArgumentException(strip_tags($operator) . " is not a valid comparison operator.");
|
|
}
|
|
if (!$this->comparisonValidation[$operator]($fieldName, $fieldValue)) {
|
|
throw new \InvalidArgumentException('The given Name and/or Value are not allowed for the given operator.');
|
|
}
|
|
|
|
$this->unfinishedQuery['lastElement'] = 'on';
|
|
if (!ctype_digit((string)$this->currQueryGroup)) {
|
|
$currJoinName = $this->unfinishedQuery['currJoinName'];
|
|
$currJoinRef = &$this->unfinishedQuery['join'][$currJoinName];
|
|
$currJoinRef['on']['ungrouped'][] = array('precedingOperator' => '', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
} else {
|
|
$currJoinName = $this->unfinishedQuery['currJoinName'];
|
|
$currJoinRef = &$this->unfinishedQuery['join'][$currJoinName];
|
|
$currJoinRef['on']['grouped'][$this->currQueryGroup][] = array('precedingOperator' => '', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $fieldName
|
|
* @param $operator
|
|
* @param null $fieldValue
|
|
* @param bool $fieldValueIsLiteral
|
|
* @return $this
|
|
*/
|
|
public function andOn($fieldName, $operator, $fieldValue = null, $fieldValueIsLiteral = false)
|
|
{
|
|
if (!isset($this->unfinishedQuery['currJoinName'])) {
|
|
throw new \BadMethodCallException('There is no join currently open.');
|
|
}
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('on', 'andOn', 'orOn')))) {
|
|
throw new \BadMethodCallException("'on' can only be called immediately after calling either 'on', 'andOn' or 'orOn'.");
|
|
}
|
|
if (!in_array($operator, $this->allowedComparisonOperators)) {
|
|
throw new \InvalidArgumentException(strip_tags($operator) . "is not a valid comparison operator.");
|
|
}
|
|
if (!$this->comparisonValidation[$operator]($fieldName, $fieldValue)) {
|
|
throw new \InvalidArgumentException('The given Name and/or Value are not allowed for the given operator.');
|
|
}
|
|
|
|
$this->unfinishedQuery['lastElement'] = 'andOn';
|
|
if (!ctype_digit((string)$this->currQueryGroup)) {
|
|
$currJoinName = $this->unfinishedQuery['currJoinName'];
|
|
$currJoinRef = &$this->unfinishedQuery['join'][$currJoinName];
|
|
$currJoinRef['on']['ungrouped'][] = array('precedingOperator' => 'AND', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
} else {
|
|
$currJoinName = $this->unfinishedQuery['currJoinName'];
|
|
$currJoinRef = &$this->unfinishedQuery['join'][$currJoinName];
|
|
$currJoinRef['on']['grouped'][$this->currQueryGroup][] = array('precedingOperator' => 'AND', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $fieldName
|
|
* @param $operator
|
|
* @param null $fieldValue
|
|
* @param bool $fieldValueIsLiteral
|
|
* @return $this
|
|
*/
|
|
public function orOn($fieldName, $operator, $fieldValue = null, $fieldValueIsLiteral = false)
|
|
{
|
|
if (!isset($this->unfinishedQuery['currJoinName'])) {
|
|
throw new \BadMethodCallException('There is no join currently open.');
|
|
}
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('on', 'andOn', 'orOn')))) {
|
|
throw new \BadMethodCallException("'on' can only be called immediately after calling either 'on', 'andOn' or 'orOn'.");
|
|
}
|
|
if (!in_array($operator, $this->allowedComparisonOperators)) {
|
|
throw new \InvalidArgumentException(strip_tags($operator) . "is not a valid comparison operator.");
|
|
}
|
|
if (!$this->comparisonValidation[$operator]($fieldName, $fieldValue)) {
|
|
throw new \InvalidArgumentException('The given Name and/or Value are not allowed for the given operator.');
|
|
}
|
|
|
|
$this->unfinishedQuery['lastElement'] = 'orOn';
|
|
if (!ctype_digit((string)$this->currQueryGroup)) {
|
|
$currJoinName = $this->unfinishedQuery['currJoinName'];
|
|
$currJoinRef = &$this->unfinishedQuery['join'][$currJoinName];
|
|
$currJoinRef['on']['ungrouped'][] = array('precedingOperator' => 'OR', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
} else {
|
|
$currJoinName = $this->unfinishedQuery['currJoinName'];
|
|
$currJoinRef = &$this->unfinishedQuery['join'][$currJoinName];
|
|
$currJoinRef['on']['grouped'][$this->currQueryGroup][] = array('precedingOperator' => 'OR', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $fieldName
|
|
* @param $operator
|
|
* @param null $fieldValue
|
|
* @param bool $fieldValueIsLiteral
|
|
* @return PDOQueryWrapper
|
|
*/
|
|
public function where($fieldName, $operator, $fieldValue = null, $fieldValueIsLiteral = true)
|
|
{
|
|
/*if(isset($this->currQueryGroup)) {
|
|
throw new \BadMethodCallException('A parenthesis needs to close before \'where\' can be called.');
|
|
}*/
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('from', 'join', 'on', 'andOn', 'orOn', 'leaveParen', 'enterParen')))) {
|
|
throw new \BadMethodCallException("'where' can only be called immediately after calling either 'from', 'join', 'on', 'andOn', 'orOn' or 'leaveParen'.");
|
|
}
|
|
if (!in_array($operator, $this->allowedComparisonOperators)) {
|
|
throw new \InvalidArgumentException(strip_tags($operator) . "is not a valid comparison operator.");
|
|
}
|
|
if (!$this->comparisonValidation[$operator]($fieldName, $fieldValue)) {
|
|
throw new \InvalidArgumentException('The given Name and/or Value are not allowed for the given operator.');
|
|
}
|
|
|
|
$this->unfinishedQuery['lastElement'] = 'where';
|
|
if (!ctype_digit((string)$this->currQueryGroup)) {
|
|
$this->unfinishedQuery['where']['ungrouped'][] = array('precedingOperator' => '', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
} else {
|
|
$this->unfinishedQuery['where']['grouped'][$this->currQueryGroup][] = array('precedingOperator' => '', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
}
|
|
$this->unfinishedQuery['currJoinName'] = null;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $fieldName
|
|
* @param $operator
|
|
* @param null $fieldValue
|
|
* @param bool $fieldValueIsLiteral
|
|
* @return PDOQueryWrapper
|
|
*/
|
|
public function andWhere($fieldName, $operator, $fieldValue = null, $fieldValueIsLiteral = true)
|
|
{
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('where', 'andWhere', 'orWhere')))) {
|
|
throw new \BadMethodCallException("'andWhere' can only be called immediately after calling either 'where', 'andWhere' or 'orWhere'.");
|
|
}
|
|
if (!in_array($operator, $this->allowedComparisonOperators)) {
|
|
throw new \InvalidArgumentException(strip_tags($operator) . "is not a valid comparison operator.");
|
|
}
|
|
if (!$this->comparisonValidation[$operator]($fieldName, $fieldValue)) {
|
|
throw new \InvalidArgumentException('The given Name and/or Value are not allowed for the given operator.');
|
|
}
|
|
|
|
$this->unfinishedQuery['lastElement'] = 'andWhere';
|
|
if (!ctype_digit((string)$this->currQueryGroup)) {
|
|
$this->unfinishedQuery['where']['ungrouped'][] = array('precedingOperator' => 'AND', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
} else {
|
|
$this->unfinishedQuery['where']['grouped'][$this->currQueryGroup][] = array('precedingOperator' => 'AND', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
}
|
|
$this->unfinishedQuery['currJoinName'] = null;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $fieldName
|
|
* @param $operator
|
|
* @param null $fieldValue
|
|
* @param bool $fieldValueIsLiteral
|
|
* @return PDOQueryWrapper
|
|
*/
|
|
public function orWhere($fieldName, $operator, $fieldValue = null, $fieldValueIsLiteral = true)
|
|
{
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('where', 'andWhere', 'orWhere')))) {
|
|
throw new \BadMethodCallException("'orWhere' can only be called immediately after calling either 'where', 'andWhere', 'on', 'andOn' or 'orOn' .");
|
|
}
|
|
if (!in_array($operator, $this->allowedComparisonOperators)) {
|
|
throw new \InvalidArgumentException(strip_tags($operator) . "is not a valid comparison operator.");
|
|
}
|
|
if (!$this->comparisonValidation[$operator]($fieldName, $fieldValue)) {
|
|
throw new \InvalidArgumentException('The given Name and/or Value are not allowed for the given operator.');
|
|
}
|
|
|
|
$this->unfinishedQuery['lastElement'] = 'orWhere';
|
|
if (!ctype_digit((string)$this->currQueryGroup)) {
|
|
$this->unfinishedQuery['where']['ungrouped'][] = array('precedingOperator' => 'OR', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
} else {
|
|
$this->unfinishedQuery['where']['grouped'][$this->currQueryGroup][] = array('precedingOperator' => 'OR', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue, 'valueIsLiteral' => (bool)$fieldValueIsLiteral);
|
|
}
|
|
$this->unfinishedQuery['currJoinName'] = null;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $expression
|
|
* @return PDOQueryWrapper
|
|
*/
|
|
public function groupBy($expression)
|
|
{
|
|
if (isset($this->currQueryGroup)) {
|
|
throw new \BadMethodCallException('A parenthesis needs to close before \'groupBy\' can be called.');
|
|
}
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('from', 'join', 'on', 'andOn', 'orOn', 'where', 'andWhere', 'orWhere', 'groupBy')))) {
|
|
throw new \BadMethodCallException("'groupBy' can only be called immediately after calling either 'from', 'join', 'on', 'andOn', 'orOn', 'where', 'andWhere', 'orWhere' or 'groupBy' .");
|
|
}
|
|
if (!is_scalar($expression) || (strip_tags($expression) !== (string)$expression)) {
|
|
throw new \InvalidArgumentException(strip_tags($expression) . ' is not a valid gorup-by expression.');
|
|
}
|
|
$this->unfinishedQuery['lastElement'] = 'groupBy';
|
|
$this->unfinishedQuery['groupBy'][] = $expression;
|
|
$this->unfinishedQuery['currJoinName'] = null;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $fieldName
|
|
* @param $operator
|
|
* @param null $fieldValue
|
|
* @return PDOQueryWrapper
|
|
*/
|
|
public function having($fieldName, $operator, $fieldValue = null)
|
|
{
|
|
if (isset($this->currQueryGroup)) {
|
|
throw new \BadMethodCallException('A parenthesis needs to close before \'having\' can be called.');
|
|
}
|
|
if (isset($this->currQueryGroup)) {
|
|
throw new \BadMethodCallException('A parenthesis needs to close before \'having\' can be called.');
|
|
}
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('groupBy', 'join', 'on', 'andOn', 'orOn')))) {
|
|
throw new \BadMethodCallException("'having' can only be called immediately after calling either 'groupBy', 'join', 'on', 'andOn' or 'orOn' .");
|
|
}
|
|
if (!in_array($operator, $this->allowedComparisonOperators)) {
|
|
throw new \InvalidArgumentException(strip_tags($operator) . "is not a valid comparison operator.");
|
|
}
|
|
if (!$this->comparisonValidation[$operator]($fieldName, $fieldValue)) {
|
|
throw new \InvalidArgumentException('The given Name and/or Value are not allowed for the given operator.');
|
|
}
|
|
|
|
$this->unfinishedQuery['lastElement'] = 'having';
|
|
if (!ctype_digit((string)$this->currQueryGroup)) {
|
|
$this->unfinishedQuery['having']['ungrouped'][] = array('precedingOperator' => '', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue);
|
|
} else {
|
|
$this->unfinishedQuery['having']['grouped'][$this->currQueryGroup][] = array('precedingOperator' => '', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue);
|
|
}
|
|
$this->unfinishedQuery['currJoinName'] = null;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $fieldName
|
|
* @param $operator
|
|
* @param null $fieldValue
|
|
* @return PDOQueryWrapper
|
|
*/
|
|
public function andHaving($fieldName, $operator, $fieldValue = null)
|
|
{
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('having', 'andHaving', 'orHaving')))) {
|
|
throw new \BadMethodCallException("'andHaving' can only be called immediately after calling either 'having', 'andHaving' or 'orHaving'.");
|
|
}
|
|
if (!in_array($operator, $this->allowedComparisonOperators)) {
|
|
throw new \InvalidArgumentException(strip_tags($operator) . "is not a valid comparison operator.");
|
|
}
|
|
if (!$this->comparisonValidation[$operator]($fieldName, $fieldValue)) {
|
|
throw new \InvalidArgumentException('The given Name and/or Value are not allowed for the given operator.');
|
|
}
|
|
|
|
$this->unfinishedQuery['lastElement'] = 'andHaving';
|
|
if (!ctype_digit((string)$this->currQueryGroup)) {
|
|
$this->unfinishedQuery['having']['ungrouped'][] = array('precedingOperator' => 'AND', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue);
|
|
} else {
|
|
$this->unfinishedQuery['having']['grouped'][$this->currQueryGroup][] = array('precedingOperator' => 'AND', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue);
|
|
}
|
|
$this->unfinishedQuery['currJoinName'] = null;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $fieldName
|
|
* @param $operator
|
|
* @param null $fieldValue
|
|
* @return PDOQueryWrapper
|
|
*/
|
|
public function orHaving($fieldName, $operator, $fieldValue = null)
|
|
{
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('having', 'andHaving', 'orHaving')))) {
|
|
throw new \BadMethodCallException("'orHaving' can only be called immediately after calling either 'having', 'andHaving' or 'orHaving'.");
|
|
}
|
|
if (!in_array($operator, $this->allowedComparisonOperators)) {
|
|
throw new \InvalidArgumentException(strip_tags($operator) . "is not a valid comparison operator.");
|
|
}
|
|
if (!$this->comparisonValidation[$operator]($fieldName, $fieldValue)) {
|
|
throw new \InvalidArgumentException('The given Name and/or Value are not allowed for the given operator.');
|
|
}
|
|
|
|
$this->unfinishedQuery['lastElement'] = 'andHaving';
|
|
if (!ctype_digit((string)$this->currQueryGroup)) {
|
|
$this->unfinishedQuery['having']['ungrouped'][] = array('precedingOperator' => 'OR', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue);
|
|
} else {
|
|
$this->unfinishedQuery['having']['grouped'][$this->currQueryGroup][] = array('precedingOperator' => 'OR', 'fieldName' => $fieldName, 'operator' => $operator, 'fieldValue' => $fieldValue);
|
|
}
|
|
$this->unfinishedQuery['currJoinName'] = null;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $expression
|
|
* @param $order
|
|
* @return PDOQueryWrapper
|
|
*/
|
|
public function orderBy($expression, $order)
|
|
{
|
|
if (!isset($this->unfinishedQuery['lastElement']) || (!in_array($this->unfinishedQuery['lastElement'], array('from', 'join', 'on', 'andOn', 'orOn', 'where', 'andWhere', 'orWhere', 'groupBy', 'orderBy','leaveParen')))) {
|
|
throw new \BadMethodCallException("'orderBy' can only be called immediately after calling either 'from', 'join', 'on', 'andOn', 'orOn', 'where', 'andWhere', 'orWhere', 'groupBy','orderBy' or 'leaveParen'.");
|
|
}
|
|
if (!is_scalar($expression) || (strip_tags($expression) !== (string)$expression)) {
|
|
throw new \InvalidArgumentException(strip_tags($expression) . ' is not a valid order-by expression.');
|
|
}
|
|
if (strcasecmp($order, 'asc') === 0) {
|
|
$order = 'ASC';
|
|
} elseif (strcasecmp($order, 'desc') === 0) {
|
|
$order = 'DESC';
|
|
} else {
|
|
throw new \InvalidArgumentException('Paramter \'order\' must be \'asc\' or \'desc\' (not case sensitive).');
|
|
}
|
|
$this->unfinishedQuery['currJoinName'] = null;
|
|
$this->unfinishedQuery['lastElement'] = 'orderBy';
|
|
$this->unfinishedQuery['orderBy'][] = array('expression' => $expression, 'order' => $order);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param null $operator
|
|
* @return $this
|
|
*/
|
|
public function enterParentheses($operator = null)
|
|
{
|
|
if (isset($operator)) {
|
|
if (strcasecmp($operator, 'AND') === 0) {
|
|
$operator = 'AND';
|
|
} elseif (strcasecmp($operator, 'OR') === 0) {
|
|
$operator = 'OR';
|
|
} else {
|
|
throw new \InvalidArgumentException("Operator must be 'AND' or 'OR'.");
|
|
}
|
|
}
|
|
if (!isset($this->unfinishedQuery['lastElement']) || !in_array($this->unfinishedQuery['lastElement'], array('join', 'on', 'andOn', 'orOn', 'where', 'andWhere', 'orWhere', 'leaveParen'))) {
|
|
throw new \BadMethodCallException("Can only enter parantheses immediately after calling either 'join', 'on', 'andOn', 'orOn', 'where', 'andWhere','orWhere' or 'leaveParen.");
|
|
}
|
|
|
|
$newGroupIndex = 1;
|
|
if (isset($this->unfinishedQueryGroups) && is_array($this->unfinishedQueryGroups) && count($this->unfinishedQueryGroups) > 0) {
|
|
$newGroupIndex = (max(array_keys($this->unfinishedQueryGroups)) + 1);
|
|
}
|
|
$this->unfinishedQueryGroups[$newGroupIndex] = $operator;
|
|
|
|
$this->currQueryGroup = $newGroupIndex;
|
|
|
|
$this->unfinishedQuery['lastElement'] = 'enterParen';
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return $this
|
|
*/
|
|
public function leaveParentheses()
|
|
{
|
|
if (!ctype_digit((string)$this->currQueryGroup)) {
|
|
throw new \BadMethodCallException("Can only leave parantheses if parentheses were set.");
|
|
}
|
|
$newGroupIndex = ($this->currQueryGroup - 1);
|
|
$this->currQueryGroup = $newGroupIndex;
|
|
if ($newGroupIndex <= 1) {
|
|
$this->currQueryGroup = null;
|
|
}
|
|
$this->unfinishedQuery['lastElement'] = 'leaveParen';
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function getConstructedQuery()
|
|
{
|
|
if (!isset($this->unfinishedQuery)) {
|
|
throw new \BadMethodCallException('Query has not been constructed yet.');
|
|
}
|
|
|
|
//Evaluate Select-part
|
|
$query = 'SELECT ';
|
|
$query .= $this->unfinishedQuery['select'];
|
|
$query .= ' FROM ';
|
|
$i = 0;
|
|
|
|
//Evaluate From-part
|
|
foreach ($this->unfinishedQuery['from'] as $fromPart) {
|
|
if ($i > 0) {
|
|
$query .= ', ';
|
|
}
|
|
$query .= $fromPart['fromName'] . ' ';
|
|
if (isset($fromPart['fromAlias'])) {
|
|
$query .= $fromPart['fromAlias'] . ' ';
|
|
}
|
|
++$i;
|
|
}
|
|
|
|
//Evaluate Join-part
|
|
foreach ($this->unfinishedQuery['join'] as $joinPart) {
|
|
$joinType = 'LEFT JOIN ';
|
|
if ($joinPart['joinType'] === 'right') {
|
|
$joinType = 'RIGHT JOIN ';
|
|
} elseif ($joinPart['joinType'] === 'straight') {
|
|
$joinType = 'STRAIGHT_JOIN ';
|
|
}
|
|
$query .= $joinType . $joinPart['joinName'] . ' ';
|
|
if (isset($joinPart['joinAlias'])) {
|
|
$query .= $joinPart['joinAlias'] . ' ';
|
|
}
|
|
if (is_array($joinPart['on'])) {
|
|
$query .= 'ON (';
|
|
if (isset($joinPart['on']['ungrouped']) && is_array($joinPart['on']['ungrouped'])) {
|
|
foreach ($joinPart['on']['ungrouped'] as $onCondition) {
|
|
$precedingOperator = $onCondition['precedingOperator'];
|
|
$fieldName = $onCondition['fieldName'];
|
|
$operator = $onCondition['operator'];
|
|
$valueIsLiteral = $onCondition['valueIsLiteral'];
|
|
$fieldValue = '';
|
|
if (isset($onCondition['fieldValue'])) {
|
|
$fieldValue = (($valueIsLiteral) ? $this->escapeString($onCondition['fieldValue']) : $onCondition['fieldValue']);
|
|
}
|
|
$query .= ' ' . $precedingOperator . ' (' . $fieldName . ' ' . $operator . ' ' . $fieldValue . ') ';
|
|
++$i;
|
|
}
|
|
}
|
|
if (isset($joinPart['on']['grouped']) && is_array($joinPart['on']['grouped'])) {
|
|
$i = 0;
|
|
foreach ($joinPart['on']['grouped'] as $groupKey => $groupArr) {
|
|
$connector = (($i > 0) || (isset($joinPart['on']['ungrouped']) && is_array($joinPart['on']['ungrouped']))) ? $this->unfinishedQueryGroups[$groupKey] : '';
|
|
$query .= " $connector (";
|
|
foreach ($joinPart['on']['grouped'][$groupKey] as $onCondition) {
|
|
$precedingOperator = $onCondition['precedingOperator'];
|
|
$fieldName = $onCondition['fieldName'];
|
|
$operator = $onCondition['operator'];
|
|
$valueIsLiteral = $onCondition['valueIsLiteral'];
|
|
$fieldValue = '';
|
|
if (isset($onCondition['fieldValue'])) {
|
|
$fieldValue = (($valueIsLiteral) ? $this->escapeString($onCondition['fieldValue']) : $onCondition['fieldValue']);
|
|
}
|
|
$query .= ' ' . $precedingOperator . ' (' . $fieldName . ' ' . $operator . ' ' . $fieldValue . ') ';
|
|
}
|
|
$query .= ') ';
|
|
++$i;
|
|
}
|
|
}
|
|
$query .= ') ';
|
|
}
|
|
}
|
|
//Evaluate Where-part
|
|
if (array_key_exists('where',$this->unfinishedQuery) && is_array($this->unfinishedQuery['where'])) {
|
|
$query .= ' WHERE ';
|
|
if (array_key_exists('ungrouped',$this->unfinishedQuery['where']) && is_array($this->unfinishedQuery['where']['ungrouped'])) {
|
|
foreach ($this->unfinishedQuery['where']['ungrouped'] as $whereCondition) {
|
|
$precedingOperator = $whereCondition['precedingOperator'];
|
|
$fieldName = $whereCondition['fieldName'];
|
|
$operator = $whereCondition['operator'];
|
|
$valueIsLiteral = $whereCondition['valueIsLiteral'];
|
|
$fieldValue = '';
|
|
if (isset($whereCondition['fieldValue'])) {
|
|
$fieldValue = (($valueIsLiteral) ? $this->escapeString($whereCondition['fieldValue']) : $whereCondition['fieldValue']);
|
|
}
|
|
$query .= ' ' . $precedingOperator . ' (' . $fieldName . ' ' . $operator . ' ' . $fieldValue . ') ';
|
|
}
|
|
}
|
|
if (isset($this->unfinishedQuery['where']['grouped']) && is_array($this->unfinishedQuery['where']['grouped'])) {
|
|
$i = 0;
|
|
$hasWhereUngrouped = array_key_exists('ungrouped',$this->unfinishedQuery['where']) && is_array($this->unfinishedQuery['where']['ungrouped']);
|
|
foreach ($this->unfinishedQuery['where']['grouped'] as $groupKey => $groupArr) {
|
|
$connector = (($i > 0) || $hasWhereUngrouped) ? $this->unfinishedQueryGroups[$groupKey] : '';
|
|
$query .= " $connector (";
|
|
foreach ($this->unfinishedQuery['where']['grouped'][$groupKey] as $whereCondition) {
|
|
$precedingOperator = $whereCondition['precedingOperator'];
|
|
$fieldName = $whereCondition['fieldName'];
|
|
$operator = $whereCondition['operator'];
|
|
$valueIsLiteral = $whereCondition['valueIsLiteral'];
|
|
$fieldValue = '';
|
|
if (isset($whereCondition['fieldValue'])) {
|
|
$fieldValue = (($valueIsLiteral) ? $this->escapeString($whereCondition['fieldValue']) : $whereCondition['fieldValue']);
|
|
}
|
|
$query .= ' ' . $precedingOperator . ' (' . $fieldName . ' ' . $operator . ' ' . $fieldValue . ') ';
|
|
}
|
|
$query .= ')';
|
|
++$i;
|
|
}
|
|
}
|
|
}
|
|
//Evaluate Group-By-part
|
|
if (isset($this->unfinishedQuery['groupBy']) && is_array($this->unfinishedQuery['groupBy'])) {
|
|
$query .= ' GROUP BY ';
|
|
$i = 0;
|
|
foreach ($this->unfinishedQuery['groupBy'] as $groupExp) {
|
|
if ($i > 0) {
|
|
$query .= ', ';
|
|
}
|
|
$query .= $groupExp;
|
|
++$i;
|
|
}
|
|
}
|
|
//Evaluate Having-part
|
|
if (isset($this->unfinishedQuery['having']) && is_array($this->unfinishedQuery['having'])) {
|
|
$query .= ' HAVING ';
|
|
foreach ($this->unfinishedQuery['having']['ungrouped'] as $havingCondition) {
|
|
$precedingOperator = $havingCondition['precedingOperator'];
|
|
$fieldName = $havingCondition['fieldName'];
|
|
$operator = $havingCondition['operator'];
|
|
$valueIsLiteral = $havingCondition['valueIsLiteral'];
|
|
$fieldValue = '';
|
|
if (isset($havingCondition['fieldValue'])) {
|
|
$fieldValue = (($valueIsLiteral) ? $this->escapeString($havingCondition['fieldValue']) : $havingCondition['fieldValue']);
|
|
}
|
|
$fieldValue = (($havingCondition['fieldValue']) ? "'{$havingCondition['fieldValue']}'" : null);
|
|
$query .= ' ' . $precedingOperator . ' (' . $fieldName . ' ' . $operator . ' ' . $fieldValue . ') ';
|
|
}
|
|
foreach ($this->unfinishedQuery['having']['grouped'] as $groupKey => $groupArr) {
|
|
$connector = $this->unfinishedQueryGroups[$groupKey];
|
|
$query .= " $connector (";
|
|
foreach ($this->unfinishedQuery['having']['grouped'][$groupKey] as $havingCondition) {
|
|
$precedingOperator = $havingCondition['precedingOperator'];
|
|
$fieldName = $havingCondition['fieldName'];
|
|
$operator = $havingCondition['operator'];
|
|
$valueIsLiteral = $havingCondition['valueIsLiteral'];
|
|
$fieldValue = '';
|
|
if (isset($havingCondition['fieldValue'])) {
|
|
$fieldValue = (($valueIsLiteral) ? $this->escapeString($havingCondition['fieldValue']) : $havingCondition['fieldValue']);
|
|
}
|
|
$query .= ' ' . $precedingOperator . ' (' . $fieldName . ' ' . $operator . ' ' . $fieldValue . ') ';
|
|
}
|
|
$query .= ') ';
|
|
}
|
|
$query .= ') ';
|
|
}
|
|
|
|
//Evaluate Order-By-part
|
|
if (array_key_exists('orderBy',$this->unfinishedQuery) && is_array($this->unfinishedQuery['orderBy'])) {
|
|
$query .= ' ORDER BY ';
|
|
$i = 0;
|
|
foreach ($this->unfinishedQuery['orderBy'] as $groupExpArr) {
|
|
$expression = $groupExpArr['expression'];
|
|
$order = $groupExpArr['order'];
|
|
if ($i > 0) {
|
|
$query .= ', ';
|
|
}
|
|
$query .= $expression . ' ' . $order;
|
|
++$i;
|
|
}
|
|
}
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* @return $this
|
|
*/
|
|
public function setConstructedQuery()
|
|
{
|
|
$this->setQuery($this->getConstructedQuery());
|
|
unset($this->unfinishedQuery);
|
|
return $this;
|
|
}
|
|
|
|
|
|
protected function _setComparisonValidationArray()
|
|
{
|
|
$arr = array(
|
|
'IS NULL' => function ($name, $value = null) {
|
|
return (is_scalar($name) && (strip_tags($name) === (string)$name));
|
|
},
|
|
'IS NOT NULL' => function ($name, $value = null) {
|
|
return (is_scalar($name) && (strip_tags($name) === (string)$name));
|
|
},
|
|
'=' => function ($name, $value) {
|
|
return (is_scalar($name) && is_scalar($value) && (strip_tags($name) === (string)$name) && (strip_tags($value) === (string)$value));
|
|
},
|
|
'!=' => function ($name, $value) {
|
|
return (is_scalar($name) && is_scalar($value) && (strip_tags($name) === (string)$name) && (strip_tags($value) === (string)$value));
|
|
},
|
|
'<' => function ($name, $value) {
|
|
return (is_scalar($name) && is_scalar($value) && (strip_tags($name) === (string)$name) && (strip_tags($value) === (string)$value));
|
|
},
|
|
'>' => function ($name, $value) {
|
|
return (is_scalar($name) && is_scalar($value) && (strip_tags($name) === (string)$name) && (strip_tags($value) === (string)$value));
|
|
},
|
|
'>=' => function ($name, $value) {
|
|
return (is_scalar($name) && is_scalar($value) && (strip_tags($name) === (string)$name) && (strip_tags($value) === (string)$value));
|
|
},
|
|
'<=' => function ($name, $value) {
|
|
return (is_scalar($name) && is_scalar($value) && (strip_tags($name) === (string)$name) && (strip_tags($value) === (string)$value));
|
|
},
|
|
'IN' => function ($name, $value) {
|
|
return (is_scalar($name) && (strip_tags($name) === (string)$name) && ((is_scalar($value) && (strip_tags($value) === (string)$value)) || (is_array($value) && array_depth($value) === 1)));
|
|
},
|
|
'LIKE' => function ($name, $value) {
|
|
return (is_scalar($name) && is_scalar($value) && (strip_tags($name) === (string)$name) && (strip_tags($value) === (string)$value));
|
|
}
|
|
);
|
|
$this->comparisonValidation = $arr;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function inTransaction()
|
|
{
|
|
return $this->connectionObject->inTransaction();
|
|
}
|
|
|
|
/**
|
|
* @param array $arr
|
|
* @param $tableName
|
|
* @param $updateOrInsert
|
|
* @return string
|
|
*/
|
|
public function getUpdateInsertQueryFromArray(array $arr, $tableName, $updateOrInsert)
|
|
{
|
|
$strIsUpdate = (strcasecmp($updateOrInsert, 'update') === 0);
|
|
$strIsInsert = (strcasecmp($updateOrInsert, 'insert') === 0);
|
|
if (!(strlen($tableName) > 0)) {
|
|
throw new \InvalidArgumentException("Parameter 'tableName' must not be empty.");
|
|
}
|
|
if (!$strIsInsert && !$strIsUpdate) {
|
|
throw new \InvalidArgumentException('Parameter \'updateOrInsert\' must be a either \'update\' or \'insert\'');
|
|
}
|
|
if ($strIsUpdate && (!array_key_exists('id', $arr) || !($arr['id'] > 0))) {
|
|
throw new \InvalidArgumentException('id-field must be set in array for update operation');
|
|
} elseif ($strIsInsert && array_key_exists('id', $arr) && $arr['id'] > 0) {
|
|
throw new \InvalidArgumentException('id-field must not be set to a positive value for insert operation');
|
|
}
|
|
|
|
if ($strIsUpdate) {
|
|
$id = (int)$arr['id'];
|
|
$updateInsertSnippet = "UPDATE `$tableName` ";
|
|
$whereIDSnippet = " WHERE (`id` = $id)";
|
|
} else {
|
|
$updateInsertSnippet = "INSERT INTO `$tableName` ";
|
|
$whereIDSnippet = '';
|
|
}
|
|
$query = $updateInsertSnippet . 'SET ';
|
|
$i = 0;
|
|
foreach ($arr as $fieldName => $fieldValue) {
|
|
if ($fieldName !== 'id') {
|
|
if($i > 0) {
|
|
$query .= ',';
|
|
}
|
|
if(is_bool($fieldValue)) { $fieldValue = (int)$fieldValue;}
|
|
elseif(is_float($fieldValue)) { $fieldValue = number_format($fieldValue,4,'.','');}
|
|
elseif(is_string($fieldValue)) {$fieldValue = $this->connectionObject->quote($fieldValue);}
|
|
$fieldValue = (string)$fieldValue;
|
|
if('' === $fieldValue) { $fieldValue = '\'\'';}
|
|
$query .= "`$fieldName` = $fieldValue";
|
|
$i++;
|
|
}
|
|
}
|
|
$query .= $whereIDSnippet;
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* @param $tableName
|
|
* @param $id
|
|
* @return string
|
|
*/
|
|
public function getDeleteQueryForID($tableName, $id)
|
|
{
|
|
if (!(strlen($tableName) > 0)) {
|
|
throw new \InvalidArgumentException("Parameter 'tableName' must not be empty.");
|
|
}
|
|
$id = (int)$id;
|
|
if (!($id > 0)) {
|
|
throw new \InvalidArgumentException("Parameter 'id' must be a positive integer.");
|
|
}
|
|
$query = "DELETE FROM `$tableName` WHERE id = $id";
|
|
return $query;
|
|
}
|
|
|
|
/**
|
|
* @param $objName
|
|
* @param array $constructorArgFields
|
|
* @return mixed
|
|
*/
|
|
public function getResultRowAsObject($objName, array $constructorArgFields = [])
|
|
{
|
|
if(!$this->stmt instanceof \PDOStatement) {
|
|
throw new \RuntimeException('No PDOStatement for query. Cannot execute.');
|
|
}
|
|
|
|
$obj = $this->stmt->fetchObject($objName,$constructorArgFields);
|
|
return $obj;
|
|
}
|
|
|
|
/**
|
|
* @param $objName
|
|
* @param array $constructorArgFields
|
|
* @return array
|
|
*/
|
|
public function getAllResultRowAsArrayOfObjects($objName, array $constructorArgFields = [])
|
|
{
|
|
if(!$this->stmt instanceof \PDOStatement) {
|
|
throw new \RuntimeException('No PDOStatement for query. Cannot execute.');
|
|
}
|
|
$objArr = $this->stmt->fetchAll(PDO::FETCH_CLASS,$objName);
|
|
return $objArr;
|
|
}
|
|
} |