diff --git a/src/Application/CriteriaBuilder.php b/src/Application/CriteriaBuilder.php new file mode 100644 index 0000000..44b9c2b --- /dev/null +++ b/src/Application/CriteriaBuilder.php @@ -0,0 +1,223 @@ + + * @package OtherCode\ComplexHeart\Application + */ +final class CriteriaBuilder +{ + private array $filters = []; + + private string $orderBy = ''; + + private string $orderType = 'asc'; + + private int $pageOffset = 0; + + private int $pageLimit = 1000; + + /** + * Adds an arbitrary filter. + * + * @param string $field + * @param string $operator + * @param mixed $value + * @return $this + */ + public function filter(string $field, string $operator, $value): self + { + $this->filters[] = [$field, $operator, $value]; + return $this; + } + + /** + * Adds new filter for equals operator. + * + * @param string $field + * @param mixed $value + * @return $this + */ + public function filterEqual(string $field, $value): self + { + $this->filter($field, Filter::EQUAL, $value); + return $this; + } + + /** + * Adds new filter for not equals operator. + * + * @param string $field + * @param mixed $value + * @return $this + */ + public function filterNotEqual(string $field, $value): self + { + $this->filter($field, Filter::NOT_EQUAL, $value); + return $this; + } + + /** + * Adds new filter for greater than operator. + * + * @param string $field + * @param mixed $value + * @return $this + */ + public function filterGreaterThan(string $field, $value): self + { + $this->filter($field, Filter::GT, $value); + return $this; + } + + /** + * Adds new filter for greater or equal than operator. + * + * @param string $field + * @param mixed $value + * @return $this + */ + public function filterGreaterOrEqualThan(string $field, $value): self + { + $this->filter($field, Filter::GTE, $value); + return $this; + } + + /** + * Adds new filter for less than operator. + * + * @param string $field + * @param mixed $value + * @return $this + */ + public function filterLessThan(string $field, $value): self + { + $this->filter($field, Filter::LT, $value); + return $this; + } + + /** + * Adds new filter for less or equal than operator. + * + * @param string $field + * @param mixed $value + * @return $this + */ + public function filterLessOrEqualThan(string $field, $value): self + { + $this->filter($field, Filter::LTE, $value); + return $this; + } + + /** + * Adds new filter for in operator. + * + * @param string $field + * @param mixed $value + * @return $this + */ + public function filterIn(string $field, $value): self + { + $this->filter($field, Filter::IN, $value); + return $this; + } + + /** + * Adds new filter for not in operator. + * + * @param string $field + * @param mixed $value + * @return $this + */ + public function filterNotIn(string $field, $value): self + { + $this->filter($field, Filter::NOT_IN, $value); + return $this; + } + + /** + * Adds new filter for like operator. + * + * @param string $field + * @param mixed $value + * @return $this + */ + public function filterLike(string $field, $value): self + { + $this->filter($field, Filter::LIKE, $value); + return $this; + } + + /** + * Sets the order by field parameter. + * + * @param string $field + * @return $this + */ + public function orderedBy(string $field): self + { + $this->orderBy = $field; + return $this; + } + + /** + * Sets the order type parameter. + * + * @param string $type + * @return $this + */ + public function orderedType(string $type): self + { + $this->orderType = $type; + return $this; + } + + /** + * Set the page limit parameter. + * + * @param int $limit + * @return $this + */ + public function withLimit(int $limit): self + { + $this->pageLimit = $limit; + return $this; + } + + /** + * Set the page offset parameter. + * + * @param int $offset + * @return $this + */ + public function withOffset(int $offset): self + { + $this->pageOffset = $offset; + return $this; + } + + /** + * Builds the Criteria object. + * + * @return Criteria + */ + public function build(): Criteria + { + return new Criteria( + FilterGroup::create($this->filters), + Order::create($this->orderBy, $this->orderType), + Page::create($this->pageLimit, $this->pageOffset) + ); + } +} \ No newline at end of file diff --git a/src/Domain/Criteria/FilterGroup.php b/src/Domain/Criteria/FilterGroup.php index 5965eb3..8cba211 100644 --- a/src/Domain/Criteria/FilterGroup.php +++ b/src/Domain/Criteria/FilterGroup.php @@ -42,7 +42,7 @@ public static function create(array $filters): FilterGroup public function add(Filter $filter): FilterGroup { - return new self(array_merge($this->filters, [$filter])); + return new self(...array_merge($this->filters, [$filter])); } public function filters(): array diff --git a/tests/Application/CriteriaBuilderTest.php b/tests/Application/CriteriaBuilderTest.php new file mode 100644 index 0000000..9c53439 --- /dev/null +++ b/tests/Application/CriteriaBuilderTest.php @@ -0,0 +1,63 @@ + + * @package OtherCode\ComplexHeart\Tests\Application + */ +class CriteriaBuilderTest extends MockeryTestCase +{ + public function testShouldBuildCriteriaInstance(): void + { + $criteria = (new CriteriaBuilder())->build(); + $this->assertInstanceOf(Criteria::class, $criteria); + } + + public function testShouldAddFiltersToCriteria(): void + { + $criteria = (new CriteriaBuilder()) + ->filterEqual('name', 'Jules') + ->filterNotEqual('surname', 'Wallace') + ->filterGreaterThan('height', 1) + ->filterLessThan('weight', 100) + ->filterGreaterOrEqualThan('age', 18) + ->filterLessOrEqualThan('age', 50) + ->filterIn('address.state', ['FL', 'NY']) + ->filterNotIn('address.zip', [10, 11, 12, 13]) + ->filterLike('job.title', '%Gangster%') + ->build(); + + $this->assertCount(9, $criteria->filters()); + } + + public function testShouldSetOrderByAndOrderType(): void + { + $criteria = (new CriteriaBuilder()) + ->orderedBy('name') + ->orderedType('desc') + ->build(); + + $this->assertEquals('name', $criteria->orderBy()); + $this->assertEquals('desc', $criteria->orderType()); + } + + public function testShouldSetPageLimitAndPageOffset(): void + { + $criteria = (new CriteriaBuilder()) + ->withLimit(50) + ->withOffset(100) + ->build(); + + $this->assertEquals(50, $criteria->pageLimit()); + $this->assertEquals(100, $criteria->pageOffset()); + } +} \ No newline at end of file