-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
ExpandArrayParameters.php
141 lines (109 loc) · 3.62 KB
/
ExpandArrayParameters.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?php
declare(strict_types=1);
namespace Doctrine\DBAL;
use Doctrine\DBAL\ArrayParameters\Exception\InvalidParameterType;
use Doctrine\DBAL\ArrayParameters\Exception\MissingNamedParameter;
use Doctrine\DBAL\ArrayParameters\Exception\MissingPositionalParameter;
use Doctrine\DBAL\SQL\Parser\Visitor;
use Doctrine\DBAL\Types\Type;
use function array_fill;
use function array_key_exists;
use function count;
use function implode;
use function is_int;
use function substr;
final class ExpandArrayParameters implements Visitor
{
private int $originalParameterIndex = 0;
/** @var list<string> */
private array $convertedSQL = [];
/** @var list<mixed> */
private array $convertedParameters = [];
/** @var array<int,string|ParameterType|Type> */
private array $convertedTypes = [];
/**
* @param array<int, mixed>|array<string, mixed> $parameters
* @param array<int,int|string|ParameterType|Type>|array<string,int|string|ParameterType|Type> $types
*/
public function __construct(private readonly array $parameters, private readonly array $types)
{
}
public function acceptPositionalParameter(string $sql): void
{
$index = $this->originalParameterIndex;
if (! array_key_exists($index, $this->parameters)) {
throw MissingPositionalParameter::new($index);
}
$this->acceptParameter($index, $this->parameters[$index]);
$this->originalParameterIndex++;
}
public function acceptNamedParameter(string $sql): void
{
$name = substr($sql, 1);
if (! array_key_exists($name, $this->parameters)) {
throw MissingNamedParameter::new($name);
}
$this->acceptParameter($name, $this->parameters[$name]);
}
public function acceptOther(string $sql): void
{
$this->convertedSQL[] = $sql;
}
public function getSQL(): string
{
return implode('', $this->convertedSQL);
}
/**
* @return list<mixed>
*/
public function getParameters(): array
{
return $this->convertedParameters;
}
/**
* @throws InvalidParameterType
*/
private function acceptParameter(int|string $key, mixed $value): void
{
if (! isset($this->types[$key])) {
$this->convertedSQL[] = '?';
$this->convertedParameters[] = $value;
return;
}
$type = $this->types[$key];
if (! is_int($type)) {
$this->appendTypedParameter([$value], $type);
return;
}
if (count($value) === 0) {
$this->convertedSQL[] = 'NULL';
return;
}
$this->appendTypedParameter($value, match ($type) {
Connection::PARAM_INT_ARRAY => ParameterType::INTEGER,
Connection::PARAM_STR_ARRAY => ParameterType::STRING,
Connection::PARAM_ASCII_STR_ARRAY => ParameterType::ASCII,
default => throw InvalidParameterType::new($type),
});
}
/**
* @return array<int,string|ParameterType|Type>
*/
public function getTypes(): array
{
return $this->convertedTypes;
}
/**
* @param list<mixed> $values
*/
private function appendTypedParameter(array $values, string|ParameterType|Type $type): void
{
$this->convertedSQL[] = implode(', ', array_fill(0, count($values), '?'));
$index = count($this->convertedParameters);
foreach ($values as $value) {
$this->convertedParameters[] = $value;
$this->convertedTypes[$index] = $type;
$index++;
}
}
}