ulmus/src/Query/Where.php

154 lines
4.8 KiB
PHP

<?php
namespace Ulmus\Query;
use Ulmus\QueryBuilder;
use Ulmus\Common\EntityField,
Ulmus\Common\Sql;
class Where extends Fragment {
const OPERATOR_LIKE = "LIKE";
const OPERATOR_EQUAL = "=";
const OPERATOR_NOT_EQUAL = "<>";
const CONDITION_AND = "AND";
const CONDITION_OR = "OR";
const CONDITION_NOT = "NOT";
const COMPARISON_IN = "IN";
const COMPARISON_IS = "IS";
const COMPARISON_NULL = "NULL";
const SQL_TOKEN = "WHERE";
public int $order = 50;
public array $conditionList;
public QueryBuilder $queryBuilder;
public ? Where $parent = null;
public string $condition = self::CONDITION_AND;
public function __construct(? QueryBuilder $queryBuilder, $condition = self::CONDITION_AND)
{
$this->queryBuilder = $queryBuilder;
$this->condition = $condition;
$this->parent = $queryBuilder->where ?? null;
}
public function add($field, $value, string $operator, string $condition, bool $not = false) : self
{
$this->conditionList[] = [
$field,
$value,
$operator ?: $this->queryBuilder->conditionOperator,
$condition,
$not
];
return $this;
}
public function render(bool $skipToken = false) : string
{
$stack = [];
foreach ($this->conditionList ?? [] as $key => $item) {
if ( $item instanceof Where ) {
if ( $item->conditionList ?? false ) {
$stack[] = ( $key !== 0 ? "{$item->condition} " : "" ) . "(" . $item->render($skipToken) . ")";
}
}
else {
list($field, $value, $operator, $condition, $not) = $item;
$stack[] = $latest = $this->whereCondition($field, $value, $operator, $key !== 0 ? $condition : "", $not);
}
}
return $this->renderSegments([
! $this->parent && ! $skipToken && ! empty($this->conditionList) ? static::SQL_TOKEN : "",
implode(" ", $stack)
]);
}
protected function whereCondition($field, $value, string $operator = self::OPERATOR_EQUAL, string $condition = self::CONDITION_AND, bool $not = false) {
return new class($this->queryBuilder, $field, $value, $operator, $condition, $not) {
public $value;
public bool $not = false;
public string $field;
public string $operator;
public string $condition;
public QueryBuilder $queryBuilder;
protected string $content = "";
public function __construct(QueryBuilder $queryBuilder, string $field, $value, string $operator, string $condition, bool $not) {
$this->queryBuilder = $queryBuilder;
$this->field = $field;
$this->value = $value;
$this->condition = $condition;
$this->operator = $operator;
$this->not = $not;
}
public function render() : string
{
$value = $this->value();
return $this->content ?: $this->content = implode(" ", array_filter([
$this->condition,
$this->not ? Where::CONDITION_NOT : "",
$this->field,
$this->operator(),
$value,
]));
}
protected function operator() : string
{
if ( is_array($this->value) ) {
return (in_array($this->operator, [ '!=', '<>' ]) ? Where::CONDITION_NOT . " " : "") . Where::COMPARISON_IN;
}
return $this->operator;
}
protected function value()
{
if ( is_array($this->value) ) {
$stack = [];
foreach($this->value as $item) {
$stack[] = $this->filterValue($item);
}
return "(" . implode(", ", $stack) . ")";
}
return $this->filterValue($this->value);
}
protected function filterValue($value)
{
if ( $value === null ) {
$this->operator = in_array($this->operator, [ '!=', '<>' ]) ? Where::COMPARISON_IS . " " . Where::CONDITION_NOT : Where::COMPARISON_IS;
return Where::COMPARISON_NULL;
}
elseif ( is_object($value) && ( $value instanceof EntityField ) ) {
return $value->name();
}
else {
return $this->queryBuilder->addParameter($value);
}
}
public function __toString() : string
{
return $this->render();
}
};
}
}