Files
web-site/Internal/package-database/DB.php
T
2026-07-01 16:44:17 +03:00

3307 lines
74 KiB
PHP

<?php namespace ZN\Database;
/**
* ZN PHP Web Framework
*
* "Simplicity is the ultimate sophistication." ~ Da Vinci
*
* @package ZN
* @license MIT [http://opensource.org/licenses/MIT]
* @author Ozan UYKUN [ozan@znframework.com]
*/
use ZN\Base;
use ZN\Config;
use ZN\Datatype;
use ZN\Singleton;
use ZN\Request\URI;
use ZN\Request\Method;
use ZN\Protection\Json;
use ZN\DataTypes\Arrays;
use ZN\Filesystem\Converter;
use ZN\Database\Exception\UnconditionalException;
use ArrayObject;
#[\AllowDynamicProperties]
class DB extends Connection
{
/**
* Vartype Elements
*
* @var array
*/
protected $vartypeElements =
[
'int' , 'smallint', 'tinyint' , 'mediumint', 'bigint',
'decimal' , 'double' , 'float' ,
'char' , 'varchar' ,
'tinytext', 'text' , 'mediumtext', 'longtext' ,
'date' , 'time' , 'timestamp' , 'datetime' ,
'integer' => 'int'
];
/**
* Statement Elements
*
* @var array
*/
protected $statementElements =
[
'autoincrement', 'primarykey', 'foreignkey', 'unique',
'null' , 'notnull' ,
'exists' , 'notexists' ,
'constraint'
];
/**
* Function Elements
*
* @var array
*/
protected $functionElements =
[
'ifnull' , 'nullif' , 'abs' , 'mod' , 'asin' ,
'acos' , 'atan' , 'atan2' , 'ceil' , 'ceiling' ,
'cos' , 'cot' , 'crc32' , 'degrees' , 'exp' ,
'floor' , 'ln' , 'log10' , 'log2' , 'log' ,
'pi' , 'pow' , 'power' , 'radians' , 'rand' ,
'round' , 'sign' , 'sin' , 'sqrt' , 'tan' ,
'ascii' , 'field' , 'format' , 'lower' , 'upper' ,
'length' , 'ltrim' , 'substring', 'ord' , 'position' ,
'quote' , 'repeat' , 'rtrim' , 'soundex' , 'space' ,
'substr' , 'trim' , 'ucase' , 'lcase' , 'benchmark',
'charset', 'coercibility', 'user' , 'collation', 'database' ,
'schema' , 'avg' , 'min' , 'max' , 'count' ,
'sum' , 'variance' ,
'ifelse' => 'IF' ,
'charlength' => 'CHAR_LENGTH' ,
'substringindex' => 'SUBSTRING_INDEX',
'connectionid' => 'CONNECTION_ID' ,
'currentuser' => 'CURRENT_USER' ,
'lastinsertid' => 'LAST_INSERT_ID' ,
'systemuser' => 'SYSTEM_USER' ,
'sessionuser' => 'SESSION_USER' ,
'rowcount' => 'ROW_COUNT' ,
'versioninfo' => 'VERSION'
];
/*
|--------------------------------------------------------------------------
| Scalar Variables
|--------------------------------------------------------------------------
|
| Definitions of scaled of variables.
|
*/
private $select , $where , $distinct , $highPriority, $lowPriority ;
private $delayed , $procedure , $outFile , $characterSet, $into ;
private $forUpdate , $quick , $ignore , $partition , $straightJoin ;
private $smallResult, $bigResult , $bufferResult , $cache , $calcFoundRows;
private $groupBy , $having , $orderBy , $limit , $join ;
private $transStart , $transError , $duplicateCheck , $duplicateCheckUpdate ;
private $joinType , $joinTable , $unionQuery = NULL, $caching = [], $jsonDecode ;
private $hashId , $hashIdColumn, $isUpdate = false , $unset = [], $object ;
private $preselect , $results , $returnQueryType , $paging = 'row' ;
/**
* Callable talking queries.
*/
use CallableTalkingQueries;
public function preselect($preselect)
{
$this->preselect = $preselect . ' ';
return $this;
}
/**
* Defines SQL SELECT
*
* @param string ...$condition
*
* @return DB
*/
public function select(...$condition) : DB
{
if( empty($condition[0]) )
{
$condition[0] = '*';
}
$condition = rtrim(implode(',', array_map(function($value)
{
return preg_replace_callback('/(?<database>\w+\.)*(?<table>\w+\.\w+)/', function($data)
{
return $data['database'] . $this->prefix . $data['table'];
}, $value);
}, $condition)), ',');
$this->select = ' '.$condition.' ';
return $this;
}
/**
* Defines SQL WHERE
*
* @param mixed $column
* @param string $value = NULL
* @param string $logical = NULL
*
* @return DB
*/
public function where($column, $value = NULL, ?string $logical = NULL) : DB
{
$this->buildWhereHavingClause($column, $value, $logical, __FUNCTION__);
return $this;
}
/**
* Defines SQL WHERE
*
* @param mixed $column
* @param string $value = NULL
*
* @return DB
*/
public function whereAnd($column, $value = NULL) : DB
{
$this->where($column, $value, 'AND');
return $this;
}
/**
* Defines SQL WHERE
*
* @param mixed $column
* @param string $value = NULL
*
* @return DB
*/
public function whereOr($column, $value = NULL) : DB
{
$this->where($column, $value, 'OR');
return $this;
}
/**
* WHERE NULL OR EMPTY
*
* @param mixed $column
* @param string $logical = NULL
*
* @return DB
*/
public function whereEmpty($column, ?string $logical = NULL) : DB
{
$group[] = ['exp:' . $column, '""', 'or'];
$group[] = ['exp:' . $column . ' is', 'null'];
if( $logical !== NULL )
{
$group[] = $logical;
}
$this->whereGroup(...$group);
return $this;
}
/**
* WHERE NOT [NULL AND EMPTY]
*
* @param mixed $column
* @param string $logical = NULL
*
* @return DB
*/
public function whereNotEmpty($column, ?string $logical = NULL) : DB
{
$group[] = ['exp:' . $column . ' !=', '""', 'and'];
$group[] = ['exp:' . $column . ' is not', 'null'];
if( $logical !== NULL )
{
$group[] = $logical;
}
$this->whereGroup(...$group);
return $this;
}
/**
* WHERE NULL
*
* @param mixed $column
* @param string $logical = NULL
*
* @return DB
*/
public function whereNull($column, ?string $logical = NULL) : DB
{
$this->where('exp:' . $column . ' is', 'null', $logical);
return $this;
}
/**
* WHERE NOT NULL
*
* @param mixed $column
* @param string $logical = NULL
*
* @return DB
*/
public function whereNotNull($column, ?string $logical = NULL) : DB
{
$this->where('exp:' . $column . ' is', 'not null', $logical);
return $this;
}
/**
* Defines SQL WHERE
*
* @param mixed $column
* @param string $value = NULL
* @param string $logical = NULL
*
* @return DB
*/
public function whereNot($column, $value = NULL, ?string $logical = NULL) : DB
{
$this->where($column . ' != ', $value, $logical);
return $this;
}
/**
* Defines SQL WHERE JSON_SEARCH IS NOT NULL
*
* @param mixed $column
* @param string $value = NULL
* @param string $logical = NULL
*
* @return DB
*/
public function whereJson($column, $value = NULL, ?string $logical = NULL) : DB
{
$this->specialDefinedWhere($column, $value, $logical, __FUNCTION__);
return $this;
}
/**
* Defines SQL WHERE JSON_SEARCH IS NULL
*
* @param mixed $column
* @param string $value = NULL
* @param string $logical = NULL
*
* @return DB
*/
public function whereNotJson($column, $value = NULL, ?string $logical = NULL) : DB
{
$this->specialDefinedWhere($column, $value, $logical, __FUNCTION__);
return $this;
}
/**
* Full Text
*
* 5.7.4[added]
*
* @param string $column
* @param string $value
* @param string $type = NULL
*
* @return string
*/
public function whereFullText($column, $value = NULL, ?string $type = NULL, ?string $logical = NULL) : DB
{
$this->where('exp:' . $this->db->fullText($column, $this->escapeStringAddNail($value), $type), '', $logical);
return $this;
}
/**
* Defines SQL WHERE BETWEEN value1 and value2
*
* @param mixed $column
* @param string $value1 = NULL
* @param string $value2 = NULL
* @param string $logical = NULL
*
* @return DB
*/
public function whereBetween($column, ?string $value1 = NULL, ?string $value2 = NULL, ?string $logical = NULL) : DB
{
$this->where($column . ' between', $this->between($value1, $value2), $logical);
return $this;
}
/**
* Defines SQL WHERE LIKE %value%
*
* @param mixed $column
* @param string $value = NULL
* @param string $logical = NULL
*
* @return DB
*/
public function whereLike($column, $value = NULL, ?string $logical = NULL) : DB
{
$this->where($column . ' like', $this->like($value, 'inside'), $logical);
return $this;
}
/**
* Defines SQL WHERE LIKE value%
*
* @param mixed $column
* @param string $value = NULL
* @param string $logical = NULL
*
* @return DB
*/
public function whereStartLike($column, $value = NULL, ?string $logical = NULL) : DB
{
$this->where($column . ' like', $this->like($value, 'starting'), $logical);
return $this;
}
/**
* Defines SQL WHERE LIKE %value
*
* @param mixed $column
* @param string $value = NULL
* @param string $logical = NULL
*
* @return DB
*/
public function whereEndLike($column, $value = NULL, ?string $logical = NULL) : DB
{
$this->where($column . ' like', $this->like($value, 'ending'), $logical);
return $this;
}
/**
* Defines SQL WHERE IN(...$values)
*
* @param mixed $column
* @param array $values = []
* @param string $logical = NULL
*
* @return DB
*/
public function whereIn($column, array $values = [], ?string $logical = NULL) : DB
{
$this->where($column . ' in', $this->in(...$values), $logical);
return $this;
}
/**
* Defines SQL WHERE NOT IN(...$values)
*
* @param mixed $column
* @param array $values = []
* @param string $logical = NULL
*
* @return DB
*/
public function whereNotIn($column, array $values = [], ?string $logical = NULL) : DB
{
$this->where($column . ' not in', $this->notIn(...$values), $logical);
return $this;
}
/**
* Defines SQL WHERE IN(SELECT * FROM $table)
*
* @param mixed $column
* @param string $table
* @param string $logical = NULL
*
* @return DB
*/
public function whereInTable($column, string $table, ?string $logical = NULL) : DB
{
$this->where($column . ' in', $this->inTable($table), $logical);
return $this;
}
/**
* Defines SQL WHERE IN(SELECT * FROM $table)
*
* @param mixed $column
* @param string $table
* @param string $logical = NULL
*
* @return DB
*/
public function whereInQuery($column, string $table, ?string $logical = NULL) : DB
{
$this->where($column . ' in', $this->inQuery($table), $logical);
return $this;
}
/**
* Defines SQL WHERE
*
* @param array ...$args
*
* @return DB
*/
public function whereGroup(...$args) : DB
{
$this->where .= $this->whereHavingGroup($args);
return $this;
}
/**
* Having Group
*
* @param array ...$args
*
* @return DB
*/
public function havingGroup(...$args) : DB
{
$this->having .= $this->whereHavingGroup($args);
return $this;
}
/**
* Defines SQL HAVING
*
* @param mixed $column
* @param string $value = NULL
* @param string $logical = NULL
*
* @return DB
*/
public function having($column, $value = NULL, ?string $logical = NULL) : DB
{
$this->buildWhereHavingClause($column, $value, $logical, __FUNCTION__);
return $this;
}
/**
* Caching Query
*
* @param string $time
* @param string $driver = NULL
*
* @return DB
*/
public function caching($time, ?string $driver = NULL) : DB
{
$this->caching['time'] = $time;
$this->caching['driver'] = $driver ?? $this->config['cacheDriver'] ?? 'file';
return $this;
}
/**
* Clean Cache
*
* @param string $driver = 'file'
*
* @return bool
*/
public function cleanCaching(string $driver = 'file') : bool
{
return Singleton::class('ZN\Cache\Processor')->driver($this->caching['driver'] ?? $driver)->delete($this->getEncryptedCacheQuery());
}
/**
* Join table
*
* @param string $table
* @param string $condition
* @param string $type = NULL
*
* @return DB
*/
public function join(string $table, string $condition, ?string $type = NULL) : DB
{
$tableEx = explode('.', $table);
switch( count($tableEx) )
{
case 2:
$table = $tableEx[0] . '.' . $this->prefix . $tableEx[1];
break;
case 1:
$table = $this->prefix.$table;
break;
}
$type = strtoupper((string) $type);
$this->joinType = $type;
$this->joinTable = $table;
$this->join .= ' '.$type.' JOIN '.$table.' ON '.$condition.' ';
return $this;
}
/**
* Inner Join
*
* @param string $mainTableAndColumn
* @param string $otherTableAndColumn
* @param string $operator = '='
*
* @return DB
*/
public function innerJoin(string $table, string $otherColumn, string $operator = '=') : DB
{
$this->buildJoinClause($table, $otherColumn, $operator, 'INNER');
return $this;
}
/**
* Outer Join
*
* @param string $mainTableAndColumn
* @param string $otherTableAndColumn
* @param string $operator = '='
*
* @return DB
*/
public function outerJoin(string $table, string $otherColumn, string $operator = '=') : DB
{
$this->buildJoinClause($table, $otherColumn, $operator, 'FULL OUTER');
return $this;
}
/**
* Left Join
*
* @param string $mainTableAndColumn
* @param string $otherTableAndColumn
* @param string $operator = '='
*
* @return DB
*/
public function leftJoin(string $table, string $otherColumn, string $operator = '=') : DB
{
$this->buildJoinClause($table, $otherColumn, $operator, 'LEFT');
return $this;
}
/**
* Right Join
*
* @param string $mainTableAndColumn
* @param string $otherTableAndColumn
* @param string $operator = '='
*
* @return DB
*/
public function rightJoin(string $table, string $otherColumn, string $operator = '=') : DB
{
$this->buildJoinClause($table, $otherColumn, $operator, 'RIGHT');
return $this;
}
/**
* Group By
*
* @param string ...$args
*
* @return DB
*/
public function groupBy(...$args) : DB
{
$this->groupBy .= implode(',', $args).', ';
return $this;
}
/**
* Order By
*
* @param mixed $condition
* @param string $type = NULL
*
* @return DB
*/
public function orderBy($condition, ?string $type = NULL) : DB
{
if( is_string($condition) )
{
$this->orderBy .= $condition.' '.$type.', ';
}
else
{
if( ! empty($condition) ) foreach( $condition as $key => $val )
{
$this->orderBy .= $key.' '.$val.', ';
}
}
return $this;
}
/**
* Order By Field
*
* @param string $field
* @param array $values
*
* @return DB
*/
public function orderByField(string $field, array $values) : DB
{
$revalues = [];
foreach( $values as $value )
{
$revalues[] = $this->escapeStringAddNail($value ?? '', true);
}
return $this->orderBy('FIELD(' . $field . ', ' . implode(', ', $revalues) . ')');
}
/**
* Order By Random
*
* @return DB
*/
public function orderByRandom() : DB
{
return $this->orderBy('rand()');
}
/**
* Limit
*
* @param int $start = NULL
* @param int $limit = 0
*
* @return DB
*/
public function limit($start = NULL, int $limit = 0) : DB
{
if( $start < 0 )
{
$start = $this->paging(is_numeric($segment = URI::segment($start)) ? $segment : 1, $limit);
$this->paging = 'page';
}
else if( $start === NULL )
{
$start = URI::segment(-1);
}
$start = (int) $start;
$this->limit = $this->db->limit($start, $limit);
return $this;
}
/**
* protected paging
*/
protected function paging($start, $limit)
{
if( $start == 0 )
{
return 1; // @codeCoverageIgnore
}
return ($start - 1) * $limit;
}
/**
* Basic Query
*
* @return DB
*/
public function basic() : DB
{
$this->returnQueryType = 'basicQuery';
return $this;
}
/**
* Get Table
*
* @param string $table = NULL
* @param string $return = 'object' - Options['object'|'array'|'json']
*
* @return mixed
*/
public function get(?string $table = NULL, string $return = 'object')
{
$this->tableName = $table = $this->addPrefixForTableAndColumn($table, 'table');
$finalQuery = $this->preselect .
'SELECT ' .
$this->distinct . $this->highPriority . $this->straightJoin .
$this->smallResult. $this->bigResult . $this->bufferResult .
$this->cache . $this->calcFoundRows. $this->buildSelectClause() .
' FROM ' .
$table.' ' . $this->partition . $this->join .
$this->buildWhereClause() . $this->buildGroupByClause() . $this->buildHavingClause() .
$this->buildOrderByClause() . $this->limit . $this->procedure .
$this->outFile . $this->characterSet . $this->into .
$this->forUpdate;
if( $this->unionQuery !== NULL )
{
$finalQuery = $this->unionQuery . ' ' . $finalQuery;
$this->unionQuery = NULL;
}
$returnQuery = $this->returnQueryType ?? 'query';
$isString = $this->string === true || $return === 'string';
$finalQuery = $this->querySecurity($finalQuery, $isString);
$this->resetSelectQueryVariables();
if( $isString )
{
$this->string = NULL;
return $finalQuery;
}
if( $this->transaction === true )
{
$this->transactionQueries[] = $finalQuery;
return $this;
}
return $this->$returnQuery($finalQuery, $this->secure);
}
/**
* Duplicate Check
*
* @param string ...$args
*
* @return DB
*/
public function duplicateCheck(...$args) : DB
{
$this->duplicateCheck = $args;
if( empty($this->duplicateCheck) )
{
$this->duplicateCheck[0] = '*';
}
return $this;
}
/**
* Duplicate Check Update
*
* @param string ...$args
*
* @return DB
*/
public function duplicateCheckUpdate(...$args) : DB
{
$this->duplicateCheck(...$args);
$this->duplicateCheckUpdate = true;
return $this;
}
/**
* Real Escape String
*
* @param string $data
*
* @return string
*/
public function escapeString(string $data) : string
{
return $this->db->realEscapeString($data);
}
/**
* Real Escape String
*
* @param string $data
*
* @return string
*/
public function realEscapeString(string $data) : string
{
return $this->db->realEscapeString($data);
}
/**
* Get String Query
*
* @param string $table = NULL
*
* @return string
*/
public function getString(?string $table = NULL) : string
{
return $this->get($table, 'string');
}
/**
* Set aliases
*
* @param array $aliases
*
* @return self
*/
public function aliases(array $aliases)
{
$this->aliases = $aliases;
return $this;
}
/**
* Alias
*
* @param string $string
* @param string $alias
* @param bool $brackets = false
*
* @return string
*/
public function alias(string $string, string $alias, bool $brackets = false) : string
{
if( $brackets === true)
{
$string = $this->brackets($string);
}
return $string.' AS '.$alias;
}
/**
* Brackets
*
* @param string $string
*
* @return string
*/
public function brackets(string $string) : string
{
return ' ( '.$string.' ) ';
}
/**
* Defines SQL ALL
*
* @return DB
*/
public function all() : DB
{
$this->distinct = ' ALL ';
return $this;
}
/**
* Defines SQL DISTINCT
*
* @return DB
*/
public function distinct() : DB
{
$this->distinct = ' DISTINCT ';
return $this;
}
/**
* Defines SQL DISTINCTROW
*
* @return DB
*/
public function distinctRow() : DB
{
$this->distinct = ' DISTINCTROW ';
return $this;
}
/**
* Defines SQL STRAIGHT_JOIN
*
* @return DB
*/
public function straightJoin() : DB
{
$this->straightJoin = ' STRAIGHT_JOIN ';
return $this;
}
/**
* Defines SQL HIGH_PRIORITY
*
* @return DB
*/
public function highPriority() : DB
{
$this->highPriority = ' HIGH_PRIORITY ';
return $this;
}
/**
* Defines SQL LOW_PRIORITY
*
* @return DB
*/
public function lowPriority() : DB
{
$this->lowPriority = ' LOW_PRIORITY ';
return $this;
}
/**
* Defines SQL QUICK
*
* @return DB
*/
public function quick() : DB
{
$this->quick = ' QUICK ';
return $this;
}
/**
* Defines SQL DELAYED
*
* @return DB
*/
public function delayed() : DB
{
$this->delayed = ' DELAYED ';
return $this;
}
/**
* Defines SQL IGNORE
*
* @return DB
*/
public function ignore() : DB
{
$this->ignore = ' IGNORE ';
return $this;
}
/**
* Defines SQL PARTITION
*
* @param string ...$args
*
* @return DB
*/
public function partition(...$args) : DB
{
$this->partition = $this->setMathFunction(__FUNCTION__, $args)->args;
return $this;
}
/**
* Defines SQL PROCEDURE
*
* @param string ...$args
*
* @return DB
*/
public function procedure(...$args) : DB
{
$this->procedure = $this->setMathFunction(__FUNCTION__, $args)->args;
return $this;
}
/**
* Defines SQL INTO OUTFILE
*
* @param string $file
*
* @return DB
*/
public function outFile(string $file) : DB
{
$this->outFile = 'INTO OUTFILE '."'".$file."'".' ';
return $this;
}
/**
* Defines SQL INTO DUMPFILE
*
* @param string $file
*
* @return DB
*/
public function dumpFile(string $file) : DB
{
$this->into = 'INTO DUMPFILE '."'".$file."'".' ';
return $this;
}
/**
* Defines SQL REFERENCES table(column)
*
* 5.7.4[added]
*
* @return string
*/
public function references(string $table, string $column) : string
{
return $this->db->references($table, $column);
}
/**
* Foreign Key
*
* 5.7.4[added]
*
* @param string $column
* @param string $references
*
* @return string
*/
public function foreignKey($column = NULL, $references = NULL) : string
{
return $this->db->foreignKey($column, $references);
}
/**
* Defines SQL CHARACTER SET
*
* @param string $set
* @param bool $return = false
*
* @return mixed
*/
public function characterSet(string $set, bool $return = false)
{
$string = 'CHARACTER SET '.$set.' ';
if( $return === false )
{
$this->characterSet = $string;
return $this;
}
else
{
return $string;
}
}
/**
* Character Set
*
* @param string $set
*
* @return string
*/
public function cset(string $set) : string
{
if( empty($set) )
{
$set = $this->config['charset'];
}
return $this->characterSet($set, true);
}
/**
* Defines SQL COLLATE
*
* @param string $set
*
* @return string
*/
public function collate(?string $set = NULL) : string
{
if( empty($set) )
{
$set = $this->config['collation'];
}
return 'COLLATE '.$set.' ';
}
/**
* Sets encoding
*
* @param string $charset = 'utf8'
* @param string $collate = 'utf8_general_ci'
*
* @return string
*/
public function encoding(string $charset = 'utf8', string $collate = 'utf8_general_ci') : string
{
$encoding = $this->cset($charset);
$encoding .= $this->collate($collate);
return $encoding;
}
/**
* Defines SQL INTO
*
* @param string $varname1
* @param string $varname2
*
* @return DB
*/
public function into(string $varname1, ?string $varname2 = NULL) : DB
{
$this->into = 'INTO '.$varname1.' ';
if( ! empty($varname2) )
{
$this->into .= ', '.$varname2.' ';
}
return $this;
}
/**
* Defines SQL FOR UPDATE
*
* @return DB
*/
public function forUpdate() : DB
{
$this->forUpdate = ' FOR UPDATE ';
return $this;
}
/**
* Defines SQL LOCK IN SHARE MODE
*
* @return DB
*/
public function lockInShareMode() : DB
{
$this->forUpdate = ' LOCK IN SHARE MODE ';
return $this;
}
/**
* Defines SQL SQL_SMALL_RESULT
*
* @return DB
*/
public function smallResult() : DB
{
$this->smallResult = ' SQL_SMALL_RESULT ';
return $this;
}
/**
* Defines SQL SQL_BIG_RESULT
*
* @return DB
*/
public function bigResult() : DB
{
$this->bigResult = ' SQL_BIG_RESULT ';
return $this;
}
/**
* Defines SQL SQL_BUFFER_RESULT
*
* @return DB
*/
public function bufferResult() : DB
{
$this->bufferResult = ' SQL_BUFFER_RESULT ';
return $this;
}
/**
* Defines SQL SQL_CACHE
*
* @return DB
*/
public function cache() : DB
{
$this->cache = ' SQL_CACHE ';
return $this;
}
/**
* Defines SQL SQL_NO_CACHE
*
* @return DB
*/
public function noCache() : DB
{
$this->cache = ' SQL_NO_CACHE ';
return $this;
}
/**
* Defines SQL SQL_CALC_FOUND_ROWS
*
* @return DB
*/
public function calcFoundRows() : DB
{
$this->calcFoundRows = ' SQL_CALC_FOUND_ROWS ';
return $this;
}
/**
* Defines SQL UNION
*
* @param string $table = NULL
*
* @return DB
*/
public function union(?string $table = NULL, $name = 'UNION') : DB
{
$this->unionQuery .= $this->get($table, 'string') . ' ' . $name;
return $this;
}
/**
* Defines SQL UNION ALL
*
* @param string $table = NULL
*
* @return DB
*/
public function unionAll(?string $table = NULL) : DB
{
$this->union($table, 'UNION ALL');
return $this;
}
/**
* Json columns decoder
*
* @param variadic $columns
*
* @return DB
*/
public function jsonDecode(...$columns)
{
$this->jsonDecode = ! empty($columns) ? $columns : '*';
return $this;
}
/**
* Basic Query
*
* @param string $query
* @param array $secure = []
*
* @return DB
*/
public function query(string $query, array $secure = [])
{
$secure = $this->secure ?: $secure; $this->secure = [];
$caching = $this->caching; $this->caching = [];
$tableName = $this->tableName; $this->tableName = '';
$jsonDecode = $this->jsonDecode; $this->jsonDecode = [];
$paging = $this->paging;
return (new self($this->config))->setQueryByDriver($query, $secure,
[
'caching' => $caching,
'tableName' => $tableName,
'jsonDecode' => $jsonDecode,
'paging' => $paging
]);
}
/**
* Exec Basic Query
*
* @param string $query
* @param array $secure = []
*
* @return bool
*/
public function execQuery(string $query, array $secure = []) : bool
{
$this->secure = $this->secure ?: $secure;
return $this->db->exec($this->querySecurity($query), $this->secure);
}
/**
* Basic Query
*
* @param string $query
* @param array $secure = []
*
* @return DB
*/
public function basicQuery(string $query, array $secure = []) : DB
{
return $this->setQueryByDriver($query, $secure);
}
/**
* Trans Query
*
* @param string $query
* @param array $secure = []
*
* @return DB
*/
public function transQuery(string $query, array $secure = []) : DB
{
return $this->setQueryByDriver($query, $secure);
}
/**
* Multi Query
*
* @param string $query
* @param array $secure = []
*
* @return bool
*/
public function multiQuery(string $query, array $secure = []) : bool
{
$this->secure = $this->secure ?: $secure;
return $this->db->multiQuery($this->querySecurity($query), $this->secure);
}
/**
* Start transaction query
*
* @return DB
*/
public function transStart() : DB
{
$this->transStart = $this->db->transStart();
$this->transaction = true;
return $this;
}
/**
* End transaction query
*
* @return bool
*/
public function transEnd()
{
$this->runTransactionQueries();
if( ! empty($this->transError) )
{
$this->db->transRollback();
}
else
{
$this->db->transCommit();
}
$status = ! (bool) $this->transError;
$this->resetTransactionQueryVariables();
return $status;
}
/**
* Transaction queryies builder
*
* @param callback $callback
*
* @return bool
*/
public function transaction($callback) : bool
{
$this->transStart();
$this->transaction = true;
$callback();
$this->runTransactionQueries();
return $this->transEnd();
}
/**
* Get Insert ID
*
* @return int|string
*/
public function insertID()
{
return $this->db->insertId();
}
/**
* Set postgres driver returning id
*
* @param string $returningId
*
* @return self
*/
public function returningId(string $returningId)
{
Properties::$returningId = $returningId;
return $this;
}
/**
* Get table status
*
* @param string $table = NULL
*
* @return DB
*/
public function status(?string $table = NULL) : DB
{
$table = Base::presuffix($this->addPrefixForTableAndColumn($table), "'");
$query = "SHOW TABLE STATUS FROM " . $this->config['database'] . " LIKE $table";
$this->runQuery($query);
return $this;
}
/**
* Increment
*
* @param string $table = NULL
* @param mixed $columns = []
* @param int $increment = 1
*
* @return bool
*/
public function increment(?string $table = NULL, $columns = [], int $increment = 1)
{
return $this->setIncrementDecrement($table, $columns, $increment, 'increment');
}
/**
* Decrement
*
* @param string $table = NULL
* @param mixed $columns = []
* @param int $decrement = 1
*
* @return bool
*/
public function decrement(?string $table = NULL, $columns = [], int $decrement = 1)
{
return $this->setIncrementDecrement($table, $columns, $decrement, 'decrement');
}
/**
* Insert CSV
*
* @param string $table
* @param string $file
*
* @return bool
*/
public function insertCSV(string $table, string $file) : bool
{
$this->convertCSVData($file);
array_map(function($data) use($table)
{
$this->duplicateCheck()->insert(Base::prefix($table, 'ignore:'), $data);
}, $file);
return true;
}
/**
* Insert
*
* @param string $table = NULL
* @param array $datas = []
*
* @return bool
*/
public function insert(?string $table = NULL, array $datas = [])
{
if( isset($datas[0]) && is_array($datas[0]) )
{
$insertQuery = $this->multiInsert($table, $datas);
}
else
{
$this->isHashIdColumn($datas);
$this->ignoreData($table, $datas);
$datas = $this->addPrefixForTableAndColumn($datas, 'column');
$this->buildDataValuesQueryForInsert($datas, $data, $values, $duplicateCheckWhere);
$this->duplicateCheckProcess($duplicateCheckWhere, $table, $datas, $return);
if( isset($return) )
{
return $return;
}
$insertQuery = $this->buildInsertQuery($table, $data, $values);
}
$this->resetInsertQueryVariables();
if( $return = $this->runQuery($insertQuery) )
{
if( is_string($this->object) )
{
Properties::$returningId = $processColumn = $this->object; $this->object = NULL;
$insertId = $this->insertId(); Properties::$returningId = 'id';
return $this->where($processColumn, $insertId)->get($table)->row();
}
}
return $return;
}
/**
* Object
*
* @param string $processColumn = 'id'
*
* @return self
*/
public function object(string $processColumn = 'id')
{
$this->object = $processColumn;
return $this;
}
/**
* Unset
*
* @param variadic ...$argument
*
* @return self
*/
public function unset(...$columns)
{
$this->unset = $columns;
return $this;
}
/**
* Is update
*
* @return boolean
*/
public function isUpdate() : bool
{
return $this->isUpdate;
}
/**
* Set hash id column
*
* @param string $column
*
* @return self
*/
public function hashIdColumn(string $column)
{
$this->hashIdColumn = $column;
return $this;
}
/**
* Create hash id
*
* @param array $data
*
* @return string
*/
public function createHashId(array $data) : string
{
$output = '';
foreach( $data as $value )
{
$output .= json_encode($value);
}
$output .= microtime();
return md5($output);
}
/**
* Get hash Id
*
* @return string
*/
public function hashId()
{
return $this->hashId;
}
/**
* Update
*
* @param string $table = NULL
* @param array $datas = []
*
* @return bool
*/
public function update(?string $table = NULL, array $datas = [])
{
$this->ignoreData($table, $datas);
$datas = $this->addPrefixForTableAndColumn($datas, 'column');
$this->buildDataValuesQueryForUpdate($datas, $data);
$updateQuery = $this->buildUpdateQuery($table, $data, $where);
$this->resetUpdateQueryVariables();
if( $return = $this->runQuery($updateQuery) )
{
if( $this->object )
{
$this->object = NULL;
return $this->where('exp:' . str_ireplace('WHERE ', '', $where))->get($table)->row(-1);
}
}
return $return;
}
/**
* Delete
*
* @param string $table = NULL
*
* @return bool
*/
public function delete(?string $table = NULL)
{
if( empty($this->where) )
{
throw new UnconditionalException();
}
$deleteQuery = $this->buildDeleteQuery($table);
$this->resetDeleteQueryVariables();
return $this->runQuery($deleteQuery);
}
/**
* Get total rows
*
* @param bool $real = false
*
* @return int
*/
public function totalRows(bool $total = false) : int
{
if( $total === true )
{
return $this->query($this->db->cleanLimit($this->stringQuery()))->totalRows();
}
return $this->db->numRows();
}
/**
* Get total columns
*
* @return int
*/
public function totalColumns() : int
{
return $this->db->numFields();
}
/**
* Get columns
*
* @return array
*/
public function columns() : array
{
return $this->db->columns();
}
/**
* Get table result
*
* @param string $type = 'objects' - Options[object|array|json]
*
* @return mixed
*/
public function result(string $type = 'object', $usageRow = false)
{
$this->getCacheResult($type, $results);
if( empty($results) )
{
$results = $this->results = ($this->results ?? $this->db->result($type, $this->jsonDecode ?? NULL, $usageRow));
}
if( $type === 'json' )
{
return Json::encode($results);
}
return $results;
}
/**
* Get result json
*
* @return string
*/
public function resultJson() : string
{
return $this->result('json');
}
/**
* Get result array
*
* @return array
*/
public function resultArray() : array
{
return $this->result('array');
}
/**
* Get fetch array
*
* @return array
*/
public function fetchArray() : array
{
return $this->db->fetchArray();
}
/**
* Get fetch assoc
*
* @return array
*/
public function fetchAssoc() : array
{
return $this->db->fetchAssoc();
}
/**
* Get fetch array
*
* @param string $type = 'assoc' - Options[assoc|array|row]
*
* @return array
*/
public function fetch(string $type = 'assoc') : array
{
if( $type === 'assoc' )
{
return $this->db->fetchAssoc();
}
elseif( $type === 'array')
{
return $this->db->fetchArray();
}
else
{
return $this->db->fetchRow();
}
}
/**
* Get fetch row
*
* @param bool $printable = false
*
* @return mixed
*/
public function fetchRow(bool $printable = false)
{
$row = $this->db->fetchRow();
if( $printable === false )
{
return $row;
}
else
{
return current((array) $row);
}
}
/**
* Get table row
*
* @param mixed $printable = 0
*
* @return mixed
*/
public function row($printable = 0)
{
$result = $this->result('object', true);
if( $printable < 0 )
{
$index = count($result) + $printable;
return isset($result[$index]) ? (object) $result[$index] : false;
}
else
{
if( $printable === true )
{
$resultObject = new ArrayObject($result[0] ?? []);
return $resultObject->getIterator()->current();
}
return isset($result[$printable]) ? (object) $result[$printable] : false;
}
}
/**
* Get table column value
*
* @param string $column = NULL - added 5.6.5
*
* @return string
*/
public function value(?string $column = NULL)
{
if( preg_match('/[a-z]\w+/i', $column ?? '') )
{
return $this->row()->$column ?? false;
}
return $this->row(true);
}
/**
* Get affected rows
*
* @return int
*/
public function affectedRows() : int
{
return $this->db->affectedRows();
}
/**
* Column Data
*
* @param string $column = NULL
*
* @return array
*/
public function columnData(?string $column = NULL)
{
return $this->db->columnData($column);
}
/**
* Table Name
*
* @return string
*/
public function tableName() : string
{
return $this->tableName;
}
/**
* Pagination
*
* @param string $url = NULL
* @param array $settings = []
* @param bool $output = true
*
* @return string
*/
public function pagination(?string $url = NULL, array $settings = [], bool $output = true)
{
$pagcon = Config::get('ViewObjects', 'pagination');
$getLimit = $this->db->getLimitValues($this->stringQuery());
$start = $getLimit['start'] ?? NULL;
$limit = $getLimit['limit'] ?? NULL;
$settings['totalRows'] = $this->totalRows(true);
$settings['limit'] = ! empty($limit) ? $limit : $pagcon['limit'];
$settings['start'] = $start ?? $pagcon['start'];
$settings['paging'] = $this->paging;
if( $settings['paging'] === 'page' )
{
$settings['start'] = floor($settings['start'] / $settings['limit'] + 1);
}
if( ! empty($url) )
{
$settings['url'] = $url; // @codeCoverageIgnore
}
$return = $output === true
? Singleton::class('ZN\Pagination\Paginator')->create(NULL, $settings)
: $settings;
return $return;
}
/**
* Is Exists
*
* @param string $table
* @param string $column
* @param string $value
*
* @param bool
*/
public function isExists(string $table, string $column, string $value) : bool
{
return (bool) $this->where($column, $value)->get($table)->totalRows();
}
/**
* Simple Result
*
* @param string $table
* @param string $column = NULL
* @param string $value = NULL
*
* @return object
*/
public function simpleResult(string $table, ?string $column = NULL, $value = NULL, $type = 'result')
{
if( $column !== NULL && $value !== NULL )
{
$this->where($column, $value);
}
return $this->get($table)->$type();
}
/**
* Simple Result Array
*
* @param string $table
* @param string $column = NULL
* @param string $value = NULL
*
* @return array
*/
public function simpleResultArray(string $table, ?string $column = NULL, $value = NULL)
{
return $this->simpleResult($table, $column, $value, 'resultArray');
}
/**
* Simple Row
*
* @param string $table
* @param string $column = NULL
* @param string $value = NULLL
*
* @return object
*/
public function simpleRow(string $table, ?string $column = NULL, $value = NULL)
{
return $this->simpleResult($table, $column, $value, 'row');
}
/**
* Simple Total Rows
*
* @param string $table
*
* @return int
*/
public function simpleTotalRows(string $table) : int
{
return $this->simpleResult($table, NULL, NULL, 'totalRows');
}
/**
* Simple Total Columns
*
* @param string $table
*
* @return int
*/
public function simpleTotalColumns(string $table) : int
{
return $this->simpleResult($table, NULL, NULL, 'totalColumns');
}
/**
* Simple Columns
*
* @param string $table
*
* @return array
*/
public function simpleColumns(string $table) : array
{
return $this->simpleResult($table, NULL, NULL, 'columns');
}
/**
* Simple Column Data
*
* @param string $table
* @param string $column
*
* @return stdClass
*/
public function simpleColumnData(string $table, ?string $column = NULL) : \stdClass
{
return $this->get($table)->columnData($column);
}
/**
* Simple Update
*
* @param string $table
* @param string $data
* @param string $column
* @param string $value
*
* @return bool
*/
public function simpleUpdate(string $table, array $data, string $column, string $value)
{
return $this->where($column, $value)->update($table, $data);
}
/**
* Simple Delete
*
* @param string $table
* @param string $column
* @param string $value
*
* @return bool
*/
public function simpleDelete(string $table, string $column, string $value)
{
return $this->where($column, $value)->delete($table);
}
/**
* Switch Case
*
* @param string $switch
* @param array $conditions = []
* @param bool $return = false
*
* @return mixed
*/
public function switchCase(string $switch, array $conditions = [], bool $return = false)
{
$case = ' CASE '.$switch;
$alias = '';
if( isset($conditions['as']) )
{
$alias = ' as ' . $conditions['as'] . ' ';
unset($conditions['as']);
}
if( is_array($conditions) ) foreach( $conditions as $key => $val )
{
if( strtolower($key) === 'default' || strtolower($key) === 'else' )
{
$key = ' ELSE ';
}
else
{
$key = ' WHEN ' . $key . ' THEN ';
}
$case .= $key . $val;
}
$case .= ' END ' . $alias;
if( $return === true )
{
return $case;
}
else
{
$this->selectFunctions[] = $case;
return $this;
}
}
/**
* Vartype
*
* @param mixed $type
* @param string $len = NULL
* @param bool $output = true
*
* @return string
*/
public function vartype(string $type, ?int $len = NULL, bool $output = true) : string
{
return $this->db->variableTypes($type, $len, $output);
}
/**
* Property
*
* @param mixed $type
* @param string $col = NULL
* @param bool $output = true
*
* @return string
*/
public function property($type, ?string $col = NULL, bool $output = true) : string
{
if( is_array($type) )
{
$state = '';
foreach( $type as $key => $val )
{
if( ! is_numeric($key) )
{
$state .= $this->db->statements($key, $val);
}
else
{
$state .= $this->db->statements($val);
}
}
return $state;
}
else
{
return $this->db->statements($type, $col, $output);
}
}
/**
* Defines SQL DEFAULT
*
* @param string $default = NULL
* @param string $bool = false
*
* @return string
*/
public function defaultValue(?string $default = NULL, bool $type = false) : string
{
if( ! is_numeric($default) )
{
$default = Base::presuffix($default, '"');
}
return $this->db->statements('default', $default, $type);
}
/**
* Defines SQL LIKE Operators
*
* @param string $value
* @param string $type = 'starting' - Options[starting|ending|inside]
*
* @return string
*/
public function like(string $value, string $type = 'starting') : string
{
$operator = $this->db->operator(__FUNCTION__);
if( $type === "inside" )
{
$value = $operator.$value.$operator;
}
// İle Başlayan
if( $type === "starting" )
{
$value = $value.$operator;
}
// İle Biten
if( $type === "ending" )
{
$value = $operator.$value;
}
return $value;
}
/**
* Defines SQL BETWEEN
*
* @param string $value1
* @param string $value2
*
* @return string
*/
public function between(string $value1, string $value2) : string
{
return $this->escapeStringAddNail($value1, true).' AND '.$this->escapeStringAddNail($value2, true);
}
/**
* Defines SQL NOT IN
*
* @param string ...$value
*
* @return string
*/
public function notIn(...$value) : string
{
return $this->buildInClause('in', ...$value);
}
/**
* Defines SQL IN
*
* @param string ...$value
*
* @return string
*/
public function in(...$value) : string
{
return $this->buildInClause(__FUNCTION__, ...$value);
}
/**
* protected IN Table
*
* @param string ...$value
*
* @return string
*/
public function inTable(...$value) : string
{
return $this->buildInClause(__FUNCTION__, ...$value);
}
/**
* protected IN Query
*
* @param string ...$value
*
* @return string
*/
public function inQuery(...$value) : string
{
return $this->buildInClause(__FUNCTION__, ...$value);
}
/**
* protected is hash id column
*/
protected function isHashIdColumn(&$datas)
{
$this->hashId = NULL;
if( $this->hashIdColumn )
{
$this->hashId = $datas[$this->hashIdColumn] = $this->createHashId($datas);
$this->hashIdColumn = NULL;
}
}
/**
* protected build insert query
*/
protected function buildInsertQuery($table, $data, $values)
{
return 'INSERT '.
$this->lowPriority.
$this->delayed.
$this->highPriority.
$this->ignore.
' INTO '.
$this->addPrefixForTableAndColumn($table).
$this->partition.
$this->buildInsertValuesClause($data, $values) .
$this->db->getInsertExtrasByDriver();
}
/**
* protected duplicate check process
*/
protected function duplicateCheckProcess($duplicateCheckWhere, $table, $datas, &$return = NULL)
{
$this->isUpdate = false;
if( ! empty($duplicateCheckWhere) && $this->where($duplicateCheckWhere)->count('*')->get($table)->value() )
{
$this->duplicateCheck = NULL; $return = false;
if( $this->duplicateCheckUpdate === true )
{
$this->duplicateCheckUpdate = NULL;
$this->isUpdate = true;
$return = $this->where($duplicateCheckWhere)->update($table, $datas);
}
}
}
/**
* protected build data values query
*/
protected function buildDataValuesQueryForInsert($datas, &$data, &$values, &$duplicateCheckWhere)
{
$data = ''; $values = ''; $duplicateCheckWhere = [];
foreach( $datas as $key => $value )
{
if( $this->isExpressionExists($key) )
{
$key = $this->clearExpression($key); $isExp = true;
}
$this->isNonscalarValueEncodeJson($value);
$data .= Base::suffix($key, ',');
if( ! empty($this->duplicateCheck) && ($this->duplicateCheck[0] === '*' || in_array($key, $this->duplicateCheck)) )
{
$duplicateCheckWhere[] = [$key . ' = ', $value, 'and'];
}
$value = $this->nailEncode($value);
if( isset($isExp) )
{
$values .= Base::suffix($value, ','); unset($isExp);
}
else
{
$values .= Base::suffix(Base::presuffix($value, "'"), ',');
}
}
}
/**
* protected multi insert
*/
protected function multiInsert($table, $datas)
{
$data = $datas[0]; unset($datas[0]);
$query = $this->string()->insert($table, $data);
foreach( $datas as $values )
{
$value = '';
foreach( $values as $val )
{
$value .= Base::suffix(Base::presuffix($this->nailEncode($val), "'"), ',');
}
$query .= ', (' . rtrim($value, ',') . ')';
}
return Base::suffix($query, ';');
}
/**
* protected build data values query for update
*/
protected function buildDataValuesQueryForUpdate($datas, &$data)
{
$data = '';
foreach( $datas as $key => $value )
{
$this->isNonscalarValueEncodeJson($value);
$value = $this->nailEncode($value);
if( $this->isExpressionExists($key) )
{
$key = $this->clearExpression($key); // @codeCoverageIgnore
}
else
{
$value = Base::presuffix($value, "'");
}
$data .= $key . '=' . Base::suffix($value, ',');
}
}
/**
* protected build update query
*/
protected function buildUpdateQuery($table, $data, &$where = NULL)
{
$where = $this->buildWhereClause();
return 'UPDATE '.
$this->lowPriority.
$this->ignore.
$this->addPrefixForTableAndColumn($table).
$this->join.
' SET ' . substr($data, 0, -1) .
$where.
$this->buildOrderByClause().
$this->limit .
$this->db->getInsertExtrasByDriver();
}
/**
* protected build delete query
*/
protected function buildDeleteQuery($table)
{
return 'DELETE '.
$this->lowPriority.
$this->quick.
$this->ignore.
$this->deleteJoinTables($table).
' FROM '.
$this->addPrefixForTableAndColumn($table).
$this->join.
$this->partition.
$this->buildWhereClause().
$this->buildOrderByClause().
$this->limit;
}
/**
* protected run transaction queries
*/
protected function runTransactionQueries()
{
if( $this->transactionQueries )
{
foreach( $this->transactionQueries as $query )
{
$this->transQuery($query);
}
}
}
/**
* protected special defined where
*/
protected function specialDefinedWhere($column, $value = NULL, ?string $logical = NULL, $type = 'whereJson')
{
$this->where('exp:' . $this->db->$type($column, $this->escapeStringAddNail((string) $value)), '', $logical, 'where');
}
/**
* protected IN
*
* @param string $type = 'in'
* @param string ...$value
*
* @return string
*/
protected function buildInClause($type = 'in', ...$value)
{
$query = '(';
$type = strtolower($type);
foreach( $value as $val )
{
if( $type === 'in' )
{
$query .= $this->escapeStringAddNail($val, true);
}
elseif( $type === 'intable' )
{
$query .= $this->getString($val);
}
else
{
$query .= $val;
}
$query .= ',';
}
return rtrim($query, ',') . ')';
}
/**
* protected is nonscalar value encode json
*/
protected function isNonscalarValueEncodeJson(&$value)
{
if( ! is_scalar($value) )
{
$value = Json::encode($value);
}
}
/**
* protected Select
*
* @return string
*/
protected function buildSelectClause()
{
if( ! empty($this->selectFunctions) )
{
$selectFunctions = rtrim(implode(',', $this->selectFunctions), ',');
if( empty($this->select) )
{
$this->select = $selectFunctions;
}
else
{
$this->select .= ',' . $selectFunctions; // @codeCoverageIgnore
}
}
if( empty($this->select) )
{
$this->select = ' * ';
}
return $this->select;
}
/**
* protected Values
*
* @param string $data
* @param string $values
*
* @return string
*/
protected function buildInsertValuesClause($data, $values)
{
return ' ('.rtrim($data, ',').') VALUES ('.rtrim($values, ',').')';
}
/**
* protected Result Cache
*
* @param string $type
*/
protected function getCacheResult($type, &$results = [])
{
if( ! empty($this->caching) )
{
$driver = $this->caching['driver'] ?? 'file';
$cache = Singleton::class('ZN\Cache\Processor');
if( $cacheResult = $cache->driver($driver)->select($this->getEncryptedCacheQuery()) )
{
$results = $cacheResult; // @codeCoverageIgnore
}
else
{
$cache->driver($driver)->insert($this->getEncryptedCacheQuery(), $results = $this->db->result($type), $this->caching['time'] ?? 0);
}
}
}
/**
* protected Ignore Data
*
* @param string & $table
* @param string & $data
*/
protected function ignoreData(&$table, &$data)
{
$table = $table ?? '';
$methods = ['ignore', 'post', 'get', 'request'];
if( stristr($table, ':') )
{
$tableEx = explode(':', $table);
$method = $tableEx[0];
$table = $tableEx[1];
if( in_array($method, $methods) )
{
if( $method !== 'ignore' )
{
$data = Method::$method();
}
$columns = array_flip($this->setQueryByDriver('SELECT * FROM ' . $table . ' LIMIT 1')->columns());
$data = array_intersect_key($data, $columns);
$this->unsetData($data);
}
}
}
/**
* protected unset data
*/
protected function unsetData(&$data)
{
# The ID column is removed by default.
if( $find = preg_grep('/(^(id)$)/i', array_keys($data)) )
{
$id = current($find); unset($data[$id]);
}
# The columns you specified are removed.
if( ! empty($this->unset) )
{
foreach( $this->unset as $column )
{
unset($data[$column]);
}
$this->unset = [];
}
}
/**
* protected CSV
*
* @param string & $data
*/
protected function convertCSVData(&$data)
{
$csv = Converter::CSVToArray($data);
$csvColumn = $csv[0];
array_shift($csv);
$csvDatas = $csv;
$data = array_map(function($d) use($csvColumn)
{
return array_combine($csvColumn, $d);
}, $csvDatas);
}
/**
* protected Delete Join Tables
*
* @param string $table
*
* @return string
*/
protected function deleteJoinTables($table)
{
if( $this->join )
{
$joinType = strtolower($this->joinType ?? '');
if( $joinType === 'inner' )
{
$joinTables = $this->addPrefixForTableAndColumn($table) . ', ' . $this->joinTable; // @codeCoverageIgnore
}
elseif( $joinType === 'right' )
{
$joinTables = $this->joinTable; // @codeCoverageIgnore
}
else
{
$joinTables = $this->addPrefixForTableAndColumn($table);
}
$this->joinType = NULL;
$this->joinTable = NULL;
return Base::presuffix($joinTables, ' ');
}
return NULL;
}
/**
* protected Where Key Control
*
* @param string $column
* @param string $value
*
* @return string
*/
protected function whereKeyControl($column, $value)
{
$keys = ['between', 'in'];
$column = trim($column);
if( in_array(strtolower(Datatype::divide($column, ' ', -1)), $keys) || $this->isExpressionExists($column) )
{
return $value;
}
return $this->escapeStringAddNail($value);
}
/**
* protected Equal Control
*
* @param string $column
*
* @return string
*/
protected function setEqualClause($column)
{
$column = $column ?? ''; $control = trim($column);
if( strstr($column, '.') )
{
$control = str_replace('.', '', $control);
}
if( preg_match('/^\w+$/', $control) )
{
$column .= ' = ';
}
return $column;
}
/**
* protected Where Having
*
* @param mixed $column
* @param string $value
* @param string $logical
*
* @return string
*/
protected function whereHaving($column, $value, $logical)
{
if( $value !== '' )
{
$value = $this->whereKeyControl($column, $value);
}
$this->convertVartype($column, $value);
$column = $this->setEqualClause($column);
return ' '.$this->tablePrefixColumnControl($column).' '.$value.' '.$logical.' ';
}
/**
* protected Where
*
* @param mixed $column
* @param string $value
* @param string $logical
* @param string $type = 'where'
*
* @return DB
*/
protected function buildWhereHavingClause($column, $value, $logical, $type = 'where')
{
if( is_array($column) )
{
$columns = func_get_args();
if( isset($columns[0][0]) && is_array($columns[0][0]) )
{
$columns = $columns[0];
}
foreach( $columns as $col )
{
if( is_array($col) )
{
$c = $col[0] ?? '';
$v = $col[1] ?? '';
$l = $col[2] ?? 'and';
$this->$type .= $this->whereHaving($c, $v, $l);
}
}
}
else
{
$this->$type .= $this->whereHaving($column, $value, $logical ?: 'and');
}
return $this;
}
/**
* protected Where Having Group
*
* @param array $condition = []
*
* @return string
*/
protected function whereHavingGroup($conditions = [])
{
$con = [];
// @codeCoverageIgnoreStart
if( isset($conditions[0][0]) && is_array($conditions[0][0]) )
{
$con = Arrays\GetElement::last($conditions);
$conditions = $conditions[0];
}
// @codeCoverageIgnoreEnd
$getLast = Arrays\GetElement::last($conditions);
if( is_string($con) )
{
$conjunction = $con; // @codeCoverageIgnore
}
else
{
if( is_string($getLast) )
{
$conjunction = $getLast;
array_pop($conditions);
}
else
{
$conjunction = 'and';
}
}
$whereGroup = '';
if( is_array($conditions) ) foreach( $conditions as $column )
{
$col = $column[0] ?? '';
$value = $column[1] ?? '';
$logical = $column[2] ?? 'and';
$whereGroup .= $this->whereHaving($col, $value, $logical);
}
return ' ( '.$this->whereHavingConjuctionClean($whereGroup).' ) '.$conjunction.' ';
}
/**
* protected Where Having Conjuction Control
*
* @param string $type
*
* @return string
*/
protected function whereHavingConjuctionControl($type)
{
if( ! empty($this->$type) )
{
$this->$type = $this->whereHavingConjuctionClean($this->$type) ?: $this->$type;
$return = ' '.strtoupper($type).' '.$this->$type;
$this->$type = NULL;
return $return;
}
}
/**
* protected Where Having Conjuction Clean
*
* @param string $str
*
* @return string
*
* @codeCoverageIgnore
*/
protected function whereHavingConjuctionClean($str)
{
if( ! empty($str) )
{
$str = strtolower($orgstr = trim($str));
switch( substr($str, -3) )
{
case 'and' :
case 'xor' :
case 'not' :
return substr($orgstr, 0, -3);
}
switch( substr($str, -2) )
{
case 'or' :
case '||' :
case '&&' :
return substr($orgstr, 0, -2);
}
switch( substr($str, -1) )
{
case '!' :
return substr($orgstr, 0, -1);
}
}
return $str;
}
/**
* protected Where
*
* @return string
*/
protected function buildWhereClause()
{
return $this->whereHavingConjuctionControl('where');
}
/**
* protected Having
*
* @return string
*/
protected function buildHavingClause()
{
return $this->whereHavingConjuctionControl('having');
}
/**
* protected Join
*
* @param string $tableAndColumn = ''
* @param string $otherColumn = ''
* @param string $operator = '='
* @param string $type = 'INNER'
*
* @param object
*/
protected function buildJoinClause($tableAndColumn = '', $otherColumn = '', $operator = '=', $type = 'INNER')
{
$condition = $this->tablePrefixColumnControl($tableAndColumn, $table).' '.
$operator.' '.
$this->tablePrefixColumnControl($otherColumn).' ';
$this->join($table, $condition, $type);
}
/**
* protected Table Prefix Column Control
*
* @param string $column
* @param string & $table = NULL
*
* @return string
*/
protected function tablePrefixColumnControl($column, &$table = NULL)
{
$column = explode('.', $column);
# For table
switch( $count = count($column) )
{
case 3 : $table = $column[0] . '.' . $column[1]; break;
case 1 :
case 2 :
default: $table = $column[0]; break;
}
# For column
switch( $count )
{
case 2 : return $this->prefix . $column[0] . '.' . $column[1];
case 3 : return $column[0] . '.' . $this->prefix . $column[1] . '.' . $column[2];
case 1 :
default: return $column[0];
}
}
/**
* protected Group By
*
* @return mixed
*/
protected function buildGroupByClause()
{
if( ! empty($this->groupBy) )
{
return ' GROUP BY '.rtrim($this->groupBy, ', ');
}
return false;
}
/**
* protected Order By
*
* @return mixed
*/
protected function buildOrderByClause()
{
if( ! empty($this->orderBy) )
{
return ' ORDER BY '.rtrim($this->orderBy, ', ');
}
return false;
}
/**
* protected Increment & Decrement
*
* @param string $table
* @param array $columns
* @param int $incdec
* @param string $type
*
* @return bool
*/
protected function setIncrementDecrement($table, $columns, $incdec, $type)
{
$newColumns = [];
$table = $this->addPrefixForTableAndColumn($table);
$columns = $this->addPrefixForTableAndColumn($columns, 'column');
$incdec = $type === 'increment' ? abs($incdec) : -abs($incdec);
if( is_array($columns) ) foreach( $columns as $v )
{
$newColumns[$v] = "$v + $incdec";
}
else
{
$newColumns = [$columns => "$columns + $incdec"];
}
$data = '';
foreach( $newColumns as $key => $value )
{
$data .= $key.'='.$value.',';
}
$set = ' SET '.substr($data, 0, -1);
$updateQuery = 'UPDATE '.$this->prefix.$table.$set.$this->buildWhereClause();
$this->where = NULL;
if( $this->string === true )
{
return $updateQuery; // @codeCoverageIgnore
}
if( $this->transaction === true )
{
$this->transactionQueries[] = $updateQuery; // @codeCoverageIgnore
return $this; // @codeCoverageIgnore
}
return $this->db->query($updateQuery);
}
/**
* Query
*
* @param string $query
* @param array $secure = []
* @param mixed $data = NULL
*
* @return DB
*/
public function setQueryByDriver(string $query, array $secure = [], $data = NULL)
{
$this->stringQuery = $query;
$this->caching = $data['caching'] ?? [];
$this->tableName = $data['tableName'] ?? '';
$this->jsonDecode = $data['jsonDecode'] ?? [];
$this->paging = $data['paging'];
if( empty($this->caching) || ! Singleton::class('ZN\Cache\Processor')->select($this->getEncryptedCacheQuery()) )
{
$this->secure = $this->secure ?: $secure;
$this->db->query($this->querySecurity($query), $secure);
if( ! empty($this->transStart) )
{
$transError = $this->db->error();
if( ! empty($transError) )
{
$this->transError = $transError;
}
}
}
return $this;
}
/**
* protected Cache Query
*
* @return string
*/
protected function getEncryptedCacheQuery()
{
return md5(Json::encode($this->config) . $this->stringQuery());
}
/**
* protected reset transaction query variables
*/
protected function resetTransactionQueryVariables()
{
$this->transStart = NULL;
$this->transError = NULL;
$this->transaction = false;
$this->transactionQueries = [];
}
/**
* protected Select Reset Query
*/
protected function resetSelectQueryVariables()
{
$this->distinct = NULL;
$this->highPriority = NULL;
$this->straightJoin = NULL;
$this->smallResult = NULL;
$this->bigResult = NULL;
$this->bufferResult = NULL;
$this->cache = NULL;
$this->calcFoundRows = NULL;
$this->preselect = NULL;
$this->select = NULL;
$this->table = NULL;
$this->where = NULL;
$this->groupBy = NULL;
$this->having = NULL;
$this->orderBy = NULL;
$this->limit = NULL;
$this->join = NULL;
$this->selectFunctions = NULL;
$this->table = NULL;
$this->partition = NULL;
$this->procedure = NULL;
$this->outFile = NULL;
$this->characterSet = NULL;
$this->into = NULL;
$this->forUpdate = NULL;
$this->returnQueryType = NULL;
}
/**
* protected Reset Insert Query
*/
protected function resetInsertQueryVariables()
{
$this->column = NULL;
$this->table = NULL;
$this->highPriority = NULL;
$this->lowPriority = NULL;
$this->partition = NULL;
$this->ignore = NULL;
$this->delayed = NULL;
$this->duplicateCheck = NULL;
$this->duplicateCheckUpdate = NULL;
}
/**
* protected Reset Update Query
*/
protected function resetUpdateQueryVariables()
{
$this->where = NULL;
$this->lowPriority = NULL;
$this->ignore = NULL;
$this->orderBy = NULL;
$this->limit = NULL;
$this->table = NULL;
$this->join = NULL;
$this->column = NULL;
}
/**
* protected Reset Delete Query
*/
protected function resetDeleteQueryVariables()
{
$this->where = NULL;
$this->lowPriority = NULL;
$this->quick = NULL;
$this->ignore = NULL;
$this->join = NULL;
$this->partition = NULL;
$this->orderBy = NULL;
$this->limit = NULL;
$this->table = NULL;
}
}