Skip to content

Commit 7531f60

Browse files
committed
add option "from" to allow to bind multiple parameters even if their number is unknown,
interpret expressions in "query" when reading the configuration
1 parent 03a1347 commit 7531f60

File tree

6 files changed

+198
-117
lines changed

6 files changed

+198
-117
lines changed

src/Builder/AlternativeLookup.php

Lines changed: 138 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -34,71 +34,78 @@ public function withState(Node\Expr $state): StepBuilderInterface
3434
return $this;
3535
}
3636

37-
public function addStringParam(int|string $key, Node\Expr $param): StepBuilderInterface
37+
public function addStringParam(int|string $key, Node\Expr $param, null|bool $iterable = false): StepBuilderInterface
3838
{
3939
$this->parameters[$key] = [
4040
'value' => $param,
4141
'type' => 'string',
42+
'iterable' => $iterable,
4243
];
4344

4445
return $this;
4546
}
4647

47-
public function addIntegerParam(int|string $key, Node\Expr $param): StepBuilderInterface
48+
public function addIntegerParam(int|string $key, Node\Expr $param, null|bool $iterable = false): StepBuilderInterface
4849
{
4950
$this->parameters[$key] = [
5051
'value' => $param,
5152
'type' => 'integer',
53+
'iterable' => $iterable,
5254
];
5355

5456
return $this;
5557
}
5658

57-
public function addBooleanParam(int|string $key, Node\Expr $param): StepBuilderInterface
59+
public function addBooleanParam(int|string $key, Node\Expr $param, null|bool $iterable = false): StepBuilderInterface
5860
{
5961
$this->parameters[$key] = [
6062
'value' => $param,
6163
'type' => 'boolean',
64+
'iterable' => $iterable,
6265
];
6366

6467
return $this;
6568
}
6669

67-
public function addDateParam(int|string $key, Node\Expr $param): self
70+
public function addDateParam(int|string $key, Node\Expr $param, null|bool $iterable = false): self
6871
{
6972
$this->parameters[$key] = [
7073
'value' => $param,
7174
'type' => 'date',
75+
'iterable' => $iterable,
7276
];
7377

7478
return $this;
7579
}
7680

77-
public function addDateTimeParam(int|string $key, Node\Expr $param): self
81+
public function addDateTimeParam(int|string $key, Node\Expr $param, null|bool $iterable = false): self
7882
{
7983
$this->parameters[$key] = [
8084
'value' => $param,
8185
'type' => 'datetime',
86+
'iterable' => $iterable,
8287
];
8388

8489
return $this;
8590
}
8691

87-
public function addJSONParam(int|string $key, Node\Expr $param): self
92+
public function addJSONParam(int|string $key, Node\Expr $param, null|bool $iterable = false): self
8893
{
8994
$this->parameters[$key] = [
9095
'value' => $param,
9196
'type' => 'json',
97+
'iterable' => $iterable,
9298
];
9399

94100
return $this;
95101
}
96102

97-
public function addBinaryParam(int|string $key, Node\Expr $param): self
103+
public function addBinaryParam(int|string $key, Node\Expr $param, null|bool $iterable = false): self
98104
{
99105
$this->parameters[$key] = [
100106
'value' => $param,
101107
'type' => 'binary',
108+
'iterable' => $iterable,
102109
];
103110

104111
return $this;
@@ -151,7 +158,7 @@ public function getAlternativeLookupNode(): Node
151158
),
152159
),
153160
),
154-
...$this->compileParameters(),
161+
...$this->getParameters(),
155162
new Node\Stmt\Expression(
156163
expr: new Node\Expr\MethodCall(
157164
var: new Node\Expr\Variable('stmt'),
@@ -233,121 +240,141 @@ class: new Node\Name\FullyQualified('PDO'),
233240
))->getNode();
234241
}
235242

236-
public function compileParameters(): iterable
243+
public function getParameters(): iterable
237244
{
238245
foreach ($this->parameters as $key => $parameter) {
239-
yield match ($parameter['type']) {
240-
'datetime' => new Node\Stmt\Expression(
241-
new Node\Expr\MethodCall(
242-
var: new Node\Expr\Variable('stmt'),
243-
name: new Node\Identifier('bindValue'),
244-
args: [
245-
new Node\Arg(
246-
\is_string($key) ? new Node\Scalar\Encapsed(
247-
[
248-
new Node\Scalar\EncapsedStringPart(':'),
249-
new Node\Scalar\EncapsedStringPart($key),
250-
]
251-
) : new Node\Scalar\LNumber($key)
252-
),
253-
new Node\Arg(
254-
value: new Node\Expr\StaticCall(
255-
class: new Node\Name('DateTimeImmutable'),
256-
name: new Node\Name('createFromFormat'),
257-
args: [
258-
new Node\Arg(
259-
value: new Node\Scalar\String_('YYYY-MM-DD HH:MI:SS')
260-
),
261-
new Node\Arg(
262-
value: $parameter['value']
263-
),
264-
],
246+
if (\array_key_exists('iterable', $parameter) && true === $parameter['iterable']) {
247+
yield new Node\Stmt\Foreach_(
248+
expr: $parameter['value'],
249+
valueVar: new Node\Expr\Variable('value'),
250+
subNodes: [
251+
'keyVar' => new Node\Expr\Variable('key'),
252+
'stmts' => [
253+
$this->compileParameters(
254+
new Node\Arg(
255+
new Node\Expr\BinaryOp\Concat(
256+
new Node\Scalar\String_($key.'_'),
257+
new Node\Expr\Variable('key'),
258+
)
265259
),
260+
[
261+
'type' => $parameter['type'],
262+
'value' => new Node\Expr\Variable('value'),
263+
]
266264
),
267-
$this->compileParameterType($parameter),
268265
],
269-
),
270-
),
271-
'date' => new Node\Stmt\Expression(
272-
new Node\Expr\MethodCall(
273-
var: new Node\Expr\Variable('stmt'),
274-
name: new Node\Identifier('bindValue'),
275-
args: [
276-
new Node\Arg(
277-
\is_string($key) ? new Node\Scalar\Encapsed(
278-
[
279-
new Node\Scalar\EncapsedStringPart(':'),
280-
new Node\Scalar\EncapsedStringPart($key),
281-
]
282-
) : new Node\Scalar\LNumber($key)
283-
),
284-
new Node\Arg(
285-
value: new Node\Expr\StaticCall(
286-
class: new Node\Name('DateTimeImmutable'),
287-
name: new Node\Name('createFromFormat'),
288-
args: [
289-
new Node\Arg(
290-
value: new Node\Scalar\String_('YYYY-MM-DD')
291-
),
292-
new Node\Arg(
293-
value: $parameter['value']
294-
),
295-
],
296-
),
266+
]
267+
);
268+
} else {
269+
yield $this->compileParameters($key, $parameter);
270+
}
271+
}
272+
}
273+
274+
private function compileParameters(int|string|Node\Arg $key, array $parameter): Node\Stmt\Expression
275+
{
276+
return match ($parameter['type']) {
277+
'datetime' => new Node\Stmt\Expression(
278+
new Node\Expr\MethodCall(
279+
var: new Node\Expr\Variable('stmt'),
280+
name: new Node\Identifier('bindValue'),
281+
args: [
282+
$this->compileParameterKey($key),
283+
new Node\Arg(
284+
value: new Node\Expr\StaticCall(
285+
class: new Node\Name('DateTimeImmutable'),
286+
name: new Node\Name('createFromFormat'),
287+
args: [
288+
new Node\Arg(
289+
value: new Node\Scalar\String_('YYYY-MM-DD HH:MI:SS')
290+
),
291+
new Node\Arg(
292+
value: $parameter['value']
293+
),
294+
],
297295
),
298-
$this->compileParameterType($parameter),
299-
],
300-
),
296+
),
297+
$this->compileParameterType($parameter),
298+
],
301299
),
302-
'json' => new Node\Stmt\Expression(
303-
new Node\Expr\MethodCall(
304-
var: new Node\Expr\Variable('stmt'),
305-
name: new Node\Identifier('bindValue'),
306-
args: [
307-
new Node\Arg(
308-
\is_string($key) ? new Node\Scalar\Encapsed(
309-
[
310-
new Node\Scalar\EncapsedStringPart(':'),
311-
new Node\Scalar\EncapsedStringPart($key),
312-
]
313-
) : new Node\Scalar\LNumber($key)
314-
),
315-
new Node\Arg(
316-
new Node\Expr\FuncCall(
317-
name: new Node\Name('json_decode'),
318-
args: [
319-
new Node\Arg(
320-
value: $parameter['value']
321-
),
322-
],
323-
),
300+
),
301+
'date' => new Node\Stmt\Expression(
302+
new Node\Expr\MethodCall(
303+
var: new Node\Expr\Variable('stmt'),
304+
name: new Node\Identifier('bindValue'),
305+
args: [
306+
$this->compileParameterKey($key),
307+
new Node\Arg(
308+
value: new Node\Expr\StaticCall(
309+
class: new Node\Name('DateTimeImmutable'),
310+
name: new Node\Name('createFromFormat'),
311+
args: [
312+
new Node\Arg(
313+
value: new Node\Scalar\String_('YYYY-MM-DD')
314+
),
315+
new Node\Arg(
316+
value: $parameter['value']
317+
),
318+
],
324319
),
325-
$this->compileParameterType($parameter),
326-
],
327-
),
320+
),
321+
$this->compileParameterType($parameter),
322+
],
328323
),
329-
default => new Node\Stmt\Expression(
330-
new Node\Expr\MethodCall(
331-
var: new Node\Expr\Variable('stmt'),
332-
name: new Node\Identifier('bindValue'),
333-
args: [
334-
new Node\Arg(
335-
\is_string($key) ? new Node\Scalar\Encapsed(
336-
[
337-
new Node\Scalar\EncapsedStringPart(':'),
338-
new Node\Scalar\EncapsedStringPart($key),
339-
]
340-
) : new Node\Scalar\LNumber($key)
341-
),
342-
new Node\Arg(
343-
$parameter['value']
324+
),
325+
'json' => new Node\Stmt\Expression(
326+
new Node\Expr\MethodCall(
327+
var: new Node\Expr\Variable('stmt'),
328+
name: new Node\Identifier('bindValue'),
329+
args: [
330+
$this->compileParameterKey($key),
331+
new Node\Arg(
332+
new Node\Expr\FuncCall(
333+
name: new Node\Name('json_decode'),
334+
args: [
335+
new Node\Arg(
336+
value: $parameter['value']
337+
),
338+
],
344339
),
345-
$this->compileParameterType($parameter),
346-
],
347-
),
340+
),
341+
$this->compileParameterType($parameter),
342+
],
343+
),
344+
),
345+
default => new Node\Stmt\Expression(
346+
new Node\Expr\MethodCall(
347+
var: new Node\Expr\Variable('stmt'),
348+
name: new Node\Identifier('bindValue'),
349+
args: [
350+
$this->compileParameterKey($key),
351+
new Node\Arg(
352+
$parameter['value']
353+
),
354+
$this->compileParameterType($parameter),
355+
],
348356
),
349-
};
357+
),
358+
};
359+
}
360+
361+
private function compileParameterKey(int|string|Node\Arg $key): Node\Arg
362+
{
363+
if (\is_string($key)) {
364+
return new Node\Arg(
365+
new Node\Scalar\Encapsed([
366+
new Node\Scalar\EncapsedStringPart(':'),
367+
new Node\Scalar\EncapsedStringPart($key),
368+
])
369+
);
370+
}
371+
if ($key instanceof Node\Arg) {
372+
return $key;
350373
}
374+
375+
return new Node\Arg(
376+
new Node\Scalar\LNumber($key)
377+
);
351378
}
352379

353380
private function compileParameterType(array $parameter): Node\Arg

src/Configuration/Extractor.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
88
use Symfony\Component\Config\Definition\ConfigurationInterface;
99

10+
use function Kiboko\Component\SatelliteToolbox\Configuration\asExpression;
11+
use function Kiboko\Component\SatelliteToolbox\Configuration\isExpression;
12+
1013
final class Extractor implements ConfigurationInterface
1114
{
1215
public function getConfigTreeBuilder(): TreeBuilder
@@ -15,7 +18,12 @@ public function getConfigTreeBuilder(): TreeBuilder
1518

1619
/* @phpstan-ignore-next-line */
1720
$builder->getRootNode()
18-
->append((new Query())->getConfigTreeBuilder()->getRootNode())
21+
->append((new Query())->getConfigTreeBuilder()->getRootNode()
22+
->validate()
23+
->ifTrue(isExpression())
24+
->then(asExpression())
25+
->end()
26+
)
1927
->append((new Parameters())->getConfigTreeBuilder()->getRootNode())
2028
;
2129

src/Configuration/Loader.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ public function getConfigTreeBuilder(): TreeBuilder
3535
return $data;
3636
})
3737
->end()
38-
->append((new Query())->getConfigTreeBuilder()->getRootNode())
38+
->append((new Query())->getConfigTreeBuilder()->getRootNode()
39+
->validate()
40+
->ifTrue(isExpression())
41+
->then(asExpression())
42+
->end()
43+
)
3944
->append((new Parameters())->getConfigTreeBuilder()->getRootNode())
4045
->children()
4146
->append((new FastMap\Configuration('merge'))->getConfigTreeBuilder()->getRootNode())
@@ -66,7 +71,12 @@ private function getConditionalTreeBuilder(): TreeBuilder
6671
->then(asExpression())
6772
->end()
6873
->end()
69-
->append((new Query())->getConfigTreeBuilder()->getRootNode())
74+
->append((new Query())->getConfigTreeBuilder()->getRootNode()
75+
->validate()
76+
->ifTrue(isExpression())
77+
->then(asExpression())
78+
->end()
79+
)
7080
->append((new Parameters())->getConfigTreeBuilder()->getRootNode())
7181
->append((new FastMap\Configuration('merge'))->getConfigTreeBuilder()->getRootNode())
7282
->end()

0 commit comments

Comments
 (0)