Skip to content

Commit 030292a

Browse files
authored
Feature/Add build from source. (#19)
1 parent d3406d9 commit 030292a

File tree

6 files changed

+256
-32
lines changed

6 files changed

+256
-32
lines changed

src/Contracts/CriteriaSource.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ComplexHeart\Domain\Criteria\Contracts;
6+
7+
/**
8+
* Interface CriteriaSource
9+
*
10+
* @author Unay Santisteban <usantisteban@othercode.io>
11+
* @package ComplexHeart\Domain\Criteria\Contracts
12+
*/
13+
interface CriteriaSource
14+
{
15+
/**
16+
* Provides the list of filter groups. Each filter group is a list of
17+
* filters. A filter is the combination of field or attribute, operator
18+
* and value:
19+
*
20+
* [
21+
* [
22+
* ["field" => "title", "operator" => "like", "value" => "to hero"],
23+
* ["field" => "tag", "operator" => "in", "value" => ["beginner", "intermediate"]],
24+
* ],
25+
* ];
26+
*
27+
* @return array<array<array<string, mixed>>>
28+
*/
29+
public function filterGroups(): array;
30+
31+
/**
32+
* One of: asc, desc, none or random.
33+
*
34+
* @return string
35+
*/
36+
public function orderType(): string;
37+
38+
/**
39+
* The field or attribute to order by.
40+
*
41+
* @return string
42+
*/
43+
public function orderBy(): string;
44+
45+
/**
46+
* Provides the size of a page.
47+
*
48+
* @return int
49+
*/
50+
public function pageLimit(): int;
51+
52+
/**
53+
* Provides the offset, by default should be 0.
54+
*
55+
* @return int
56+
*/
57+
public function pageOffset(): int;
58+
}

src/Criteria.php

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
use Closure;
88
use ComplexHeart\Domain\Contracts\Model\ValueObject;
9+
use ComplexHeart\Domain\Criteria\Contracts\CriteriaSource;
10+
use ComplexHeart\Domain\Criteria\Errors\CriteriaError;
911
use ComplexHeart\Domain\Model\IsValueObject;
1012

1113
use function Lambdish\Phunctional\map;
@@ -32,6 +34,27 @@ public function __construct(
3234
private readonly Order $order,
3335
private readonly Page $page,
3436
) {
37+
$this->check();
38+
}
39+
40+
protected function invariantGroupsMustBeArrayOfFilterGroup(): bool
41+
{
42+
foreach ($this->groups as $group) {
43+
if (!($group instanceof FilterGroup)) {
44+
return false;
45+
}
46+
}
47+
48+
return true;
49+
}
50+
51+
/**
52+
* @param array<string> $violations
53+
* @return void
54+
*/
55+
protected function invariantHandler(array $violations): void
56+
{
57+
throw CriteriaError::create('Unable to create criteria object.', $violations);
3558
}
3659

3760
/**
@@ -42,12 +65,30 @@ public function __construct(
4265
*/
4366
public static function create(array $groups, Order $order, Page $page): self
4467
{
45-
return new self($groups, $order, $page);
68+
return new self(groups: $groups, order: $order, page: $page);
69+
}
70+
71+
/**
72+
* Creates a new instance of Criteria from the given data source.
73+
*
74+
* @param CriteriaSource $source
75+
* @return Criteria
76+
*/
77+
public static function fromSource(CriteriaSource $source): self
78+
{
79+
return Criteria::create(
80+
groups: map(
81+
fn(array $g): FilterGroup => FilterGroup::createFromArray($g),
82+
$source->filterGroups()
83+
),
84+
order: Order::create($source->orderBy(), OrderType::make($source->orderType())),
85+
page: Page::create($source->pageLimit(), $source->pageOffset())
86+
);
4687
}
4788

4889
public static function default(): self
4990
{
50-
return self::create([], Order::none(), Page::create());
91+
return self::create(groups: [], order: Order::none(), page: Page::create());
5192
}
5293

5394
/**
@@ -58,7 +99,11 @@ public static function default(): self
5899
*/
59100
public function withFilterGroups(array $groups): self
60101
{
61-
return self::create($groups, $this->order, $this->page);
102+
return self::create(
103+
groups: $groups,
104+
order: $this->order,
105+
page: $this->page
106+
);
62107
}
63108

64109
/**
@@ -73,50 +118,61 @@ public function withFilterGroup(FilterGroup|Closure $group): self
73118
$group = $group(new FilterGroup());
74119
}
75120

76-
return $this->withFilterGroups(array_merge($this->groups, [$group]));
121+
// push single FilterGroup into an array.
122+
$group = is_array($group) ? $group : [$group];
123+
124+
return $this->withFilterGroups(groups: array_merge($this->groups, $group));
77125
}
78126

79127
public function withOrder(Order $order): self
80128
{
81-
return self::create($this->groups, $order, $this->page);
129+
return self::create(groups: $this->groups, order: $order, page: $this->page);
82130
}
83131

84132
public function withOrderRandom(): self
85133
{
86-
return self::create($this->groups, Order::random(), $this->page);
134+
return self::create(groups: $this->groups, order: Order::random(), page: $this->page);
87135
}
88136

89137
public function withOrderBy(string $field): self
90138
{
91-
return self::create($this->groups, Order::create($field, $this->order->type()), $this->page);
139+
return self::create(
140+
groups: $this->groups,
141+
order: Order::create($field, $this->order->type()),
142+
page: $this->page
143+
);
92144
}
93145

94146
public function withOrderType(string $type): self
95147
{
96148
return self::create(
97-
$this->groups,
98-
Order::create($this->orderBy(), OrderType::make($type)),
99-
$this->page
149+
groups: $this->groups,
150+
order: Order::create($this->orderBy(), OrderType::make($type)),
151+
page: $this->page
100152
);
101153
}
102154

103155
public function withPage(Page $page): self
104156
{
105-
return self::create($this->groups, $this->order, $page);
157+
return self::create(groups: $this->groups, order: $this->order, page: $page);
106158
}
107159

108160
public function withPageOffset(int $offset): self
109161
{
110162
return self::create(
111-
$this->groups,
112-
$this->order,
113-
Page::create($this->pageLimit(), $offset)
163+
groups: $this->groups,
164+
order: $this->order,
165+
page: Page::create($this->pageLimit(), $offset)
114166
);
115167
}
116168

117169
public function withPageLimit(int $limit): self
118170
{
119-
return self::create($this->groups, $this->order, Page::create($limit, $this->pageOffset()));
171+
return self::create(
172+
groups: $this->groups,
173+
order: $this->order,
174+
page: Page::create($limit, $this->pageOffset())
175+
);
120176
}
121177

122178
/**

src/Errors/CriteriaError.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ComplexHeart\Domain\Criteria\Errors;
6+
7+
use Error;
8+
use Throwable;
9+
10+
/**
11+
* Class CriteriaError
12+
*
13+
* @author Unay Santisteban <usantisteban@othercode.io>
14+
* @package ComplexHeart\Domain\Criteria\Errors
15+
*/
16+
class CriteriaError extends Error
17+
{
18+
/**
19+
* List of invariant violations.
20+
*
21+
* @var array<string>
22+
*/
23+
private array $violations;
24+
25+
/**
26+
* @param string $message
27+
* @param int $code
28+
* @param Throwable|null $previous
29+
* @param array<string> $violations
30+
*/
31+
public function __construct(string $message = "", int $code = 0, Throwable $previous = null, array $violations = [])
32+
{
33+
parent::__construct($message, $code, $previous);
34+
35+
$this->violations = $violations;
36+
}
37+
38+
/**
39+
* @param string $message
40+
* @param array<string> $violations
41+
* @param int $code
42+
* @param Throwable|null $previous
43+
* @return self
44+
*/
45+
public static function create(string $message, array $violations, int $code = 0, Throwable $previous = null): self
46+
{
47+
return new self($message, $code, $previous, $violations);
48+
}
49+
50+
/**
51+
* Returns the list of invariant violations.
52+
*
53+
* @return array<string>
54+
*/
55+
public function violations(): array
56+
{
57+
return $this->violations;
58+
}
59+
}

src/FilterGroup.php

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public function __construct(array $items = [])
3636
* @param Filter ...$filters
3737
* @return FilterGroup
3838
*/
39-
public static function create(Filter ...$filters): FilterGroup
39+
public static function create(Filter ...$filters): self
4040
{
4141
return new self(array_values($filters));
4242
}
@@ -45,7 +45,7 @@ public static function create(Filter ...$filters): FilterGroup
4545
* @param array<int, array<int|string, mixed>> $filters
4646
* @return FilterGroup
4747
*/
48-
public static function createFromArray(array $filters): FilterGroup
48+
public static function createFromArray(array $filters): self
4949
{
5050
return self::create(
5151
...map(fn(array $filter): Filter => Filter::createFromArray($filter), $filters)
@@ -59,7 +59,7 @@ public static function createFromArray(array $filters): FilterGroup
5959
*
6060
* @return self
6161
*/
62-
public function addFilter(Filter $new): FilterGroup
62+
public function addFilter(Filter $new): self
6363
{
6464
if ($this->filter(fn(Filter $filter): bool => $filter->equals($new))->count() > 0) {
6565
return $this;
@@ -70,37 +70,37 @@ public function addFilter(Filter $new): FilterGroup
7070
return $this;
7171
}
7272

73-
public function addFilterEqual(string $field, mixed $value): FilterGroup
73+
public function addFilterEqual(string $field, mixed $value): self
7474
{
7575
$this->addFilter(Filter::createEqual($field, $value));
7676
return $this;
7777
}
7878

79-
public function addFilterNotEqual(string $field, mixed $value): FilterGroup
79+
public function addFilterNotEqual(string $field, mixed $value): self
8080
{
8181
$this->addFilter(Filter::createNotEqual($field, $value));
8282
return $this;
8383
}
8484

85-
public function addFilterGreaterThan(string $field, mixed $value): FilterGroup
85+
public function addFilterGreaterThan(string $field, mixed $value): self
8686
{
8787
$this->addFilter(Filter::createGreaterThan($field, $value));
8888
return $this;
8989
}
9090

91-
public function addFilterGreaterOrEqualThan(string $field, mixed $value): FilterGroup
91+
public function addFilterGreaterOrEqualThan(string $field, mixed $value): self
9292
{
9393
$this->addFilter(Filter::createGreaterOrEqualThan($field, $value));
9494
return $this;
9595
}
9696

97-
public function addFilterLessThan(string $field, mixed $value): FilterGroup
97+
public function addFilterLessThan(string $field, mixed $value): self
9898
{
9999
$this->addFilter(Filter::createLessThan($field, $value));
100100
return $this;
101101
}
102102

103-
public function addFilterLessOrEqualThan(string $field, mixed $value): FilterGroup
103+
public function addFilterLessOrEqualThan(string $field, mixed $value): self
104104
{
105105
$this->addFilter(Filter::createLessOrEqualThan($field, $value));
106106
return $this;
@@ -111,7 +111,7 @@ public function addFilterLessOrEqualThan(string $field, mixed $value): FilterGro
111111
* @param array<scalar> $value
112112
* @return $this
113113
*/
114-
public function addFilterIn(string $field, array $value): FilterGroup
114+
public function addFilterIn(string $field, array $value): self
115115
{
116116
$this->addFilter(Filter::createIn($field, $value));
117117
return $this;
@@ -122,31 +122,31 @@ public function addFilterIn(string $field, array $value): FilterGroup
122122
* @param array<scalar> $value
123123
* @return $this
124124
*/
125-
public function addFilterNotIn(string $field, array $value): FilterGroup
125+
public function addFilterNotIn(string $field, array $value): self
126126
{
127127
$this->addFilter(Filter::createNotIn($field, $value));
128128
return $this;
129129
}
130130

131-
public function addFilterLike(string $field, string $value): FilterGroup
131+
public function addFilterLike(string $field, string $value): self
132132
{
133133
$this->addFilter(Filter::createLike($field, $value));
134134
return $this;
135135
}
136136

137-
public function addFilterNotLike(string $field, string $value): FilterGroup
137+
public function addFilterNotLike(string $field, string $value): self
138138
{
139139
$this->addFilter(Filter::createNotLike($field, $value));
140140
return $this;
141141
}
142142

143-
public function addFilterContains(string $field, string $value): FilterGroup
143+
public function addFilterContains(string $field, string $value): self
144144
{
145145
$this->addFilter(Filter::createContains($field, $value));
146146
return $this;
147147
}
148148

149-
public function addFilterNotContains(string $field, string $value): FilterGroup
149+
public function addFilterNotContains(string $field, string $value): self
150150
{
151151
$this->addFilter(Filter::createNotContains($field, $value));
152152
return $this;

0 commit comments

Comments
 (0)