Skip to content

Commit fe598fe

Browse files
authored
Merge pull request #98 from php-etl/feature/filtering-plugin
Added the filtering plugin
2 parents ae0c097 + 5291cf1 commit fe598fe

File tree

12 files changed

+815
-1
lines changed

12 files changed

+815
-1
lines changed

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@
109109
"Kiboko\\Component\\Satellite\\Plugin\\Stream\\Service",
110110
"Kiboko\\Component\\Satellite\\Plugin\\SFTP\\Service",
111111
"Kiboko\\Component\\Satellite\\Plugin\\FTP\\Service",
112-
"Kiboko\\Component\\Satellite\\Plugin\\Batching\\Service"
112+
"Kiboko\\Component\\Satellite\\Plugin\\Batching\\Service",
113+
"Kiboko\\Component\\Satellite\\Plugin\\Filtering\\Service"
113114
]
114115
}
115116
},

src/Plugin/Filtering/Builder/Drop.php

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Satellite\Plugin\Filtering\Builder;
6+
7+
use Kiboko\Component\Bucket\AcceptanceResultBucket;
8+
use Kiboko\Component\Bucket\RejectionResultBucket;
9+
use Kiboko\Contract\Configurator\StepBuilderInterface;
10+
use Kiboko\Contract\Pipeline\TransformerInterface;
11+
use PhpParser\Builder;
12+
use PhpParser\Node;
13+
14+
final class Drop implements StepBuilderInterface
15+
{
16+
private ?Node\Expr $logger = null;
17+
private ?Node\Expr $rejection = null;
18+
private ?Node\Expr $state = null;
19+
/** @var list<?Node\Expr> */
20+
private array $exclusions = [];
21+
22+
public function __construct()
23+
{
24+
}
25+
26+
public function withLogger(Node\Expr $logger): self
27+
{
28+
$this->logger = $logger;
29+
30+
return $this;
31+
}
32+
33+
public function withRejection(Node\Expr $rejection): self
34+
{
35+
$this->rejection = $rejection;
36+
37+
return $this;
38+
}
39+
40+
public function withState(Node\Expr $state): self
41+
{
42+
$this->state = $state;
43+
44+
return $this;
45+
}
46+
47+
public function withExclusions(Node\Expr ...$exclusions): self
48+
{
49+
array_push($this->exclusions, ...$exclusions);
50+
51+
return $this;
52+
}
53+
54+
private function buildExclusions(Node\Expr ...$exclusions): Node\Expr
55+
{
56+
if (\count($exclusions) > 3) {
57+
$length = \count($exclusions);
58+
$middle = (int) floor($length / 2);
59+
$left = \array_slice($exclusions, 0, $middle);
60+
$right = \array_slice($exclusions, $middle, $length);
61+
62+
return new Node\Expr\BinaryOp\BooleanAnd(
63+
$this->buildExclusions(...$left),
64+
$this->buildExclusions(...$right),
65+
);
66+
}
67+
68+
if (\count($exclusions) > 2) {
69+
$right = array_shift($exclusions);
70+
71+
return new Node\Expr\BinaryOp\BooleanAnd(
72+
$this->buildExclusions(...$exclusions),
73+
$right,
74+
);
75+
}
76+
77+
if (\count($exclusions) > 1) {
78+
$left = array_pop($exclusions);
79+
$right = array_pop($exclusions);
80+
81+
return new Node\Expr\BinaryOp\BooleanAnd(
82+
$left,
83+
$right,
84+
);
85+
}
86+
87+
if (\count($exclusions) > 0) {
88+
return array_pop($exclusions);
89+
}
90+
91+
return new Node\Expr\ConstFetch(
92+
new Node\Name('false'),
93+
);
94+
}
95+
96+
public function getNode(): Node
97+
{
98+
return new Node\Expr\New_(
99+
class: new Node\Stmt\Class_(null, [
100+
'implements' => [
101+
new Node\Name\FullyQualified(TransformerInterface::class),
102+
],
103+
'stmts' => [
104+
(new Builder\Method('transform'))
105+
->makePublic()
106+
->setReturnType(new Node\Name\FullyQualified(\Generator::class))
107+
->addStmts([
108+
new Node\Stmt\Expression(
109+
new Node\Expr\Assign(
110+
new Node\Expr\Variable('input'),
111+
new Node\Expr\Yield_(),
112+
)
113+
),
114+
new Node\Stmt\While_(
115+
new Node\Expr\ConstFetch(
116+
new Node\Name('true'),
117+
),
118+
[
119+
new Node\Stmt\If_(
120+
$this->buildExclusions(...$this->exclusions),
121+
[
122+
'stmts' => [
123+
new Node\Stmt\Expression(
124+
new Node\Expr\Assign(
125+
new Node\Expr\Variable('input'),
126+
new Node\Expr\Yield_(
127+
new Node\Expr\New_(
128+
new Node\Name\FullyQualified(RejectionResultBucket::class),
129+
),
130+
),
131+
),
132+
),
133+
new Node\Stmt\Continue_(),
134+
],
135+
]
136+
),
137+
new Node\Stmt\Expression(
138+
new Node\Expr\Assign(
139+
new Node\Expr\Variable('input'),
140+
new Node\Expr\Yield_(
141+
new Node\Expr\New_(
142+
new Node\Name\FullyQualified(AcceptanceResultBucket::class),
143+
[
144+
new Node\Arg(new Node\Expr\Variable('input')),
145+
]
146+
),
147+
),
148+
),
149+
),
150+
],
151+
),
152+
new Node\Stmt\Expression(
153+
new Node\Expr\Yield_(
154+
new Node\Expr\Variable('input')
155+
),
156+
),
157+
])
158+
->getNode(),
159+
],
160+
])
161+
);
162+
}
163+
}
+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Satellite\Plugin\Filtering\Builder;
6+
7+
use Kiboko\Component\Bucket\AcceptanceResultBucket;
8+
use Kiboko\Component\Bucket\RejectionResultBucket;
9+
use Kiboko\Contract\Configurator\StepBuilderInterface;
10+
use Kiboko\Contract\Pipeline\TransformerInterface;
11+
use PhpParser\Builder;
12+
use PhpParser\Node;
13+
14+
final class Reject implements StepBuilderInterface
15+
{
16+
private ?Node\Expr $logger = null;
17+
private ?Node\Expr $rejection = null;
18+
private ?Node\Expr $state = null;
19+
/** @var list<?Node\Expr> */
20+
private array $exclusions = [];
21+
22+
public function __construct()
23+
{
24+
}
25+
26+
public function withLogger(Node\Expr $logger): self
27+
{
28+
$this->logger = $logger;
29+
30+
return $this;
31+
}
32+
33+
public function withRejection(Node\Expr $rejection): self
34+
{
35+
$this->rejection = $rejection;
36+
37+
return $this;
38+
}
39+
40+
public function withState(Node\Expr $state): self
41+
{
42+
$this->state = $state;
43+
44+
return $this;
45+
}
46+
47+
public function withExclusions(Node\Expr ...$exclusions): self
48+
{
49+
array_push($this->exclusions, ...$exclusions);
50+
51+
return $this;
52+
}
53+
54+
private function buildExclusions(Node\Expr ...$exclusions): Node\Expr
55+
{
56+
if (\count($exclusions) > 3) {
57+
$length = \count($exclusions);
58+
$middle = (int) floor($length / 2);
59+
$left = \array_slice($exclusions, 0, $middle);
60+
$right = \array_slice($exclusions, $middle, $length);
61+
62+
return new Node\Expr\BinaryOp\BooleanAnd(
63+
$this->buildExclusions(...$left),
64+
$this->buildExclusions(...$right),
65+
);
66+
}
67+
68+
if (\count($exclusions) > 2) {
69+
$right = array_shift($exclusions);
70+
71+
return new Node\Expr\BinaryOp\BooleanAnd(
72+
$this->buildExclusions(...$exclusions),
73+
$right,
74+
);
75+
}
76+
77+
if (\count($exclusions) > 1) {
78+
$left = array_pop($exclusions);
79+
$right = array_pop($exclusions);
80+
81+
return new Node\Expr\BinaryOp\BooleanAnd(
82+
$left,
83+
$right,
84+
);
85+
}
86+
87+
if (\count($exclusions) > 0) {
88+
return array_pop($exclusions);
89+
}
90+
91+
return new Node\Expr\ConstFetch(
92+
new Node\Name('false'),
93+
);
94+
}
95+
96+
public function getNode(): Node
97+
{
98+
return new Node\Expr\New_(
99+
class: new Node\Stmt\Class_(null, [
100+
'implements' => [
101+
new Node\Name\FullyQualified(TransformerInterface::class),
102+
],
103+
'stmts' => [
104+
(new Builder\Method('transform'))
105+
->makePublic()
106+
->setReturnType(new Node\Name\FullyQualified(\Generator::class))
107+
->addStmts([
108+
new Node\Stmt\Expression(
109+
new Node\Expr\Assign(
110+
new Node\Expr\Variable('input'),
111+
new Node\Expr\Yield_(),
112+
)
113+
),
114+
new Node\Stmt\While_(
115+
new Node\Expr\ConstFetch(
116+
new Node\Name('true'),
117+
),
118+
[
119+
new Node\Stmt\If_(
120+
$this->buildExclusions(...$this->exclusions),
121+
[
122+
'stmts' => [
123+
new Node\Stmt\Expression(
124+
new Node\Expr\Assign(
125+
new Node\Expr\Variable('input'),
126+
new Node\Expr\Yield_(
127+
new Node\Expr\New_(
128+
new Node\Name\FullyQualified(RejectionResultBucket::class),
129+
[
130+
new Node\Arg(new Node\Expr\Variable('input')),
131+
]
132+
),
133+
),
134+
),
135+
),
136+
new Node\Stmt\Continue_(),
137+
],
138+
]
139+
),
140+
new Node\Stmt\Expression(
141+
new Node\Expr\Assign(
142+
new Node\Expr\Variable('input'),
143+
new Node\Expr\Yield_(
144+
new Node\Expr\New_(
145+
new Node\Name\FullyQualified(AcceptanceResultBucket::class),
146+
[
147+
new Node\Arg(new Node\Expr\Variable('input')),
148+
]
149+
),
150+
),
151+
),
152+
),
153+
],
154+
),
155+
new Node\Stmt\Expression(
156+
new Node\Expr\Yield_(
157+
new Node\Expr\Variable('input')
158+
),
159+
),
160+
])
161+
->getNode(),
162+
],
163+
])
164+
);
165+
}
166+
}
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Kiboko\Component\Satellite\Plugin\Filtering;
6+
7+
use Kiboko\Contract\Configurator\PluginConfigurationInterface;
8+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
9+
10+
use function Kiboko\Component\SatelliteToolbox\Configuration\mutuallyExclusiveFields;
11+
12+
final class Configuration implements PluginConfigurationInterface
13+
{
14+
public function getConfigTreeBuilder(): TreeBuilder
15+
{
16+
$reject = new Configuration\Reject();
17+
$drop = new Configuration\Drop();
18+
19+
$builder = new TreeBuilder('filter');
20+
21+
/* @phpstan-ignore-next-line */
22+
$builder->getRootNode()
23+
->validate()
24+
->always($this->cleanupFields('reject', 'drop'))
25+
->end()
26+
->validate()
27+
->always(mutuallyExclusiveFields('reject', 'drop'))
28+
->end()
29+
->children()
30+
->arrayNode('expression_language')
31+
->scalarPrototype()->end()
32+
->end()
33+
->append(node: $reject->getConfigTreeBuilder()->getRootNode())
34+
->append(node: $drop->getConfigTreeBuilder()->getRootNode())
35+
->end()
36+
;
37+
38+
return $builder;
39+
}
40+
41+
private function cleanupFields(string ...$fieldNames): \Closure
42+
{
43+
return function (array $value) use ($fieldNames) {
44+
foreach ($fieldNames as $fieldName) {
45+
if (!\array_key_exists($fieldName, $value)) {
46+
continue;
47+
}
48+
49+
if (!\is_array($value[$fieldName]) || \count($value[$fieldName]) <= 0) {
50+
unset($value[$fieldName]);
51+
}
52+
}
53+
54+
return $value;
55+
};
56+
}
57+
}

0 commit comments

Comments
 (0)