Skip to content

Commit

Permalink
Filter object
Browse files Browse the repository at this point in the history
  • Loading branch information
mabar committed Mar 24, 2021
1 parent 4cc9a12 commit 219cb93
Show file tree
Hide file tree
Showing 7 changed files with 730 additions and 0 deletions.
53 changes: 53 additions & 0 deletions src/Collection/Filter/Filter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php declare(strict_types = 1);

namespace Nextras\Orm\Collection\Filter;

class Filter
{

/** @var FindFilter */
private $find;

/** @var OrderFilter */
private $order;

/** @var int|null */
private $limitCount;

/** @var int|null */
private $limitOffset;

public function __construct()
{
$this->find = new FindFilter();
$this->order = new OrderFilter();
}

public function find(): FindFilter
{
return $this->find;
}

public function order(): OrderFilter
{
return $this->order;
}

public function limit(int $count, ?int $offset = null): void
{
$this->limitCount = $count;
$this->limitOffset = $offset;
}

/**
* @return array{int|null, int|null}
*/
public function getLimit(): array
{
return [
$this->limitCount,
$this->limitOffset,
];
}

}
179 changes: 179 additions & 0 deletions src/Collection/Filter/FindFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<?php declare(strict_types = 1);

namespace Nextras\Orm\Collection\Filter;

use Closure;
use Nextras\Orm\Collection\Expression\LikeExpression;
use Nextras\Orm\Collection\Functions\IArrayFunction;
use Nextras\Orm\Collection\Functions\IQueryBuilderFunction;
use Nextras\Orm\Collection\ICollection;
use function array_merge;
use function array_unshift;
use function count;

class FindFilter
{

/** @var array<mixed> */
private $conditions = [];

/** @var string */
private $logicalOperator;

public function __construct(string $logicalOperator = ICollection::AND)
{
$this->logicalOperator = $logicalOperator;
}

/**
* @param mixed $value
*/
public function equal(string $property, $value): void
{
$this->operator('', $property, $value);
}

/**
* @param mixed $value
*/
public function notEqual(string $property, $value): void
{
$this->operator('!=', $property, $value);
}

/**
* @param mixed $number
*/
public function greater(string $property, $number): void
{
$this->operator('>', $property, $number);
}

/**
* @param mixed $number
*/
public function greaterOrEqual(string $property, $number): void
{
$this->operator('>=', $property, $number);
}

/**
* @param mixed $number
*/
public function lower(string $property, $number): void
{
$this->operator('<', $property, $number);
}

/**
* @param mixed $number
*/
public function lowerOrEqual(string $property, $number): void
{
$this->operator('<=', $property, $number);
}

public function like(string $property, LikeExpression $expression): void
{
$this->operator('~', $property, $expression);
}

/**
* @param mixed $value
*/
public function operator(string $operator, string $property, $value): void
{
$this->raw([
"{$property}{$operator}" => $value,
]);
}

/**
* @param class-string<IArrayFunction|IQueryBuilderFunction> $function
* @param string|array<mixed> $expression
* @param mixed $values
*/
public function function(string $function, $expression, ...$values): void
{
$this->raw($this->createFunction($function, $expression, ...$values));
}

/**
* @param class-string<IArrayFunction|IQueryBuilderFunction> $function
* @param string|array<mixed> $expression
* @param mixed $values
* @return array<mixed>
*/
public function createFunction(string $function, $expression, ...$values): array
{
return array_merge([$function, $expression], $values);
}

/**
* @param array<mixed> $condition
*/
public function raw(array $condition): void
{
$this->conditions[] = $condition;
}

/**
* @param Closure(FindFilter): void $conditions
*/
public function and(Closure $conditions): void
{
$this->logicalOperator($conditions, ICollection::AND);
}

/**
* @param Closure(FindFilter): void $conditions
*/
public function or(Closure $conditions): void
{
$this->logicalOperator($conditions, ICollection::OR);
}

/**
* @param Closure(FindFilter): void $conditions
*/
private function logicalOperator(Closure $conditions, string $operator): void
{
$find = new FindFilter($operator);

$conditions($find);

$raw = $find->getConditions();

if ($raw === []) {
return;
}

$this->raw($raw);
}

/**
* @return array<mixed>
*/
public function getConditions(): array
{
// No conditions, empty result
$count = count($this->conditions);
if ($count === 0) {
return [];
}

// Only condition is inner logical operator, optimize it
if ($count === 1) {
$key = $this->conditions[0][0] ?? null;
if ($key === ICollection::AND || $key === ICollection::OR) {
return $this->conditions[0];
}
}

$conditions = $this->conditions;
array_unshift($conditions, $this->logicalOperator);

return $conditions;
}

}
61 changes: 61 additions & 0 deletions src/Collection/Filter/OrderFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php declare(strict_types = 1);

namespace Nextras\Orm\Collection\Filter;

use Nextras\Orm\Collection\Functions\IArrayFunction;
use Nextras\Orm\Collection\Functions\IQueryBuilderFunction;
use Nextras\Orm\Collection\ICollection;
use function array_merge;

class OrderFilter
{

/** @var array<array{0:string|array<mixed>, 1:string}> */
private $order = [];

public function property(string $property, string $direction = ICollection::ASC): void
{
$this->raw($property, $direction);
}

/**
* @param class-string<IArrayFunction|IQueryBuilderFunction> $function
* @param string|array<mixed> $expression
* @param mixed $values
*/
public function function(string $function, $expression, string $direction = ICollection::ASC, ...$values): void
{
$this->raw(
$this->createFunction($function, $expression, ...$values),
$direction,
);
}

/**
* @param class-string<IArrayFunction|IQueryBuilderFunction> $function
* @param string|array<mixed> $expression
* @param mixed $values
* @return array<mixed>
*/
public function createFunction(string $function, $expression, ...$values): array
{
return array_merge([$function, $expression], $values);
}

/**
* @param string|array<mixed> $expression
*/
public function raw($expression, string $direction = ICollection::ASC): void
{
$this->order[] = [$expression, $direction];
}

/**
* @return array<array{0:string|array<mixed>, 1:string}>
*/
public function getOrder(): array
{
return $this->order;
}

}
46 changes: 46 additions & 0 deletions src/Repository/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@


use Nextras\Orm\Collection\ArrayCollection;
use Nextras\Orm\Collection\Filter\Filter;
use Nextras\Orm\Collection\Filter\FindFilter;
use Nextras\Orm\Collection\Functions\AvgAggregateFunction;
use Nextras\Orm\Collection\Functions\CompareEqualsFunction;
use Nextras\Orm\Collection\Functions\CompareGreaterThanEqualsFunction;
Expand Down Expand Up @@ -249,6 +251,22 @@ public function getByIdChecked($id): IEntity
}


public function getByFilter(FindFilter $find): ?IEntity
{
return $this->getBy($find->getConditions());
}


public function getByFilterChecked(FindFilter $find): IEntity
{
$entity = $this->getBy($find->getConditions());
if ($entity === null) {
throw new NoResultException();
}
return $entity;
}


/** {@inheritdoc} */
public function findAll(): ICollection
{
Expand Down Expand Up @@ -278,6 +296,28 @@ public function findById($ids): ICollection
}


/**
* @phpstan-return ICollection<E>
*/
public function findByFilter(Filter $filter): ICollection
{
$conditions = $filter->find()->getConditions();
$collection = $conditions === [] ? $this->findAll() : $this->findBy($conditions);

$order = $filter->order()->getOrder();
foreach ($order as [$expression, $direction]) {
$collection = $collection->orderBy($expression, $direction);
}

[$limitCount, $limitOffset] = $filter->getLimit();
if ($limitCount !== null) {
$collection = $collection->limitBy($limitCount, $limitOffset);
}

return $collection;
}


/** {@inheritdoc} */
public function findByIds(array $ids): ICollection
{
Expand Down Expand Up @@ -347,6 +387,12 @@ protected function createCollectionFunction(string $name)
}


public function createFilter(): Filter
{
return new Filter();
}


/** {@inheritdoc} */
public function attach(IEntity $entity): void
{
Expand Down
Loading

0 comments on commit 219cb93

Please sign in to comment.