155 lines
4.5 KiB
PHP
155 lines
4.5 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Nest\Database\Query\Where;
|
||
|
|
||
|
use Nest\Database\Exceptions\Query\NoPrimaryFieldException;
|
||
|
use Nest\Model\Entities;
|
||
|
use Nest\Model\Entity;
|
||
|
|
||
|
/**
|
||
|
* Add where capacity to a query builder.
|
||
|
*/
|
||
|
trait HasWhere
|
||
|
{
|
||
|
/**
|
||
|
* Conditions in where clause.
|
||
|
* @var ConditionBuilder[]
|
||
|
*/
|
||
|
protected array $wheres = [];
|
||
|
|
||
|
/**
|
||
|
* Reset WHERE conditions.
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function resetWheres(): static
|
||
|
{
|
||
|
$this->wheres = [];
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a where condition.
|
||
|
* @param string|callable $column The column of the condition, or a condition builder callable.
|
||
|
* @param mixed|null $operator The operator of the condition (or the value if no value is passed).
|
||
|
* @param mixed|null $value The value of the condition.
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function where(string|callable $column, mixed $operator = null, mixed $value = null): static
|
||
|
{
|
||
|
if (is_callable($column))
|
||
|
{ // Callable condition builder.
|
||
|
$this->wheres[] = $column(new ConditionBuilder());
|
||
|
}
|
||
|
else
|
||
|
{ // Simple condition, registering it.
|
||
|
if (!empty($operator) && empty($value))
|
||
|
{ // If there are 2 parameters, considering the second one as the value, with default operator.
|
||
|
$value = $operator;
|
||
|
$operator = null;
|
||
|
}
|
||
|
|
||
|
if (!empty($value))
|
||
|
{ // A value is defined.
|
||
|
// Default operator: "=".
|
||
|
if (empty($operator)) $operator = "=";
|
||
|
|
||
|
// Create the simple condition.
|
||
|
$this->wheres[] = (new ConditionBuilder())->column($column)->operator($operator)->value($value);
|
||
|
}
|
||
|
else
|
||
|
{ // No value is given, considering a simple existence check.
|
||
|
$this->whereExists($column);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a where IN condition.
|
||
|
* @param string $column The column of the condition.
|
||
|
* @param array $values The values of the condition.
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function whereIn(string $column, array $values): static
|
||
|
{
|
||
|
return $this->where($column, "IN", $values);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a where condition on a column as a value.
|
||
|
* @param string $column The column of the condition.
|
||
|
* @param string $operator The operator of the condition (or the value column if no value is passed).
|
||
|
* @param string|null $valueColumn The value column of the condition.
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function whereColumn(string $column, string $operator, ?string $valueColumn = null): static
|
||
|
{
|
||
|
if (!empty($operator) && empty($valueColumn))
|
||
|
{ // If there are 2 parameters, considering the second one as the value, with default operator.
|
||
|
$valueColumn = $operator;
|
||
|
$operator = "=";
|
||
|
}
|
||
|
|
||
|
// Create the simple condition.
|
||
|
$this->wheres[] = (new ConditionBuilder())->column($column)->operator($operator)->column($valueColumn);
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a where exists condition.
|
||
|
* @param string $column The column to check for existence.
|
||
|
* @return $this
|
||
|
*/
|
||
|
public function whereExists(string $column): static
|
||
|
{
|
||
|
// Create an existence check.
|
||
|
$this->wheres[] = (new ConditionBuilder())->column($column)->exists();
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add condition to find given entities.
|
||
|
* @param Entity|Entities $entities Entity or entities to find.
|
||
|
* @return $this
|
||
|
* @throws NoPrimaryFieldException
|
||
|
*/
|
||
|
public function whereKeyOf(Entity|Entities $entities): static
|
||
|
{
|
||
|
// Normalize parameter to a simple entities array.
|
||
|
if ($entities instanceof Entities)
|
||
|
$entitiesArray = $entities->get();
|
||
|
else
|
||
|
$entitiesArray = [$entities];
|
||
|
|
||
|
// Initialize entities conditions.
|
||
|
$entitiesConditions = [];
|
||
|
foreach ($entitiesArray as $entity)
|
||
|
{ // Add condition for each entity to find.
|
||
|
// Get current entity primary fields and normalize it to an array.
|
||
|
$primaryFields = $entity->getPrimaryFields();
|
||
|
if (!is_array($primaryFields)) $primaryFields = [$primaryFields];
|
||
|
|
||
|
if (empty($primaryFields))
|
||
|
// If there are no primary fields, thrown an exception to ensure not to do something on EVERY rows.
|
||
|
throw new NoPrimaryFieldException($entity);
|
||
|
|
||
|
// Create conditions for current entity.
|
||
|
$entityConditions = [];
|
||
|
foreach ($primaryFields as $primaryField)
|
||
|
// Create a condition builder for each field.
|
||
|
$entityConditions[] = fn (ConditionBuilder $condition) =>
|
||
|
$condition->column($primaryField)->equals()->value($entity->$primaryField);
|
||
|
|
||
|
// Add the full entity condition to the entities conditions array.
|
||
|
$entitiesConditions[] = fn (ConditionBuilder $condition) => $condition->and(...$entityConditions);
|
||
|
}
|
||
|
|
||
|
// Add condition to match every entities.
|
||
|
return $this->where(fn (ConditionBuilder $condition) => (
|
||
|
$condition->or(...$entitiesConditions)
|
||
|
));
|
||
|
}
|
||
|
}
|