Skip to content

Commit e973d99

Browse files
committed
Refactored the way filters are handled
1 parent 1442b14 commit e973d99

12 files changed

+596
-97
lines changed

src/CustomerExtractor.php

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,59 +6,71 @@
66

77
use Kiboko\Component\Bucket\AcceptanceResultBucket;
88
use Kiboko\Component\Bucket\RejectionResultBucket;
9+
use Kiboko\Component\Flow\Magento2\Filter\FilterInterface;
910
use Kiboko\Contract\Bucket\ResultBucketInterface;
1011
use Kiboko\Contract\Pipeline\ExtractorInterface;
1112
use Psr\Http\Client\NetworkExceptionInterface;
1213

1314
final class CustomerExtractor implements ExtractorInterface
1415
{
15-
private array $queryParameters = [
16-
'searchCriteria[currentPage]' => 1,
17-
'searchCriteria[pageSize]' => 100,
18-
];
19-
2016
public function __construct(
2117
private readonly \Psr\Log\LoggerInterface $logger,
2218
private readonly \Kiboko\Magento\V2_1\Client|\Kiboko\Magento\V2_2\Client|\Kiboko\Magento\V2_3\Client|\Kiboko\Magento\V2_4\Client $client,
19+
private readonly QueryParameters $queryParameters,
2320
private readonly int $pageSize = 100,
24-
/** @var FilterGroup[] $filters */
25-
private readonly array $filters = [],
2621
) {
2722
}
2823

29-
private function compileQueryParameters(int $currentPage = 1): array
24+
private function walkFilterVariants(int $currentPage = 1): \Traversable
3025
{
31-
$parameters = $this->queryParameters;
32-
$parameters['searchCriteria[currentPage]'] = $currentPage;
33-
$parameters['searchCriteria[pageSize]'] = $this->pageSize;
26+
$parameters = [
27+
...$this->queryParameters,
28+
...[
29+
'searchCriteria[currentPage]' => $currentPage,
30+
'searchCriteria[pageSize]' => $this->pageSize,
31+
],
32+
];
3433

3534
$filters = array_map(fn (FilterGroup $item, int $key) => $item->compileFilters($key), $this->filters, array_keys($this->filters));
3635

3736
return array_merge($parameters, ...$filters);
3837
}
3938

39+
private function applyPagination(array $parameters, int $currentPage, int $pageSize): array
40+
{
41+
return [
42+
...$parameters,
43+
...[
44+
'searchCriteria[currentPage]' => $currentPage,
45+
'searchCriteria[pageSize]' => $this->pageSize,
46+
],
47+
];
48+
}
49+
4050
public function extract(): iterable
4151
{
4252
try {
43-
$response = $this->client->customerCustomerRepositoryV1GetListGet(
44-
queryParameters: $this->compileQueryParameters(),
45-
);
53+
foreach ($this->queryParameters->walkVariants([]) as $parameters) {
54+
$currentPage = 1;
55+
$response = $this->client->customerCustomerRepositoryV1GetListGet(
56+
queryParameters: $parameters,
57+
);
4658

47-
if (!$response instanceof \Kiboko\Magento\V2_1\Model\CustomerDataCustomerSearchResultsInterface
48-
&& !$response instanceof \Kiboko\Magento\V2_2\Model\CustomerDataCustomerSearchResultsInterface
49-
&& !$response instanceof \Kiboko\Magento\V2_3\Model\CustomerDataCustomerSearchResultsInterface
50-
&& !$response instanceof \Kiboko\Magento\V2_4\Model\CustomerDataCustomerSearchResultsInterface
51-
) {
52-
return;
59+
if (!$response instanceof \Kiboko\Magento\V2_1\Model\CustomerDataCustomerSearchResultsInterface
60+
&& !$response instanceof \Kiboko\Magento\V2_2\Model\CustomerDataCustomerSearchResultsInterface
61+
&& !$response instanceof \Kiboko\Magento\V2_3\Model\CustomerDataCustomerSearchResultsInterface
62+
&& !$response instanceof \Kiboko\Magento\V2_4\Model\CustomerDataCustomerSearchResultsInterface
63+
) {
64+
return;
65+
}
66+
67+
yield $this->processResponse($response);
5368
}
5469

55-
yield $this->processResponse($response);
5670

57-
$currentPage = 1;
58-
$pageCount = ceil($response->getTotalCount() / $this->pageSize);
5971
while ($currentPage++ < $pageCount) {
6072
$response = $this->client->customerCustomerRepositoryV1GetListGet(
61-
queryParameters: $this->compileQueryParameters($currentPage),
73+
queryParameters: $this->walkFilterVariants($currentPage),
6274
);
6375

6476
yield $this->processResponse($response);
@@ -71,7 +83,7 @@ public function extract(): iterable
7183
'context' => [
7284
'path' => 'customer',
7385
'method' => 'get',
74-
'queryParameters' => $this->compileQueryParameters(),
86+
'queryParameters' => $this->walkFilterVariants(),
7587
],
7688
],
7789
);

src/Filter.php

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/Filter/ArrayFilter.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Flow\Magento2\Filter;
6+
7+
final class ArrayFilter implements FilterInterface, \IteratorAggregate
8+
{
9+
public function __construct(
10+
public string $field,
11+
public string $conditionType,
12+
public array $value,
13+
private int $threshold = 200
14+
) {}
15+
16+
/**
17+
* @return \Traversable<int, {field: string, value: string, conditionType: string}>
18+
*/
19+
public function getIterator(): \Traversable
20+
{
21+
$length = count($this->value);
22+
for ($offset = 0; $offset < $length; $offset += $this->threshold) {
23+
yield [
24+
'field' => $this->field,
25+
'value' => implode(',', array_slice($this->value, $offset, $this->threshold, false)),
26+
'conditionType' => $this->conditionType,
27+
];
28+
}
29+
}
30+
}

src/Filter/FilterInterface.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Flow\Magento2\Filter;
6+
7+
/**
8+
* @extends \Traversable<int, {field: string, value: string, conditionType: string}>
9+
*/
10+
interface FilterInterface extends \Traversable
11+
{
12+
}

src/Filter/ScalarFilter.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Flow\Magento2\Filter;
6+
7+
final class ScalarFilter implements FilterInterface, \IteratorAggregate
8+
{
9+
public function __construct(
10+
public string $field,
11+
public string $conditionType,
12+
public bool|int|float|string|\DateTimeInterface $value,
13+
) {}
14+
15+
public function getIterator(): \Traversable
16+
{
17+
yield [
18+
'field' => $this->field,
19+
'value' => $this->value,
20+
'conditionType' => $this->conditionType,
21+
];
22+
}
23+
}

src/FilterGroup.php

Lines changed: 38 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,84 +4,71 @@
44

55
namespace Kiboko\Component\Flow\Magento2;
66

7+
use Kiboko\Component\Flow\Magento2\Filter\FilterInterface;
8+
use Kiboko\Component\Flow\Magento2\Filter\ScalarFilter;
9+
710
class FilterGroup
811
{
912
private array $filters = [];
10-
private array $longFilters = [];
11-
private int $offset = 0;
12-
private int $lenght = 200;
1313

14-
public function withFilter(Filter $filter): self
14+
public function withFilter(FilterInterface $filter): self
1515
{
16-
$this->filters[] = [
17-
'field' => $filter->field,
18-
'value' => $filter->value,
19-
'condition_type' => $filter->conditionType,
20-
];
16+
$this->filters[] = $filter;
2117

2218
return $this;
2319
}
2420

25-
public function withLongFilter(Filter $filter, int $offset = 0, int $lenght = 200): self
21+
/**
22+
* @param array $parameters
23+
* @param int $groupIndex
24+
* @return \Traversable<int, array>
25+
*/
26+
public function walkFilters(array $parameters, int $groupIndex = 0): \Traversable
2627
{
27-
$this->longFilters[] = [
28-
'field' => $filter->field,
29-
'value' => $filter->value,
30-
'condition_type' => $filter->conditionType,
31-
];
32-
33-
$this->offset = $offset;
34-
$this->lenght = $lenght;
28+
if (count($this->filters) < 1) {
29+
return;
30+
}
3531

36-
return $this;
32+
yield from $this->buildFilters($parameters, $groupIndex, 1, ...$this->filters);
3733
}
3834

39-
public function withFilters(Filter ...$filters): self
35+
private function buildFilters(array $parameters, int $groupIndex, int $filterIndex, FilterInterface $first, FilterInterface ...$next): \Traversable
4036
{
41-
array_walk($filters, fn (Filter $filter) => $this->filters[] = [
42-
'field' => $filter->field,
43-
'value' => $filter->value,
44-
'condition_type' => $filter->conditionType,
45-
]);
37+
foreach ($first as $current) {
38+
$childParameters = [
39+
...$parameters,
40+
...[
41+
sprintf('searchCriteria[filterGroups][%s][filters][%s][field]', $groupIndex, $filterIndex) => $current['field'],
42+
sprintf('searchCriteria[filterGroups][%s][filters][%s][value]', $groupIndex, $filterIndex) => $current['value'],
43+
sprintf('searchCriteria[filterGroups][%s][filters][%s][conditionType]', $groupIndex, $filterIndex) => $current['conditionType'],
44+
]
45+
];
4646

47-
return $this;
48-
}
49-
50-
private function sliceFilter(string $value): iterable
51-
{
52-
$iterator = new \ArrayIterator(explode(',', $value));
53-
while ($this->offset < iterator_count($iterator)) {
54-
$filteredValue = \array_slice(iterator_to_array($iterator), $this->offset, $this->lenght);
55-
$this->offset += $this->lenght;
56-
yield $filteredValue;
47+
if (count($next) >= 1) {
48+
yield from $this->buildFilters($childParameters, $groupIndex, $filterIndex + 1, ...$next);
49+
} else {
50+
yield $childParameters;
51+
}
5752
}
5853
}
5954

60-
public function compileLongFilters(int $groupIndex = 0)
55+
public function greaterThan(string $field, int|float|string|\DateTimeInterface $value): self
6156
{
62-
return array_merge(...array_map(fn (array $item, int $key) => [
63-
sprintf('searchCriteria[filterGroups][%s][filters][%s][field]', $groupIndex, $key) => $item['field'],
64-
sprintf('searchCriteria[filterGroups][%s][filters][%s][value]', $groupIndex, $key) => iterator_to_array($this->sliceFilter($item['value'])),
65-
sprintf('searchCriteria[filterGroups][%s][filters][%s][conditionType]', $groupIndex, $key) => $item['condition_type'],
66-
], $this->longFilters, array_keys($this->longFilters)));
57+
return $this->withFilter(new ScalarFilter($field, 'gt', $value));
6758
}
6859

69-
public function compileFilters(int $groupIndex = 0): array
60+
public function lowerThan(string $field, int|float|string|\DateTimeInterface $value): self
7061
{
71-
return array_merge(...array_map(fn (array $item, int $key) => [
72-
sprintf('searchCriteria[filterGroups][%s][filters][%s][field]', $groupIndex, $key) => $item['field'],
73-
sprintf('searchCriteria[filterGroups][%s][filters][%s][value]', $groupIndex, $key) => $item['value'],
74-
sprintf('searchCriteria[filterGroups][%s][filters][%s][conditionType]', $groupIndex, $key) => $item['condition_type'],
75-
], $this->filters, array_keys($this->filters)));
62+
return $this->withFilter(new ScalarFilter($field, 'lt', $value));
7663
}
7764

78-
public function greaterThan(string $field, mixed $value): self
65+
public function greaterThanOrEqual(string $field, int|float|string|\DateTimeInterface $value): self
7966
{
80-
return $this->withFilter(new Filter($field, 'gt', $value));
67+
return $this->withFilter(new ScalarFilter($field, 'gteq', $value));
8168
}
8269

83-
public function greaterThanEqual(string $field, mixed $value): self
70+
public function lowerThanOrEqual(string $field, int|float|string|\DateTimeInterface $value): self
8471
{
85-
return $this->withFilter(new Filter($field, 'gteq', $value));
72+
return $this->withFilter(new ScalarFilter($field, 'lteq', $value));
8673
}
8774
}

src/QueryParameters.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Flow\Magento2;
6+
7+
final class QueryParameters
8+
{
9+
/** @var list<FilterGroup> */
10+
private array $groups = [];
11+
12+
public function withGroup(FilterGroup $group): self
13+
{
14+
$this->groups[] = $group;
15+
16+
return $this;
17+
}
18+
19+
/**
20+
* @return \Traversable<int, array>
21+
*/
22+
public function walkVariants(array $parameters): \Traversable
23+
{
24+
if (count($this->groups) < 1) {
25+
return;
26+
}
27+
28+
yield from $this->buildFilters($parameters, 0, ...$this->groups);
29+
}
30+
31+
private function buildFilters(array $parameters, int $groupIndex, FilterGroup $first, FilterGroup ...$next): \Traversable
32+
{
33+
foreach ($first->walkFilters($parameters, $groupIndex) as $current) {
34+
if (count($next) >= 1) {
35+
yield from $this->buildFilters($current, $groupIndex + 1, ...$next);
36+
} else {
37+
yield $current;
38+
}
39+
}
40+
}
41+
}

tests/CustomerExtractorTest.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
namespace Tests\Kiboko\Magento\V2\Extractor;
66

77
use Kiboko\Component\Flow\Magento2\CustomerExtractor;
8-
use Kiboko\Component\Flow\Magento2\Filter;
8+
use Kiboko\Component\Flow\Magento2\Filter\ScalarFilter;
99
use Kiboko\Component\Flow\Magento2\FilterGroup;
10+
use Kiboko\Component\Flow\Magento2\QueryParameters;
1011
use Kiboko\Component\PHPUnitExtension\Assert\ExtractorAssertTrait;
1112
use Kiboko\Component\PHPUnitExtension\PipelineRunner;
1213
use Kiboko\Contract\Pipeline\PipelineRunnerInterface;
@@ -48,11 +49,15 @@ public function testIsSuccessful(): void
4849
$extractor = new CustomerExtractor(
4950
new NullLogger(),
5051
$client,
51-
1,
52-
[
53-
(new FilterGroup())->withFilter(new Filter('updated_at', 'eq', '2022-09-05')),
54-
(new FilterGroup())->withFilter(new Filter('active', 'eq', true)),
55-
]
52+
(new QueryParameters())
53+
->withGroup(
54+
(new FilterGroup())
55+
->withFilter(new ScalarFilter('updated_at', 'eq', '2022-09-05')),
56+
)
57+
->withGroup(
58+
(new FilterGroup())
59+
->withFilter(new ScalarFilter('active', 'eq', true)),
60+
)
5661
);
5762

5863
$this->assertExtractorExtractsExactly(

0 commit comments

Comments
 (0)