<?php
namespace PHPFUI\ORM;
class Condition implements \Countable, \Stringable
{
private array $conditions = [];
public function __construct(string|\PHPFUI\ORM\Literal|null $field = null, mixed $value = null, \PHPFUI\ORM\Operator $operator = new \PHPFUI\ORM\Operator\Equal())
{
if ($field)
{
$this->add('', $field, $operator, $value);
}
}
public function __toString() : string
{
$retVal = '';
$first = '';
foreach ($this->conditions as $parts)
{
if (! \is_object($parts[1]) || $parts[1] instanceof \PHPFUI\ORM\Literal)
{
if ($parts[0])
{
$retVal .= " {$parts[0]}";
}
$field = $parts[1];
$value = $parts[3];
$operator = " {$parts[2]}";
if ($parts[2]->correctlyTyped($value))
{
if ($field instanceof \PHPFUI\ORM\Literal)
{
$escapedField = (string)$field;
}
else
{
$escapedField = '`' . \str_replace('.', '`.`', (string)$field) . '`';
}
$retVal .= "{$first}{$escapedField}{$operator} ";
$first = ' ';
if (\is_array($value) || $value instanceof \PHPFUI\ORM\Table)
{
$retVal .= '(' . \implode(',', \array_fill(0, \count($value), '?')) . ')';
}
elseif (null !== $value)
{
$retVal .= '?';
}
}
elseif (\is_object($value))
{
$retVal .= "{$first}{$field}{$operator} {$value}";
$first = ' ';
}
else
{
$type = \gettype($value);
throw new \PHPFUI\ORM\Exception("{$field} has incorrect type ({$type}) for {$operator}");
}
}
else
{
$retVal .= " {$parts[0]} ({$parts[1]})";
}
}
return $retVal;
}
public function and(string | \PHPFUI\ORM\Condition | \PHPFUI\ORM\Literal $condition, mixed $value = null, \PHPFUI\ORM\Operator $operator = new \PHPFUI\ORM\Operator\Equal()) : self
{
return $this->add('AND', $condition, $operator, $value);
}
public function andNot(string | \PHPFUI\ORM\Condition | \PHPFUI\ORM\Literal $condition, mixed $value = null, \PHPFUI\ORM\Operator $operator = new \PHPFUI\ORM\Operator\Equal()) : self
{
return $this->add('AND NOT', $condition, $operator, $value);
}
public function count() : int
{
return \count($this->conditions);
}
public function getFields() : array
{
$retVal = [];
foreach ($this->conditions as $parts)
{
if (! \is_object($parts[1]))
{
$retVal[] = $parts[1];
}
else
{
$retVal = \array_merge($retVal, $parts[1]->getFields());
}
}
return $retVal;
}
public function getInput() : array
{
$retVal = [];
foreach ($this->conditions as $parts)
{
if (! \is_object($parts[1]) || $parts[1] instanceof \PHPFUI\ORM\Literal)
{
$value = $parts[3];
if ($value instanceof \PHPFUI\ORM\Table)
{
$input = [];
$sql = $value->getSelectSQL($input);
$retVal = \array_merge($retVal, \PHPFUI\ORM::getValueArray($sql, $input));
}
elseif (\is_array($value))
{
$retVal = \array_merge($retVal, $value);
}
elseif (\is_object($value))
{
}
elseif (null !== $value)
{
$retVal[] = $value;
}
}
else
{
$retVal = \array_merge($retVal, $parts[1]->getInput());
}
}
return $retVal;
}
public function getJSON() : string
{
return \json_encode($this->getConditionArray($this->conditions), JSON_THROW_ON_ERROR);
}
public function or(string | \PHPFUI\ORM\Condition | \PHPFUI\ORM\Literal $condition, mixed $value = null, \PHPFUI\ORM\Operator $operator = new \PHPFUI\ORM\Operator\Equal()) : self
{
return $this->add('OR', $condition, $operator, $value);
}
public function orNot(string | \PHPFUI\ORM\Condition | \PHPFUI\ORM\Literal $condition, mixed $value = null, \PHPFUI\ORM\Operator $operator = new \PHPFUI\ORM\Operator\Equal()) : self
{
return $this->add('OR NOT', $condition, $operator, $value);
}
private function add(string $logical, string | \PHPFUI\ORM\Condition | \PHPFUI\ORM\Literal $condition, \PHPFUI\ORM\Operator $operator, mixed $value) : static
{
if (\is_object($value) && \enum_exists($value::class))
{
$value = $value->value;
}
if (null === $value && ! $operator->correctlyTyped($value))
{
if ($operator instanceof \PHPFUI\ORM\Operator\Equal)
{
$operator = new \PHPFUI\ORM\Operator\IsNull();
}
else
{
$operator = new \PHPFUI\ORM\Operator\IsNotNull();
}
}
if (empty($this->conditions))
{
$logical = '';
}
if ('string' == \gettype($condition) || \PHPFUI\ORM\Literal::class == $condition::class)
{
$this->conditions[] = [$logical, $condition, $operator, $value];
}
elseif (self::class == $condition::class)
{
$this->conditions[] = [$logical, $condition];
}
else
{
throw new \PHPFUI\ORM\Exception('Invalid type in ' . self::class);
}
return $this;
}
private function getConditionArray(array $conditions) : array
{
$data = [];
foreach ($conditions as $condition)
{
if (4 == (\is_countable($condition) ? \count($condition) : 0))
{
$condition[2] = $condition[2]->getOperatorString();
$data[] = $condition;
}
else
{
$condition[1] = $this->getConditionArray($condition[1]->conditions);
$data[] = $condition;
}
}
return $data;
}
}