Completed
Push — master ( f40c6a...9a6de3 )
by BENOIT
04:32
created

InsertQueryBuilder::getColumns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace BenTools\Where\InsertQuery;
5
6
use BenTools\Where\Helper\Previewer;
7
8
/**
9
 * Class InsertQueryBuilder
10
 *
11
 * @property $mainKeyword
12
 * @property $flags
13
 * @property $values
14
 * @property $columns
15
 * @property $table
16
 * @property $onDuplicate
17
 * @property $end
18
 * @property $escape
19
 */
20
final class InsertQueryBuilder
21
{
22
    /**
23
     * @var string
24
     */
25
    private $mainKeyword = 'INSERT';
26
27
    /**
28
     * @var array
29
     */
30
    private $flags = [];
31
32
    /**
33
     * @var array
34
     */
35
    private $values = [];
36
37
    /**
38
     * @var array
39
     */
40
    private $columns;
41
42
    /**
43
     * @var string
44
     */
45
    private $table;
46
47
    /**
48
     * @var array
49
     */
50
    private $onDuplicate;
51
52
    /**
53
     * @var string
54
     */
55
    private $end = ';';
56
57
    /**
58
     * @var string
59
     */
60
    private $escape;
61
62
    /**
63
     * @param array[] ...$values
64
     * @return InsertQueryBuilder
65
     */
66
    public static function load(array ...$values): self
67
    {
68
        $query = new self;
69
        foreach ($values as $value) {
70
            $query->values[] = $query->validateValue($value);
71
        }
72
        return $query;
73
    }
74
75
    /**
76
     * @param array[] ...$values
77
     * @return InsertQueryBuilder
78
     */
79
    public function withValues(array ...$values): self
80
    {
81
        $clone = clone $this;
82
        $clone->values = $values;
83
        return $clone;
84
    }
85
86
    /**
87
     * @param array[] ...$values
88
     * @return InsertQueryBuilder
89
     */
90
    public function and(array ...$values): self
91
    {
92
        $clone = clone $this;
93
        foreach ($values as $value) {
94
            $clone->values[] = $value;
95
        }
96
        return $clone;
97
    }
98
99
    /**
100
     * @param string $keyword
101
     * @return InsertQueryBuilder
102
     */
103
    public function withMainKeyword(string $keyword): self
104
    {
105
        $clone = clone $this;
106
        $clone->mainKeyword = $keyword;
107
        return $clone;
108
    }
109
110
    /**
111
     * @param string   $table
112
     * @param string[] ...$columns
113
     * @return InsertQueryBuilder
114
     */
115
    public function into(string $table, string ...$columns): self
116
    {
117
        $clone = clone $this;
118
        $clone->table = $table;
119
        $clone->columns = [] === $columns ? null : $columns;
120
        return $clone;
121
    }
122
123
124
    /**
125
     * @param string[] ...$flags
126
     * @return InsertQueryBuilder
127
     */
128
    public function withFlags(string ...$flags): self
129
    {
130
        $clone = clone $this;
131
        $clone->flags = $flags;
132
        return $clone;
133
    }
134
135
    /**
136
     * @param string[] ...$flags
137
     * @return InsertQueryBuilder
138
     */
139
    public function withAddedFlags(string ...$flags): self
140
    {
141
        $clone = clone $this;
142
        $existingFlags = \array_map('strtoupper', $clone->flags);
143
        foreach ($flags as $flag) {
144
            if (!\in_array(\strtoupper($flag), $existingFlags, true)) {
145
                $clone->flags[] = $flag;
146
            }
147
        }
148
        return $clone;
149
    }
150
151
    /**
152
     * @param string|null $escape
153
     * @return InsertQueryBuilder
154
     */
155
    public function withEscaper(string $escape = null): self
156
    {
157
        $clone = clone $this;
158
        $clone->escape = $escape;
159
        return $clone;
160
    }
161
162
    /**
163
     * @param array $updateConditions
164
     * @return InsertQueryBuilder
165
     */
166
    public function onDuplicateKeyUpdate(array $updateConditions = null): self
167
    {
168
        $clone = clone $this;
169
        $clone->onDuplicate = $updateConditions;
0 ignored issues
show
Documentation Bug introduced by
It seems like $updateConditions can be null. However, the property $onDuplicate is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
170
        return $clone;
171
    }
172
173
    /**
174
     * @param null $end
175
     * @return InsertQueryBuilder
176
     */
177
    public function end($end = null): self
178
    {
179
        $clone = clone $this;
180
        $clone->end = $end;
181
        return $clone;
182
    }
183
184
    /**
185
     * @param array $value
186
     * @return array
187
     * @throws \InvalidArgumentException
188
     */
189
    private function validateValue(array &$value): array
190
    {
191
        if (empty($this->values)) {
192
            return $value;
193
        }
194
        $keys = \array_keys($this->values[0]);
195
        $valueKeys = \array_keys($value);
196
        if ($valueKeys !== $keys) {
197
            if (\count($keys) !== count($valueKeys)) {
198
                throw new \InvalidArgumentException("Invalid value.");
199
            }
200
            \uksort($value, function ($key1, $key2) use ($keys) {
201
                return \array_search($key1, $keys) <=> \array_search($key2, $keys);
202
            });
203
            $valueKeys = \array_keys($value);
204
            if ($valueKeys !== $keys) {
205
                throw new \InvalidArgumentException("Invalid value.");
206
            }
207
        }
208
        return $value;
209
    }
210
211
    /**
212
     * @param string $value
213
     * @return string
214
     */
215
    public function escape(string $value): string
216
    {
217
        return null === $this->escape ? $value : $this->escape . $value . $this->escape;
218
    }
219
220
    /**
221
     * Split into multiple INSERT statements.
222
     *
223
     * @param int $max
224
     * @return iterable|self[]
225
     */
226
    public function split(int $max): iterable
227
    {
228
        $pos = 0;
229
        $total = \count($this->values);
230
        while ($pos < $total) {
231
            $clone = clone $this;
232
            $clone->values = \array_slice($this->values, $pos, $max);
233
            $pos += $max;
234
            yield $clone;
235
        }
236
    }
237
238
    /**
239
     * @return array
240
     */
241
    public function getColumns()
242
    {
243
        return $this->columns ?? \array_keys($this->values[0] ?? []);
244
    }
245
246
    /**
247
     * @return string
248
     */
249
    public function __toString(): string
250
    {
251
        return InsertQueryStringifier::stringify($this);
252
    }
253
254
    /**
255
     * @return array
256
     */
257
    public function getValues(): array
258
    {
259
        $values = [[]];
260
        $columns = $this->getColumns();
261
        foreach ($this->values as $value) {
262
            $valueKeys = \array_keys($value);
263
            if ($valueKeys !== $columns) {
264
                $value = \array_intersect_key($value, \array_combine($columns, \array_fill(0, \count($columns), null)));
265
                $valueKeys = \array_keys($value);
266
                if ($valueKeys !== $columns) {
267
                    \uksort($value, function ($key1, $key2) use ($columns) {
268
                        return \array_search($key1, $columns) <=> \array_search($key2, $columns);
269
                    });
270
                }
271
            }
272
            $values[] = \array_values($value);
273
        }
274
275
        return \array_merge(...$values);
276
    }
277
278
    /**
279
     * @return string
280
     */
281
    public function preview(): string
282
    {
283
        return Previewer::preview((string) $this, $this->getValues());
284
    }
285
286
    /**
287
     * Read-only properties.
288
     *
289
     * @param $property
290
     * @return mixed
291
     * @throws \InvalidArgumentException
292
     */
293
    public function __get($property)
294
    {
295
        if (!\property_exists($this, $property)) {
296
            throw new \InvalidArgumentException(\sprintf('Property %s::$%s does not exist.', __CLASS__, $property));
297
        }
298
        return $this->{$property};
299
    }
300
}
301