Database/src/Query/Where/HasWhere.php

154 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)
));
}
}