2019-08-21 16:13:00 -04:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Ulmus;
|
|
|
|
|
2021-03-01 16:26:06 +00:00
|
|
|
use Ulmus\Query\QueryBuilderInterface;
|
|
|
|
|
|
|
|
class QueryBuilder implements Query\QueryBuilderInterface
|
2019-08-21 16:13:00 -04:00
|
|
|
{
|
|
|
|
public Query\Where $where;
|
|
|
|
|
2020-04-09 09:50:09 -04:00
|
|
|
public Query\Having $having;
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2021-03-01 16:26:06 +00:00
|
|
|
public QueryBuilderInterface $parent;
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
/**
|
|
|
|
* Those are the parameters we are going to bind to PDO.
|
|
|
|
*/
|
|
|
|
public array $parameters = [];
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-05 16:19:57 -05:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Those values are to be inserted or updated
|
|
|
|
*/
|
|
|
|
public array $values = [];
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-04-09 09:50:09 -04:00
|
|
|
public string $whereConditionOperator = Query\Where::CONDITION_AND;
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
public string $havingConditionOperator = Query\Where::CONDITION_AND;
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
protected int $parameterIndex = 0;
|
|
|
|
|
|
|
|
protected array $queryStack = [];
|
|
|
|
|
2022-04-13 03:31:48 +00:00
|
|
|
public function __clone()
|
2020-11-27 12:09:15 -05:00
|
|
|
{
|
|
|
|
if ($this->where ?? false) {
|
|
|
|
#$this->where = clone $this->where;
|
|
|
|
#$this->where->queryBuilder = $this;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-11-27 12:09:15 -05:00
|
|
|
if ($this->having ?? false) {
|
|
|
|
#$this->having = clone $this->having;
|
|
|
|
#$this->having->queryBuiler = $this;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-11-27 12:09:15 -05:00
|
|
|
if ($this->parent ?? false) {
|
|
|
|
#$this->parent = clone $this->parent;
|
|
|
|
}
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2021-03-09 15:25:46 +00:00
|
|
|
public function select($field, bool $distinct = false) : self
|
2019-08-21 16:13:00 -04:00
|
|
|
{
|
2020-02-07 16:36:38 -05:00
|
|
|
if ( null !== ( $select = $this->getFragment(Query\Select::class) ) ) {
|
2019-08-21 16:13:00 -04:00
|
|
|
$select->add($field);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$select = new Query\Select();
|
|
|
|
$select->set($field);
|
|
|
|
$this->push($select);
|
|
|
|
}
|
|
|
|
|
2021-03-09 15:25:46 +00:00
|
|
|
$select->distinct = $distinct;
|
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
return $this;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2021-08-02 15:13:17 +00:00
|
|
|
public function insert(array $fieldlist, string $table, ? string $alias = null, ? string $database = null, ? string $schema = null, bool $replace = false) : self
|
2019-12-19 09:54:33 -05:00
|
|
|
{
|
2022-04-13 03:31:48 +00:00
|
|
|
if ( null === $this->getFragment(Query\Insert::class) ) {
|
2020-02-05 16:19:57 -05:00
|
|
|
if ( $schema ) {
|
2020-12-07 17:26:51 +00:00
|
|
|
$table = "$schema.$table";
|
2020-02-05 16:19:57 -05:00
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-17 08:23:41 -05:00
|
|
|
if ( $database ) {
|
2020-12-07 17:26:51 +00:00
|
|
|
$table = "$database.$table";
|
2020-02-17 08:23:41 -05:00
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-05 16:19:57 -05:00
|
|
|
$insert = new Query\Insert();
|
|
|
|
$this->push($insert);
|
2021-08-02 15:13:17 +00:00
|
|
|
|
|
|
|
$insert->replace = $replace;
|
2020-02-05 23:41:57 -05:00
|
|
|
$insert->fieldlist = $fieldlist;
|
2020-02-05 16:19:57 -05:00
|
|
|
$insert->alias = $alias;
|
|
|
|
$insert->table = $table;
|
2019-12-19 09:54:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
2019-08-21 16:13:00 -04:00
|
|
|
|
2022-04-13 03:31:48 +00:00
|
|
|
public function values(array $dataset) : self
|
2019-08-21 16:13:00 -04:00
|
|
|
{
|
2020-02-07 16:36:38 -05:00
|
|
|
if ( null === ( $values = $this->getFragment(Query\Values::class) ) ) {
|
2020-02-05 23:41:57 -05:00
|
|
|
$values = new Query\Values($this);
|
2020-02-05 16:19:57 -05:00
|
|
|
$this->push($values);
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-05 16:19:57 -05:00
|
|
|
$values->add($dataset);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-05 16:19:57 -05:00
|
|
|
return $this;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-05 23:41:57 -05:00
|
|
|
public function update(string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
|
|
|
|
{
|
2020-02-17 08:23:41 -05:00
|
|
|
if ( ! $this->getFragment(Query\Update::class) ) {
|
2020-02-05 23:41:57 -05:00
|
|
|
if ( $schema ) {
|
2020-04-14 09:47:09 -04:00
|
|
|
$table = "$schema.$table";
|
2020-02-05 23:41:57 -05:00
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-17 08:23:41 -05:00
|
|
|
if ( $database ) {
|
2020-04-14 09:47:09 -04:00
|
|
|
$table = "$database.$table";
|
2020-02-17 08:23:41 -05:00
|
|
|
}
|
2020-02-05 23:41:57 -05:00
|
|
|
|
|
|
|
$update = new Query\Update();
|
|
|
|
$this->push($update);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-05 23:41:57 -05:00
|
|
|
$update->alias = $alias;
|
|
|
|
$update->table = $table;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2021-03-15 13:42:52 +00:00
|
|
|
public function set(array $dataset, ? array $escapedFields = null) : self
|
2020-02-05 23:41:57 -05:00
|
|
|
{
|
2020-02-17 08:23:41 -05:00
|
|
|
if ( null === ( $set = $this->getFragment(Query\Set::class) ) ) {
|
2020-02-05 23:41:57 -05:00
|
|
|
$set = new Query\Set($this);
|
|
|
|
$this->push($set);
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2021-03-15 13:42:52 +00:00
|
|
|
$set->set($dataset, $escapedFields);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-05 23:41:57 -05:00
|
|
|
return $this;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-05 16:19:57 -05:00
|
|
|
public function delete() : self
|
|
|
|
{
|
2020-02-07 16:36:38 -05:00
|
|
|
if ( ! $this->getFragment(Query\Delete::class) ) {
|
2020-02-05 16:19:57 -05:00
|
|
|
$this->push(new Query\Delete());
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function from(string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
|
|
|
|
{
|
2020-01-29 16:11:16 -05:00
|
|
|
if ( $schema ) {
|
2020-04-14 09:47:09 -04:00
|
|
|
$table = "$schema.$table";
|
2019-08-21 16:13:00 -04:00
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-17 08:23:41 -05:00
|
|
|
if ( $database ) {
|
|
|
|
$table = "$database.$table";
|
|
|
|
}
|
2019-08-21 16:13:00 -04:00
|
|
|
|
2020-02-07 16:36:38 -05:00
|
|
|
if ( null !== ( $from = $this->getFragment(Query\From::class) ) ) {
|
2019-08-21 16:13:00 -04:00
|
|
|
$from->add($alias ? [ $alias => $table ] : $table);
|
|
|
|
}
|
|
|
|
else {
|
2020-01-29 16:11:16 -05:00
|
|
|
$from = new Query\From($this);
|
2019-08-21 16:13:00 -04:00
|
|
|
$this->push($from);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-07 16:36:38 -05:00
|
|
|
$from->set($alias ? [ $alias => $table ] : [ $table ]);
|
2019-08-21 16:13:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function open(string $condition = Query\Where::CONDITION_AND) : self
|
|
|
|
{
|
2020-03-31 13:24:15 -04:00
|
|
|
if ( null !== ($this->where ?? null) ) {
|
|
|
|
$this->where->conditionList[] = $new = new Query\Where($this, $condition);
|
|
|
|
$this->where = $new;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$this->where = new Query\Where($this, $condition);
|
|
|
|
$this->push($this->where);
|
2019-08-21 16:13:00 -04:00
|
|
|
$this->where->conditionList[] = $new = new Query\Where($this, $condition);
|
|
|
|
$this->where = $new;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function close() : self
|
|
|
|
{
|
2020-03-31 13:24:15 -04:00
|
|
|
if ( null !== ($this->where ?? null) && $this->where->parent ) {
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-03-31 13:24:15 -04:00
|
|
|
# if an enclosure was opened, and nothing done, we must remove the unused node
|
|
|
|
if ( empty($this->where->conditionList) && (count($this->where->parent->conditionList) === 1) ) {
|
|
|
|
unset($this->where->parent->conditionList);
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
$this->where = $this->where->parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2021-01-26 16:48:40 +00:00
|
|
|
public function where(/* stringable*/ $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
|
2019-08-21 16:13:00 -04:00
|
|
|
{
|
2020-05-20 15:34:50 -04:00
|
|
|
# Empty IN case
|
|
|
|
if ( [] === $value ) {
|
|
|
|
return $this;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
if ( $this->where ?? false ) {
|
|
|
|
$where = $this->where;
|
|
|
|
}
|
2020-02-07 16:36:38 -05:00
|
|
|
elseif ( null === ( $where = $this->getFragment(Query\Where::class) ) ) {
|
2019-08-21 16:13:00 -04:00
|
|
|
$this->where = $where = new Query\Where($this);
|
|
|
|
$this->push($where);
|
|
|
|
}
|
|
|
|
|
2020-04-09 09:50:09 -04:00
|
|
|
$this->whereConditionOperator = $operator;
|
2020-04-09 10:00:48 -04:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
$where->add($field, $value, $operator, $condition, $not);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
public function notWhere($field, $value, string $operator = Query\Where::CONDITION_AND) : self
|
|
|
|
{
|
|
|
|
return $this->where($field, $value, $operator, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function having($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
|
2020-04-09 09:50:09 -04:00
|
|
|
{
|
|
|
|
if ( $this->having ?? false ) {
|
|
|
|
$having = $this->having;
|
|
|
|
}
|
|
|
|
elseif ( null === ( $having = $this->getFragment(Query\Having::class) ) ) {
|
|
|
|
$this->having = $having = new Query\Having($this);
|
|
|
|
$this->push($having);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->havingConditionOperator = $operator;
|
|
|
|
$having->add($field, $value, $operator, $condition, $not);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-04-09 09:50:09 -04:00
|
|
|
return $this;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
public function limit(int $value) : self
|
|
|
|
{
|
2020-02-07 16:36:38 -05:00
|
|
|
if ( null === $limit = $this->getFragment(Query\Limit::class) ) {
|
2019-08-21 16:13:00 -04:00
|
|
|
$limit = new Query\Limit();
|
|
|
|
$this->push($limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
$limit->set($value);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2022-06-21 15:38:06 +00:00
|
|
|
if ($value === 0) {
|
|
|
|
$this->removeFragment(Query\Limit::class);
|
|
|
|
}
|
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function offset(int $value) : self
|
|
|
|
{
|
2020-02-07 16:36:38 -05:00
|
|
|
if ( null === $offset = $this->getFragment(Query\Offset::class) ) {
|
2019-08-21 16:13:00 -04:00
|
|
|
$offset = new Query\Offset();
|
|
|
|
$this->push($offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
$offset->set($value);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function orderBy(string $field, ? string $direction = null) : self
|
|
|
|
{
|
2020-02-07 16:36:38 -05:00
|
|
|
if ( null === $orderBy = $this->getFragment(Query\OrderBy::class) ) {
|
2019-08-21 16:13:00 -04:00
|
|
|
$orderBy = new Query\OrderBy();
|
|
|
|
$this->push($orderBy);
|
|
|
|
}
|
|
|
|
|
|
|
|
$orderBy->add($field, $direction);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2020-10-06 11:43:31 -04:00
|
|
|
public function groupBy(string $field, ? string $direction = null) : self
|
|
|
|
{
|
|
|
|
if ( null === $groupBy = $this->getFragment(Query\GroupBy::class) ) {
|
|
|
|
$groupBy = new Query\GroupBy();
|
|
|
|
$this->push($groupBy);
|
|
|
|
}
|
|
|
|
|
|
|
|
$groupBy->add($field, $direction);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-10-06 11:43:31 -04:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2020-04-14 09:47:09 -04:00
|
|
|
public function join(string $type, /*string | QueryBuilder*/ $table, $field, $value, bool $outer = false, ? string $alias = null) : self
|
2020-10-06 11:00:12 -04:00
|
|
|
{
|
|
|
|
$this->withJoin(...func_get_args());
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function withJoin(string $type, $table, $field, $value, bool $outer = false, ? string $alias = null) : Query\Join
|
2020-02-17 08:23:41 -05:00
|
|
|
{
|
2020-04-09 09:50:09 -04:00
|
|
|
$join = new Query\Join($this);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-04-09 09:50:09 -04:00
|
|
|
$this->push($join);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-04-09 09:50:09 -04:00
|
|
|
$join->set($type, $table, $field, $value);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-17 08:23:41 -05:00
|
|
|
$join->outer = $outer;
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-04-14 09:47:09 -04:00
|
|
|
$join->alias = $alias;
|
2022-04-13 03:31:48 +00:00
|
|
|
|
|
|
|
$join->joinOrder = $this->nextJoinOrder();
|
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
return $join;
|
2020-02-17 08:23:41 -05:00
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2023-01-14 02:19:42 +00:00
|
|
|
public function showDatabases() : self
|
|
|
|
{
|
|
|
|
$show = new Query\Show();
|
|
|
|
|
|
|
|
$this->push($show);
|
|
|
|
|
|
|
|
$show->set(Query\Show::SQL_SHOW_DATABASES);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function showTables(? string $database = null) : self
|
|
|
|
{
|
|
|
|
$show = new Query\Show();
|
|
|
|
|
|
|
|
$this->push($show);
|
|
|
|
|
|
|
|
$show->set(Query\Show::SQL_SHOW_TABLES, $database);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function showColumns(string $table) : self
|
|
|
|
{
|
|
|
|
$show = new Query\Show();
|
|
|
|
|
|
|
|
$this->push($show);
|
|
|
|
|
|
|
|
$show->set(Query\Show::SQL_SHOW_COLUMNS, $table);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
public function truncate(string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
|
|
|
|
{
|
|
|
|
if ( $schema ) {
|
|
|
|
$table = "$schema.$table";
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
if ( $database ) {
|
|
|
|
$table = "$database.$table";
|
|
|
|
}
|
2020-04-09 09:50:09 -04:00
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
$truncate = new Query\Truncate($this);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
$this->push($truncate);
|
|
|
|
|
|
|
|
$truncate->set($table);
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-10-16 15:27:54 +00:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2022-01-28 16:37:35 +00:00
|
|
|
public function create(Adapter\AdapterInterface $adapter, array $fieldlist, string $table, ? string $database = null, ? string $schema = null) : self
|
2020-10-16 15:27:54 +00:00
|
|
|
{
|
|
|
|
if ( null === $this->getFragment(Query\Create::class) ) {
|
|
|
|
if ( $schema ) {
|
2020-12-07 17:26:51 +00:00
|
|
|
$table = "$schema.$table";
|
2020-10-16 15:27:54 +00:00
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-10-16 15:27:54 +00:00
|
|
|
if ( $database ) {
|
2020-12-07 17:26:51 +00:00
|
|
|
$table = "$database.$table";
|
2020-10-16 15:27:54 +00:00
|
|
|
}
|
|
|
|
|
2022-01-28 16:37:35 +00:00
|
|
|
$create = new Query\Create($adapter);
|
2020-10-16 15:27:54 +00:00
|
|
|
$this->push($create);
|
|
|
|
|
|
|
|
$create->fieldList = $fieldlist;
|
|
|
|
$create->table = $table;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
throw new \Exception("A create SQL fragment was already found within the query builder");
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2022-01-28 16:37:35 +00:00
|
|
|
public function alter(Adapter\AdapterInterface $adapter, array $fieldlist, string $table, ? string $database = null, ? string $schema = null) : self
|
2021-05-24 20:03:38 +00:00
|
|
|
{
|
|
|
|
if ( null === $this->getFragment(Query\Create::class) ) {
|
|
|
|
if ( $schema ) {
|
|
|
|
$table = "$schema.$table";
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $database ) {
|
|
|
|
$table = "$database.$table";
|
|
|
|
}
|
|
|
|
|
2022-01-28 16:37:35 +00:00
|
|
|
$alter = new Query\Alter($adapter);
|
2021-05-24 20:03:38 +00:00
|
|
|
$this->push($alter);
|
|
|
|
|
|
|
|
$alter->fieldList = $fieldlist;
|
|
|
|
$alter->table = $table;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
throw new \Exception("A create SQL fragment was already found within the query builder");
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2020-10-16 15:27:54 +00:00
|
|
|
public function engine(string $value) : self
|
|
|
|
{
|
|
|
|
if ( null === $engine = $this->getFragment(Query\Engine::class) ) {
|
|
|
|
$engine = new Query\Engine();
|
|
|
|
$this->push($engine);
|
|
|
|
}
|
|
|
|
|
|
|
|
$engine->engine = $value;
|
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
return $this;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
public function push(Query\Fragment $queryFragment) : self
|
|
|
|
{
|
|
|
|
$this->queryStack[] = $queryFragment;
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
return $this;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
public function pull(Query\Fragment $queryFragment) : self
|
|
|
|
{
|
|
|
|
return array_shift($this->queryStack);
|
|
|
|
}
|
2019-08-21 16:13:00 -04:00
|
|
|
|
2021-03-01 16:26:06 +00:00
|
|
|
public function render(bool $skipToken = false) /* : mixed */
|
2019-08-21 16:13:00 -04:00
|
|
|
{
|
|
|
|
$sql = [];
|
|
|
|
|
|
|
|
usort($this->queryStack, function($q1, $q2) {
|
2022-05-10 13:19:48 +00:00
|
|
|
return (float) $q1->order() <=> (float) $q2->order();
|
2019-08-21 16:13:00 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
foreach($this->queryStack as $fragment) {
|
2020-10-06 11:00:12 -04:00
|
|
|
$sql[] = $fragment->render($skipToken);
|
2019-08-21 16:13:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return implode(" ", $sql);
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-17 08:23:41 -05:00
|
|
|
public function reset() : void
|
|
|
|
{
|
|
|
|
$this->parameters = $this->values = $this->queryStack = [];
|
2020-04-09 09:50:09 -04:00
|
|
|
$this->whereConditionOperator = Query\Where::CONDITION_AND;
|
2020-10-06 11:00:12 -04:00
|
|
|
$this->havingConditionOperator = Query\Where::CONDITION_AND;
|
2020-02-17 08:23:41 -05:00
|
|
|
$this->parameterIndex = 0;
|
|
|
|
|
2020-10-06 11:00:12 -04:00
|
|
|
unset($this->where, $this->having);
|
2020-02-17 08:23:41 -05:00
|
|
|
}
|
2019-08-21 16:13:00 -04:00
|
|
|
|
2021-03-01 16:26:06 +00:00
|
|
|
public function getFragment(string $class, int $index = 0) : ? Query\Fragment
|
2020-02-07 16:36:38 -05:00
|
|
|
{
|
2019-08-21 16:13:00 -04:00
|
|
|
foreach($this->queryStack as $item) {
|
2021-03-09 15:25:46 +00:00
|
|
|
if ( is_a($item, $class, true) ) {
|
2021-03-01 16:26:06 +00:00
|
|
|
if ( $index-- === 0 ) {
|
|
|
|
return $item;
|
|
|
|
}
|
2019-08-21 16:13:00 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-07 16:36:38 -05:00
|
|
|
return null;
|
2019-08-21 16:13:00 -04:00
|
|
|
}
|
|
|
|
|
2021-05-24 20:03:38 +00:00
|
|
|
public function removeFragment(/*Query\Fragment|array*/ $fragment) : void
|
2020-02-07 16:36:38 -05:00
|
|
|
{
|
2021-05-24 20:03:38 +00:00
|
|
|
is_object($fragment) && $fragment = get_class($fragment);
|
|
|
|
|
2020-02-07 16:36:38 -05:00
|
|
|
foreach($this->queryStack as $key => $item) {
|
2021-05-24 20:03:38 +00:00
|
|
|
if ( get_class($item) === $fragment ) {
|
2020-02-07 16:36:38 -05:00
|
|
|
unset($this->queryStack[$key]);
|
|
|
|
}
|
|
|
|
}
|
2021-05-24 20:03:38 +00:00
|
|
|
|
|
|
|
if ( $fragment === Query\Where::class ) {
|
|
|
|
unset($this->where);
|
|
|
|
}
|
|
|
|
elseif ( $fragment === Query\Having::class ) {
|
|
|
|
unset($this->having);
|
|
|
|
}
|
2020-02-07 16:36:38 -05:00
|
|
|
}
|
2021-03-09 15:25:46 +00:00
|
|
|
|
2022-04-13 03:31:48 +00:00
|
|
|
public function getFragments(/*? Query\Fragment|array*/ $fragment = null) : array
|
2021-03-09 15:25:46 +00:00
|
|
|
{
|
2022-07-15 19:59:38 +00:00
|
|
|
return $fragment !== null ? array_filter($this->queryStack, fn($e) => is_a($e, $fragment, true) ) : $this->queryStack;
|
2021-03-09 15:25:46 +00:00
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
public function __toString() : string
|
|
|
|
{
|
|
|
|
return $this->render();
|
|
|
|
}
|
|
|
|
|
2022-04-13 03:31:48 +00:00
|
|
|
public function addParameter($value, string $key = null) : string
|
2020-02-05 16:19:57 -05:00
|
|
|
{
|
2020-10-06 11:00:12 -04:00
|
|
|
if ( $this->parent ?? false ) {
|
|
|
|
return $this->parent->addParameter($value, $key);
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
if ( $key === null ) {
|
|
|
|
$key = ":p" . $this->parameterIndex++;
|
|
|
|
}
|
|
|
|
|
2022-04-13 03:31:48 +00:00
|
|
|
$this->parameters[$key] = $value;
|
2020-10-06 11:00:12 -04:00
|
|
|
|
2019-08-21 16:13:00 -04:00
|
|
|
return $key;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
|
2020-02-05 23:41:57 -05:00
|
|
|
public function addValues(array $values) : void
|
|
|
|
{
|
2020-02-05 16:19:57 -05:00
|
|
|
$this->values = $values;
|
|
|
|
}
|
2022-04-13 03:31:48 +00:00
|
|
|
protected function nextJoinOrder() : float
|
|
|
|
{
|
|
|
|
$next = 0;
|
|
|
|
|
|
|
|
foreach($this->getFragments(Query\Join::class) as $join) {
|
2022-01-28 16:37:35 +00:00
|
|
|
$next = max($next, $join->joinOrder - Query\Join::ORDER_VALUE);
|
2022-04-13 03:31:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $next + 1;
|
|
|
|
}
|
2019-08-21 16:13:00 -04:00
|
|
|
}
|