File "QueryBuilder.php"
Full Path: /home/warrior1/public_html/wp-content/plugins/file-manager/vendor/bitapps/wp-database/src/QueryBuilder.php
File size: 35.65 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace BitApps\WPDatabase;
use Closure;
use DateTime;
use DateTimeZone;
use Exception;
class QueryBuilder
{
public const UPDATE = 'Update';
public const INSERT = 'Insert';
public const DELETE = 'Delete';
public const SELECT = 'Select';
public const TIME_FORMAT = 'Y-m-d H:i:s';
protected $table;
protected $limit;
protected $offset;
protected $orderBy = [];
protected $order;
protected $where = [];
protected $params = [];
protected $joins = [];
protected $groupBy = [];
protected $having = [];
protected $bindings = [];
protected $select = [];
protected $insert = [];
protected $update = [];
protected $distinct = false;
protected $columns = ['*'];
protected $raw = '';
private $_model;
private $_from;
private $_for;
private $_method;
/**
* Constructs QueryBuilder
*
* @param Model $model
*/
public function __construct(Model $model)
{
$this->_model = $model;
$this->table = $model->getTable();
}
/**
* Do necessary when clone
*
* @return void
*/
public function __clone()
{
$this->bindings = [];
}
/**
* Sets alias for table
*
* @param string $_from
*
* @return self
*/
public function from($_from)
{
$this->_from = $_from;
return $this;
}
/**
* Returns model for current query
*
* @return Model
*/
public function getModel()
{
return $this->_model;
}
/**
* Undocumented function
*
* @param string $_for
*
* @return void
*/
public function queryFor($_for)
{
$this->_for = $_for;
return $this;
}
/**
* Returns new instance
*
* @return self
*/
public function newQuery()
{
return new QueryBuilder($this->_model);
}
/**
* Add bindings for this query
*
* @param array $bindings
*
* @return void
*/
public function addBindings($bindings)
{
if (\is_null($bindings)) {
return;
}
if (!\is_array($bindings)) {
$bindings = [$bindings];
}
$this->bindings = array_merge($this->bindings, $bindings);
}
/**
* Returns bindings for this query
*
* @return array
*/
public function getBindings()
{
return $this->bindings;
}
/**
* Get all rows
*
* @param array $columns
*
* @return Model|array<int, Model>|false
*/
public function all($columns = ['*'])
{
return $this->get($columns);
}
/**
* Selects column for query
*
* @param array $columns
*
* @return $this
*/
public function select($columns = ['*'])
{
$this->select = !\is_array($columns) ? \func_get_args() : $columns;
return $this;
}
/**
* Prepare the query and execute.
*
* @param array $columns
*
* @return Model|array<int, Model>| false
*/
public function get($columns = ['*'])
{
$columns = isset($columns) && \is_array($columns) ? $columns : \func_get_args();
if (empty($this->select) || $columns !== ['*']) {
$this->select = $columns;
}
$this->_method = self::SELECT;
return $this->_model->getInstanceFromBuilder(
$this->exec(),
$this->limit == 1 ? true : false
);
}
/**
* Returns only first row from query result.
*
* @return Model
*/
public function first()
{
return $this->take(1)->get();
}
/**
* Prepare the query and execute.
*
* @param array $attributes
*
* @return Model|array<int, Model>| false
*/
public function find($attributes)
{
if (!\is_array($attributes)) {
$attributes = [$this->_model->getPrimaryKey() => $attributes];
}
foreach ($attributes as $key => $value) {
$this->where($key, $value);
}
return $this->get();
}
/**
* Returns first row
*
* @param array $attributes
*
* @return Model | false
*/
public function findOne($attributes)
{
foreach ($attributes as $key => $value) {
$this->where($key, $value);
}
return $this->first();
}
/**
* Get processed conditions
*
* @param QueryBuilder $query
* @param string $type
*
* @return string|string[]|null
*/
public function getConditions(QueryBuilder $query, $type = 'where')
{
return $this->processConditions($query->{$type}, $type);
}
/**
* Prepare operator for where clause
*
* @param array $clause
*
* @return void
*/
public function prepareOperatorForWhere($clause)
{
$sql = '';
if (!isset($clause['column'])) {
return $sql;
}
if (isset($clause['operator'])) {
$sql .= ' ' . $clause['operator'];
} elseif (\is_array($clause['value'])) {
$sql .= ' IN ';
} elseif (\is_null($clause['value'])) {
$sql = ' IS NULL';
} else {
$sql .= ' = ';
}
return $sql;
}
/**
* Set where clause
*
* @param array<column, ?operator, value> ...$params
*
* @return $this
*/
public function where(...$params)
{
$this->prepareWhere($params);
return $this;
}
/**
* Set where clause with OR pipe
*
* @param array<column, ?operator, value> ...$params
*
* @return $this
*/
public function orWhere(...$params)
{
$this->prepareWhere($params, 'OR');
return $this;
}
/**
* Set where clause
*
* @param string $sql
* @param array $bindings
*
* @return $this
*/
public function whereRaw($sql, $bindings = [])
{
$this->where[] = [
'raw' => $sql,
'bindings' => $bindings,
];
return $this;
}
/**
* Set where clause and or pipe
*
* @param string $sql
* @param array $bindings
*
* @return $this
*/
public function orWhereRaw($sql, $bindings = [])
{
$this->where[] = [
'raw' => $sql,
'bindings' => $bindings,
'bool' => 'OR',
];
return $this;
}
/**
* Set where clause with IN operator
*
* @param string $column
* @param array $value
*
* @return $this
*/
public function whereIn($column, $value)
{
$this->where[] = [
'column' => $column,
'value' => $value,
'operator' => 'IN',
];
return $this;
}
/**
* Set where clause with null condition
*
* @param string $column
*
* @return $this
*/
public function whereNull($column)
{
$this->where[] = [
'column' => $column,
'operator' => 'IS NULL',
];
return $this;
}
/**
* Set where clause with not null condition
*
* @param string $column
*
* @return $this
*/
public function whereNotNull($column)
{
$this->where[] = [
'column' => $column,
'operator' => 'IS NOT NULL',
];
return $this;
}
/**
* Set where clause with between condition
*
* @param string $column
* @param mixed $start
* @param mixed $end
*
* @return $this
*/
public function whereBetween($column, $start, $end)
{
$this->where[] = [
'raw' => ' (' . $column . ' BETWEEN ' . $this->getValueType($start)
. ' AND ' . $this->getValueType($end) . ')',
'bindings' => [$start, $end],
];
return $this;
}
/**
* Set where clause with between condition and or pipe
*
* @param string $column
* @param mixed $start
* @param mixed $end
*
* @return $this
*/
public function orWhereBetween($column, $start, $end)
{
$this->where[] = [
'raw' => ' (' . $column . ' BETWEEN ' . $this->getValueType($start)
. ' AND ' . $this->getValueType($end) . ')',
'bindings' => [$start, $end],
'bool' => 'OR',
];
return $this;
}
/**
* Returns pagination data
*
* @param int $pageNo
* @param int $perPage
*
* @return array
*/
public function paginate($pageNo = 0, $perPage = 10)
{
$offset = ($pageNo > 1) ? ($pageNo * $perPage) - $perPage : 0;
$totalItems = (int) $this->count();
$this->take($perPage)->skip($offset);
$this->getLimit();
$this->getOffset();
$data = $this->get();
$pages = ceil($totalItems / $perPage);
return [
'data' => $data,
'pages' => $pages,
'total' => $totalItems,
'current_total' => is_countable($data) ? \count($data) : 0,
'current_page' => $pageNo,
'last_page' => $pages,
'per_page' => $perPage,
];
}
/**
* Sets group by clause
*
* @param array|string[] $columns
*
* @return $this
*/
public function groupBy($columns)
{
$columns = \is_array($columns) ? $columns : \func_get_args();
$this->groupBy = array_merge($this->groupBy, $columns);
return $this;
}
/**
* Set having clause
*
* @param array<column, ?operator, value> ...$params
*
* @return $this
*/
public function having(...$params)
{
return $this->prepareHaving($params);
}
/**
* Set having clause with or
*
* @param array<column, ?operator, value> ...$params
*
* @return $this
*/
public function orHaving(...$params)
{
return $this->prepareHaving($params, 'OR');
}
/**
* Sets join
*
* @param string $table
* @param string $firstColumn
* @param string $operator
* @param string $secondColumn
* @param string $type
*
* @return $this
*/
public function join($table, $firstColumn, $operator = null, $secondColumn = null, $type = 'INNER')
{
$table = Connection::wpPrefix() . $this->_model->getPrefix() . $table;
$hasAlias = preg_split('/ as /i', $table);
if ($hasAlias && isset($hasAlias[1])) {
$table = $hasAlias[0];
$alias = $hasAlias[1];
} else {
$alias = $table;
}
$on[] = $this->prepareOn($alias, $firstColumn, $operator, $secondColumn, 'AND');
$this->joins[] = [
'table' => $table,
'on' => $on,
'type' => $type,
];
return $this;
}
/**
* Sets left join
*
* @param string $table
* @param string $firstColumn
* @param string $operator
* @param string $secondColumn
*
* @return $this
*/
public function leftJoin($table, $firstColumn, $operator = null, $secondColumn = null)
{
return $this->join($table, $firstColumn, $operator, $secondColumn, 'LEFT');
}
/**
* Sets right join
*
* @param string $table
* @param string $firstColumn
* @param string $operator
* @param string $secondColumn
*
* @return $this
*/
public function rightJoin($table, $firstColumn, $operator = null, $secondColumn = null)
{
return $this->join($table, $firstColumn, $operator, $secondColumn, 'RIGHT');
}
/**
* Sets right join
*
* @param string $table
* @param string $firstColumn
* @param string $operator
* @param string $secondColumn
*
* @return $this
*/
public function fullJoin($table, $firstColumn, $operator = null, $secondColumn = null)
{
return $this->join($table, $firstColumn, $operator, $secondColumn, 'FULL');
}
/**
* Sets cross join
*
* @param string $table
* @param string $firstColumn
* @param string $operator
* @param string $secondColumn
*
* @return $this
*/
public function crossJoin($table, $firstColumn, $operator = null, $secondColumn = null)
{
return $this->join($table, $firstColumn, $operator, $secondColumn, 'CROSS');
}
/**
* Sets on clause for join
*
* @param string $firstColumn
* @param string $operator
* @param string $secondColumn
* @param string $bool
*
* @return $this
*/
public function on($firstColumn, $operator = null, $secondColumn = null, $bool = 'AND')
{
$joinIndex = (\count($this->joins) - 1);
if ($joinIndex < 0) {
$joinIndex = 0;
}
$table = $this->joins[$joinIndex]['table'];
$this->joins[$joinIndex]['on'][] = $this->prepareOn($table, $firstColumn, $operator, $secondColumn, $bool);
return $this;
}
/**
* Sets or on clause for join
*
* @param string $firstColumn
* @param string $operator
* @param string $secondColumn
*
* @return $this
*/
public function orOn($firstColumn, $operator = null, $secondColumn = null)
{
return $this->on($firstColumn, $operator, $secondColumn, 'OR');
}
/**
* Returns order by clause sql
*
* @return string
*/
public function getOrderBy()
{
$sql = '';
if (empty($this->orderBy)) {
return $sql;
}
foreach ($this->orderBy as $order) {
$sql .= $order['column'] . ' ' . $order['direction'] . ', ';
}
return ' ORDER BY ' . rtrim($sql, ', ');
}
/**
* Sets order by
*
* @param string $column
*
* @return $this
*/
public function orderBy($column)
{
$this->orderBy[] = [
'column' => $column,
'direction' => 'ASC',
];
return $this;
}
/**
* Sets ascending order
*
* @return $this
*/
public function asc()
{
$orderId = \count($this->orderBy);
if ($orderId > 0) {
$orderId = $orderId - 1;
}
$this->orderBy[$orderId]['direction'] = 'ASC';
if (!isset($this->orderBy[$orderId]['column'])) {
$this->orderBy[$orderId]['column'] = $this->_model->getPrimaryKey();
}
return $this;
}
/**
* Sets descending order
*
* @return $this
*/
public function desc()
{
$orderId = \count($this->orderBy);
if ($orderId > 0) {
$orderId = $orderId - 1;
}
$this->orderBy[$orderId]['direction'] = 'DESC';
if (!isset($this->orderBy[$orderId]['column'])) {
$this->orderBy[$orderId]['column'] = $this->_model->getPrimaryKey();
}
return $this;
}
/**
* Runs raw query
*
* @param string $sql
* @param array $bindings
*
* @return mixed
*/
public function raw($sql, $bindings = [])
{
return $this->exec(Connection::prepare($sql, $bindings));
}
/**
* Sets limit
*
* @param string $count
*
* @return $this
*/
public function take($count)
{
$this->limit = $count;
return $this;
}
/**
* Sets offset
*
* @param string $count
*
* @return $this
*/
public function skip($count)
{
$this->offset = $count;
return $this;
}
/**
* Returns processed offset for query
*
* @return string|null
*/
public function getOffset()
{
return isset($this->limit) && isset($this->offset) ? " OFFSET {$this->offset}" : '';
}
/**
* Run insert query for model
*
* @param array $attributes
*
* @return Model|array<int, Model>|false
*/
public function insert($attributes = [])
{
if (\is_array(reset($attributes))) {
return $this->bulkInsert($attributes);
}
$this->_model->fill($attributes);
if ($this->save()) {
return $this->_model;
}
return false;
}
/**
* Runs update query for model
*
* @param array $attributes
*
* @return $this
*/
public function update($attributes = [])
{
$this->_method = self::UPDATE;
$this->_model->fill($attributes);
$this->update = $this->prepareAttributeForSaveOrUpdate(true);
return $this;
}
/**
* Runs delete query for multiple model
*
* @param array $ids
*
* @return string|bool
*/
public function destroy($ids = [])
{
$this->_method = self::DELETE;
$this->where($this->_model->getPrimaryKey(), $ids);
return $this->exec();
}
/**
* Saves the current model
*
* @return string|bool
*/
public function save()
{
$columns = $this->prepareAttributeForSaveOrUpdate($this->_model->exists());
$pk = $this->_model->getPrimaryKey();
if ($this->_model->exists()) {
$isPkExistsInWhere = false;
$pkValue = $this->_model->getAttribute($pk);
foreach ($this->where as $value) {
if ($value['column'] == $pk && $value['value'] == $pkValue && !isset($value['operator'])) {
$isPkExistsInWhere = true;
}
}
if (!$isPkExistsInWhere) {
$this->where($pk, $pkValue);
}
$this->update = $columns;
$this->exec();
return Connection::prop('rows_affected');
}
$this->insert = $columns;
$this->exec();
if ($insertId = $this->lastInsertId()) {
$this->_model->setAttribute($pk, $insertId);
return true;
}
return false;
}
/**
* Set count for select
*
* @return $this
*/
public function withCount()
{
$this->select[] = 'COUNT(*) as count';
return $this;
}
/**
* Get counts for current model
*
* @return int|null
*/
public function count()
{
$this->select = ['COUNT(*) as count'];
$this->_method = 'Select';
$result = $this->exec();
unset($this->select);
return \is_array($result) && !empty($result[0]->count) ? $result[0]->count : null;
}
public function max($column)
{
$this->select = ['MAX(' . $column . ') as max'];
$this->_method = 'Select';
$result = $this->exec();
unset($this->select);
return \is_array($result) && !empty($result[0]->max) ? $result[0]->max : null;
}
public function min($column)
{
$this->select = ['MIN(' . $column . ') as min'];
$this->_method = 'Select';
$result = $this->exec();
unset($this->select);
return \is_array($result) && !empty($result[0]->min) ? $result[0]->min : null;
}
public function delete()
{
$this->_method = self::DELETE;
if ($this->_model->exists()) {
$this->where($this->_model->getPrimaryKey(), $this->_model->getAttribute($this->_model->getPrimaryKey()));
}
return $this->exec();
}
/**
* Adds relation for model
*
* @param string|Closure $relation
*
* @return $this
*/
public function with($relation)
{
$args = \func_get_args();
$relationalQuery = $this->_model->addRelation($relation);
if ($relationalQuery && \func_num_args() === 2 && $args[1] instanceof Closure) {
$args[1]($relationalQuery);
}
return $this;
}
/**
* Starts transaction
*
* @return bool
*/
public function startTransaction()
{
return Connection::query('START TRANSACTION');
}
/**
* Commits current transaction
*
* @return bool
*/
public function commit()
{
return Connection::query('COMMIT');
}
/**
* Rollback previously execute query
*
* @return void
*/
public function rollback()
{
return Connection::query('ROLLBACK');
}
/**
* Sanitize query string
*
* @param string|null $sql
*
* @return string
*/
public function prepare($sql = null)
{
if (\is_null($sql) && isset($this->_method)) {
$sql = $this->{'prepare' . $this->_method}();
}
return empty($this->bindings)
|| strpos($sql, '%') === false
? $sql : Connection::prepare($sql, $this->bindings);
}
/**
* Process conditions
*
* @param array $conditions
* @param string $type
*
* @return string
*/
protected function processConditions($conditions, $type = null)
{
$sql = '';
if (\is_array($conditions) && \count($conditions) > 0) {
foreach ($conditions as $clause) {
if (isset($clause['bool'])) {
$sql .= ' ' . $clause['bool'];
} else {
$sql .= ' AND';
}
if (isset($clause['raw'])) {
$sql .= ' ' . $clause['raw'];
$this->addBindings($clause['bindings']);
continue;
}
if (isset($clause['query']) && !\is_null($type)) {
$sql .= ' (' . $clause['query']->getConditions($clause['query'], $type) . ')';
$this->addBindings($clause['query']->getBindings());
continue;
}
$sql .= $this->prepareColumnForWhere($clause);
$sql .= $this->prepareOperatorForWhere($clause);
$sql .= $this->prepareValueForWhere($clause, $this);
}
$sql = $this->removeLeadingBool($sql);
}
return $sql;
}
/**
* Prepares conditional
*
* @param array $params
* @param string $bool
* @param string $type
*
* @return array|void
*/
protected function prepareConditional($params, $bool = 'AND', $type = 'where')
{
$noOfParams = \count($params);
$conditions = [];
if ($noOfParams === 0) {
return $conditions;
}
if (\func_num_args() == 1 && \is_array($params[0])) {
foreach ($params[0] as $clause) {
if ($type === 'where') {
$this->prepareWhere($clause, $bool);
}
}
return;
}
$conditions['bool'] = $bool;
if ($params[0] instanceof Closure) {
$nestedQuery = $this->newQuery()->queryFor($type);
\call_user_func($params[0], $nestedQuery);
$conditions['query'] = $nestedQuery;
if (isset($params[1])) {
$conditions['bool'] = $params[1];
}
} elseif ($noOfParams == 2) {
$conditions['column'] = $params[0];
$conditions['value'] = $params[1];
} elseif ($noOfParams == 3) {
$conditions['column'] = $params[0];
$conditions['operator'] = $params[1];
$conditions['value'] = $params[2];
} elseif ($noOfParams == 4) {
$conditions['column'] = $params[0];
$conditions['operator'] = $params[1];
$conditions[$type === 'where' ? 'value' : 'secondColumn'] = $params[2];
$conditions['bool'] = $params[3];
}
return $conditions;
}
/**
* Removes leading and | or
*
* @param string $sql
*
* @return string
*/
protected function removeLeadingBool($sql)
{
return preg_replace('/and |or /i', '', $sql, 1);
}
/**
* Returns processed sql for where clause
*
* @return string
*/
protected function getWhere()
{
$sql = $this->getConditions($this);
if (empty($sql)) {
return '';
}
return " WHERE {$sql}";
}
/**
* Prepares where conditions
*
* @param array $params
* @param string $bool
*
* @return void
*/
protected function prepareWhere($params, $bool = 'AND')
{
$conditions = $this->prepareConditional($params, $bool);
if (!empty($conditions)) {
$this->where[] = $conditions;
}
}
/**
* Returns sql for group by clause
*
* @return string
*/
protected function getGroupBy()
{
if (empty($this->groupBy)) {
return '';
}
return ' GROUP BY ' . implode(',', $this->groupBy);
}
/**
* Prepare having
*
* @param array $params
* @param string $bool
*
* @return $this
*/
protected function prepareHaving($params, $bool = 'AND')
{
$conditions = $this->prepareConditional($params, $bool, 'having');
if (!empty($conditions)) {
$this->having[] = $conditions;
}
return $this;
}
/**
* Return sql for having clause
*
* @return string
*/
protected function getHaving()
{
$sql = $this->getConditions($this, 'having');
if (empty($sql)) {
return '';
}
return " HAVING {$sql}";
}
/**
* Returns sql for join
*
* @return string
*/
protected function getJoin()
{
$sql = '';
if (empty($this->joins)) {
return $sql;
}
foreach ($this->joins as $join) {
$sql .= ' ' . $join['type'] . ' JOIN ' . $join['table'] . ' ON ' . $this->processConditions($join['on']);
}
return $sql;
}
/**
* Prepares on
*
* @param string $table
* @param string $firstColumn
* @param string $operator
* @param string $secondColumn
* @param string $bool
* @param mixed $column
*
* @return $this
*/
protected function prepareOn($table, $column, $operator, $secondColumn, $bool = 'AND')
{
if (\is_null($operator) && \is_null($secondColumn)) {
$column = $this->_model->getTable() . '.' . $column;
$secondColumn = $table . '.' . $column;
$operator = '=';
}
return compact('column', 'operator', 'secondColumn', 'bool');
}
/**
* Returns types
*
* @param mixed $value
*
* @return string
*/
protected function getValueType($value)
{
$placeHolder = '%s';
if (\gettype($value) == 'integer') {
$placeHolder = '%d';
} elseif (\gettype($value) == 'double') {
$placeHolder = '%f';
}
return $placeHolder;
}
/**
* Helper function, to get current timestamp
*
* @return string
*/
protected function currentTimestamp()
{
if (\function_exists('wp_timezone_string')) {
$timezoneString = wp_timezone_string();
} elseif (!($timezoneString = get_option('timezone_string'))) {
$offset = (float) get_option('gmt_offset');
$hours = (int) $offset;
$minutes = ($offset - $hours);
$sign = ($offset < 0) ? '-' : '+';
$absHour = abs($hours);
$absMins = abs($minutes * 60);
$timezoneString = sprintf('%s%02d:%02d', $sign, $absHour, $absMins);
}
$dateTime = new DateTime('now', new DateTimeZone($timezoneString));
return $dateTime->format(self::TIME_FORMAT);
}
/**
* Run bulk insert query
*
* @param array $attributes
*
* @return bool|array<int, Model>
*/
private function bulkInsert($attributes)
{
$firstRow = reset($attributes);
ksort($firstRow);
$columns = array_keys($firstRow);
$createdAt = property_exists($this->_model, 'timestamps') && $this->_model->timestamps;
if ($createdAt) {
$columns[] = 'created_at';
}
$this->bindings = [];
$sql = 'INSERT INTO ' . $this->table;
$sql .= ' (' . implode(', ', $columns) . ')';
$sql .= ' VALUES ';
$values = [];
foreach ($attributes as $row) {
ksort($row);
if ($createdAt) {
$row['created_at'] = $this->currentTimestamp();
}
$rowValues = array_values($row);
$values[] = ' ('
. implode(
', ',
array_map(
function ($value) {
$this->bindings[] = $value;
return $this->getValueType($value);
},
$rowValues
)
) . ')';
}
$sql .= empty($values) ? ' default values' : ' ' . implode(',', $values);
if ($this->raw($sql, $this->bindings) !== false) {
$nextID = $this->lastInsertId();
$ids[] = $nextID;
$affectedRows = Connection::prop('rows_affected') - 1;
while ($affectedRows--) {
$ids[] = $nextID + 1;
}
if (
!empty($ids)
&& (
$allRows = $this->newQuery()
->where($this->_model->getPrimaryKey(), $ids)
->get()
)
) {
return $allRows;
}
return $ids;
}
return false;
}
/**
* Table alias for select query
*
* @return string
*/
private function getFrom()
{
return isset($this->_from) ? " {$this->_from}" : null;
}
/**
* Prepare column for where clause
*
* @param array $clause
*
* @return void
*/
private function prepareColumnForWhere($clause)
{
if (isset($clause['column'])) {
return ' ' . $clause['column'];
}
}
/**
* Prepare value for where clause
*
* @param array $clause
* @param self $query
*
* @return string
*/
private function prepareValueForWhere($clause, self $query)
{
$sql = '';
if (isset($clause['secondColumn'])) {
return ' ' . $clause['secondColumn'];
}
if (!isset($clause['value'])) {
return $sql;
}
if (\is_array($clause['value'])) {
$sql .= ' (';
foreach ($clause['value'] as $value) {
$sql .= $this->getValueType($value) . ',';
$query->addBindings($value);
}
$sql = rtrim($sql, ',') . ')';
} elseif (isset($clause['operator']) && strpos($clause['operator'], 'IS') !== false) {
$sql .= ' ' . $clause['value'];
} elseif (isset($clause['operator']) && strtoupper($clause['operator'] === 'LIKE')) {
$sql .= ' %s';
$query->addBindings($clause['value']);
} elseif (!\is_null($clause['value'])) {
$sql .= ' ' . $query->getValueType($clause['value']);
$query->addBindings($clause['value']);
}
return $sql;
}
/**
* Returns limit part for query
*
* @return string|null
*/
private function getLimit()
{
return isset($this->limit) ? " LIMIT {$this->limit}" : '';
}
/**
* Prepares columns and value
*
* @param bool $isUpdate
*
* @return array
*/
private function prepareAttributeForSaveOrUpdate($isUpdate = false)
{
if ($isUpdate) {
$columnsToPrepare = array_keys($this->_model->getDirtyAttributes());
$this->bindings = [];
} else {
$columnsToPrepare = array_keys($this->_model->getAttributes());
}
if (property_exists($this->_model, 'timestamps') && $this->_model->timestamps) {
if (!$isUpdate) {
$this->_model->setAttribute('created_at', $this->currentTimestamp());
$columnsToPrepare[] = 'created_at';
}
$this->_model->setAttribute('updated_at', $this->currentTimestamp());
$columnsToPrepare[] = 'updated_at';
}
$attributes = $this->_model->getAttributes();
foreach ($columnsToPrepare as $key => $column) {
if (isset($attributes[$column])) {
$this->bindings[] = \is_array($this->_model->{$column})
|| \is_object($this->_model->{$column})
? wp_json_encode($this->_model->{$column}) : $this->_model->{$column};
} else {
$this->bindings[] = '';
}
}
$this->_method = $isUpdate ? self::UPDATE : self::INSERT;
return $columnsToPrepare;
}
/**
* Prepares select statement
*
* @return string
*/
private function prepareSelect()
{
$this->bindings = [];
$sql = 'SELECT ' . implode(',', $this->select) . ' FROM ' . $this->table;
$sql .= $this->getFrom();
$sql .= $this->getJoin();
$sql .= $this->getWhere($this);
$sql .= $this->getGroupBy();
$sql .= $this->getHaving();
$sql .= $this->getOrderBy();
$sql .= $this->getLimit();
$sql .= $this->getOffset();
return trim($sql);
}
/**
* Prepares insert statement
*
* @return string
*/
private function prepareInsert()
{
$sql = 'INSERT INTO ' . $this->table;
$sql .= ' (' . implode(', ', $this->insert) . ')';
$sql .= ' VALUES ('
. implode(
', ',
array_map(
function ($value) {
return $this->getValueType($value);
},
$this->bindings
)
) . ')';
return $sql;
}
/**
* Prepares update statement
*
* @return string
*/
private function prepareUpdate()
{
$sql = 'UPDATE ' . $this->table;
$sql .= $this->getJoin();
$sql .= ' SET ';
$columnCount = \count($this->update);
foreach ($this->update as $key => $column) {
$sql .= $column . ' = ' . $this->getValueType($this->bindings[$key]);
if ($key < $columnCount - 1) {
$sql .= ', ';
}
}
$sql .= $this->getWhere($this);
return $sql;
}
/**
* Prepares delete statement
*
* @return string
*/
private function prepareDelete()
{
if (property_exists($this->_model, 'soft_deletes') && $this->_model->soft_deletes) {
return $this->update(['deleted_at' => $this->currentTimestamp()])->prepareUpdate();
}
$sql = 'DELETE FROM ' . $this->table;
$sql .= $this->getWhere($this);
return $sql;
}
/**
* Executes sql query
*
* @param string $sql
*
* @return array|object|string
*/
private function exec($sql = null)
{
if (\is_null($sql)) {
$sql = $this->prepare($sql);
}
if (\is_null($sql)) {
throw new Exception('SQL query is null');
}
Connection::query($sql);
if (!empty(Connection::prop('last_error'))) {
return false;
}
return Connection::prop('last_result');
}
/**
* Returns last id
*
* @return string
*/
private function lastInsertId()
{
return Connection::prop('insert_id');
}
}