Completed
Push — master ( d58317...6c60b4 )
by BENOIT
05:45
created

UpdateQueryBuilder::end()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace BenTools\Where\UpdateQuery;
4
5
use BenTools\Where\Expression\Expression;
6
use function BenTools\Where\valuesOf;
7
8
/**
9
 * Class UpdateQueryBuilder
10
 *
11
 * @property $mainKeyword
12
 * @property $flags
13
 * @property $from
14
 * @property $set
15
 * @property $joins
16
 * @property $where
17
 * @property $orderBy
18
 * @property $limit
19
 * @property $end
20
 */
21
final class UpdateQueryBuilder
22
{
23
    /**
24
     * @var string
25
     */
26
    private $mainKeyword = 'UPDATE';
27
28
    /**
29
     * @var array
30
     */
31
    private $flags = [];
32
33
    /**
34
     * @var string
35
     */
36
    private $from;
37
38
    /**
39
     * @var Expression
40
     */
41
    private $set;
42
43
    /**
44
     * @var array
45
     */
46
    private $joins = [];
47
48
    /**
49
     * @var Expression
50
     */
51
    private $where;
52
53
    /**
54
     * @var array
55
     */
56
    private $orderBy = [];
57
58
    /**
59
     * @var int
60
     */
61
    private $limit;
62
63
    /**
64
     * @var string
65
     */
66
    private $end = ';';
67
68
    /**
69
     * @param string $table
70
     * @return UpdateQueryBuilder
71
     */
72
    public static function make(string $table): self
73
    {
74
        $query = new self;
75
        $query->from = $table;
76
        return $query;
77
    }
78
79
    /**
80
     * @param string $table
81
     * @return UpdateQueryBuilder
82
     */
83
    public function table(string $table): self
84
    {
85
        $clone = clone $this;
86
        $clone->from = $table;
87
        return $clone;
88
    }
89
90
    /**
91
     * @param string $keyword
92
     * @return UpdateQueryBuilder
93
     */
94
    public function withMainKeyword(string $keyword): self
95
    {
96
        $clone = clone $this;
97
        $clone->mainKeyword = $keyword;
98
        return $clone;
99
    }
100
101
    /**
102
     * @param string[] ...$flags
103
     * @return UpdateQueryBuilder
104
     */
105
    public function withFlags(string ...$flags): self
106
    {
107
        $clone = clone $this;
108
        $clone->flags = $flags;
109
        return $clone;
110
    }
111
112
    /**
113
     * @param string[] ...$flags
114
     * @return UpdateQueryBuilder
115
     */
116
    public function withAddedFlags(string ...$flags): self
117
    {
118
        $clone = clone $this;
119
        $existingFlags = array_map('strtoupper', $clone->flags);
120
        foreach ($flags as $flag) {
121
            if (!in_array(strtoupper($flag), $existingFlags, true)) {
122
                $clone->flags[] = $flag;
123
            }
124
        }
125
        return $clone;
126
    }
127
128
    /**
129
     * @param string                 $table
130
     * @param string|Expression|null $expression
131
     * @param array                  ...$values
132
     * @return UpdateQueryBuilder
133
     * @throws \InvalidArgumentException
134
     */
135
    public function join(string $table, $expression = null, ...$values): self
136
    {
137
        $clone = clone $this;
138
        $clone->joins[$table] = [
139
            't' => 'JOIN',
140
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
141
        ];
142
        return $clone;
143
    }
144
145
    /**
146
     * @param string                 $table
147
     * @param string|Expression|null $expression
148
     * @param array                  ...$values
149
     * @return UpdateQueryBuilder
150
     * @throws \InvalidArgumentException
151
     */
152
    public function innerJoin(string $table, $expression = null, ...$values): self
153
    {
154
        $clone = clone $this;
155
        $clone->joins[$table] = [
156
            't' => 'INNER JOIN',
157
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
158
        ];
159
        return $clone;
160
    }
161
162
    /**
163
     * @param string                 $table
164
     * @param string|Expression|null $expression
165
     * @param array                  ...$values
166
     * @return UpdateQueryBuilder
167
     * @throws \InvalidArgumentException
168
     */
169
    public function outerJoin(string $table, $expression = null, ...$values): self
170
    {
171
        $clone = clone $this;
172
        $clone->joins[$table] = [
173
            't' => 'OUTER JOIN',
174
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
175
        ];
176
        return $clone;
177
    }
178
179
    /**
180
     * @param string                 $table
181
     * @param string|Expression|null $expression
182
     * @param array                  ...$values
183
     * @return UpdateQueryBuilder
184
     * @throws \InvalidArgumentException
185
     */
186
    public function leftJoin(string $table, $expression = null, ...$values): self
187
    {
188
        $clone = clone $this;
189
        $clone->joins[$table] = [
190
            't' => 'LEFT JOIN',
191
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
192
        ];
193
        return $clone;
194
    }
195
196
    /**
197
     * @param string                 $table
198
     * @param string|Expression|null $expression
199
     * @param array                  ...$values
200
     * @return UpdateQueryBuilder
201
     * @throws \InvalidArgumentException
202
     */
203
    public function leftOuterJoin(string $table, $expression = null, ...$values): self
204
    {
205
        $clone = clone $this;
206
        $clone->joins[$table] = [
207
            't' => 'LEFT OUTER JOIN',
208
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
209
        ];
210
        return $clone;
211
    }
212
213
    /**
214
     * @param string                 $table
215
     * @param string|Expression|null $expression
216
     * @param array                  ...$values
217
     * @return UpdateQueryBuilder
218
     * @throws \InvalidArgumentException
219
     */
220
    public function rightJoin(string $table, $expression = null, ...$values): self
221
    {
222
        $clone = clone $this;
223
        $clone->joins[$table] = [
224
            't' => 'RIGHT JOIN',
225
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
226
        ];
227
        return $clone;
228
    }
229
230
    /**
231
     * @param string                 $table
232
     * @param string|Expression|null $expression
233
     * @param array                  ...$values
234
     * @return UpdateQueryBuilder
235
     * @throws \InvalidArgumentException
236
     */
237
    public function rightOuterJoin(string $table, $expression = null, ...$values): self
238
    {
239
        $clone = clone $this;
240
        $clone->joins[$table] = [
241
            't' => 'RIGHT OUTER JOIN',
242
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
243
        ];
244
        return $clone;
245
    }
246
247
    /**
248
     * @param string                 $table
249
     * @param string|Expression|null $expression
250
     * @param array                  ...$values
251
     * @return UpdateQueryBuilder
252
     * @throws \InvalidArgumentException
253
     */
254
    public function fullJoin(string $table, $expression = null, ...$values): self
255
    {
256
        $clone = clone $this;
257
        $clone->joins[$table] = [
258
            't' => 'FULL JOIN',
259
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
260
        ];
261
        return $clone;
262
    }
263
264
    /**
265
     * @param string                 $table
266
     * @param string|Expression|null $expression
267
     * @param array                  ...$values
268
     * @return UpdateQueryBuilder
269
     * @throws \InvalidArgumentException
270
     */
271
    public function fullOuterJoin(string $table, $expression = null, ...$values): self
272
    {
273
        $clone = clone $this;
274
        $clone->joins[$table] = [
275
            't' => 'FULL OUTER JOIN',
276
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
277
        ];
278
        return $clone;
279
    }
280
281
    /**
282
     * Reset all JOIN clauses.
283
     *
284
     * @return UpdateQueryBuilder
285
     */
286
    public function resetJoins(): self
287
    {
288
        $clone = clone $this;
289
        $clone->joins = [];
290
        return $clone;
291
    }
292
293
    /**
294
     * Remove a specific JOIN clause.
295
     *
296
     * @param string $table
297
     * @return UpdateQueryBuilder
298
     */
299
    public function withoutJoin(string $table)
300
    {
301
        $clone = clone $this;
302
        unset($clone->joins[$table]);
303
        return $clone;
304
    }
305
306
    /**
307
     * @param null  $expression
308
     * @param array ...$values
309
     * @return UpdateQueryBuilder
310
     * @throws \InvalidArgumentException
311
     */
312
    public function set($expression = null, ...$values): self
313
    {
314
        $clone = clone $this;
315
        $clone->set = null !== $expression ? Expression::where($expression, ...$values) : null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null !== $expression ? \...ion, ...$values) : null can also be of type object<self>. However, the property $set is declared as type object<BenTools\Where\Expression\Expression>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
316
        return $clone;
317
    }
318
319
    /**
320
     * @param null  $expression
321
     * @param array ...$values
322
     * @return UpdateQueryBuilder
323
     * @throws \InvalidArgumentException
324
     */
325
    public function andSet($expression = null, ...$values): self
326
    {
327
        if (null === $this->set) {
328
            return $this->set(Expression::where($expression, ...$values));
329
        }
330
        $clone = clone $this;
331
        $clone->set = $clone->set->plus(Expression::where($expression, ...$values));
332
        return $clone;
333
    }
334
335
    /**
336
     * @param string|Expression|null $expression
337
     * @param array                  ...$values
338
     * @return UpdateQueryBuilder
339
     * @throws \InvalidArgumentException
340
     */
341
    public function where($expression = null, ...$values): self
342
    {
343
        $clone = clone $this;
344
        $clone->where = null !== $expression ? Expression::where($expression, ...$values) : null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null !== $expression ? \...ion, ...$values) : null can also be of type object<self>. However, the property $where is declared as type object<BenTools\Where\Expression\Expression>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
345
        return $clone;
346
    }
347
348
    /**
349
     * @param string|Expression $expression
350
     * @param array             ...$values
351
     * @return UpdateQueryBuilder
352
     * @throws \InvalidArgumentException
353
     */
354
    public function andWhere($expression, ...$values): self
355
    {
356
        if (null === $this->where) {
357
            return $this->where(Expression::where($expression, ...$values));
358
        }
359
        $clone = clone $this;
360
        $clone->where = $clone->where->and(Expression::where($expression, ...$values));
361
        return $clone;
362
    }
363
364
    /**
365
     * @param string|Expression $expression
366
     * @param array             ...$values
367
     * @return UpdateQueryBuilder
368
     * @throws \InvalidArgumentException
369
     */
370
    public function orWhere($expression, ...$values): self
371
    {
372
        if (null === $this->where) {
373
            return $this->where(Expression::where($expression, ...$values));
374
        }
375
        $clone = clone $this;
376
        $clone->where = $clone->where->or(Expression::where($expression, ...$values));
377
        return $clone;
378
    }
379
380
    /**
381
     * @param string[] ...$groupBy
382
     * @return UpdateQueryBuilder
383
     */
384
    public function orderBy(string ...$orderBy): self
385
    {
386
        $clone = clone $this;
387
        $clone->orderBy = $orderBy;
388
        return $clone;
389
    }
390
391
    /**
392
     * @param string[] ...$groupBy
393
     * @return UpdateQueryBuilder
394
     */
395
    public function andOrderBy(string ...$orderBy): self
396
    {
397
        $clone = clone $this;
398
        $clone->orderBy = array_merge($clone->orderBy, $orderBy);
399
        return $clone;
400
    }
401
402
    /**
403
     * @param int|null $limit
404
     * @return UpdateQueryBuilder
405
     */
406
    public function limit(int $limit = null): self
407
    {
408
        $clone = clone $this;
409
        $clone->limit = $limit;
410
        return $clone;
411
    }
412
413
    /**
414
     * @param string|null $end
415
     * @return UpdateQueryBuilder
416
     */
417
    public function end(string $end = null): self
418
    {
419
        $clone = clone $this;
420
        $clone->end = $end;
421
        return $clone;
422
    }
423
424
    /**
425
     * @return string
426
     */
427
    public function __toString(): string
428
    {
429
        return UpdateQueryStringifier::stringify($this);
430
    }
431
432
    /**
433
     * @return array
434
     */
435
    public function getValues(): array
436
    {
437
        $expressions = array_filter(array_merge(array_column($this->joins, 'c'), [$this->set, $this->where]), function ($expression) {
438
            return $expression instanceof Expression;
439
        });
440
        return valuesOf(...$expressions);
441
    }
442
443
    /**
444
     * Read-only properties.
445
     *
446
     * @param $property
447
     * @return mixed
448
     * @throws \InvalidArgumentException
449
     */
450
    public function __get($property)
451
    {
452
        if (!property_exists($this, $property)) {
453
            throw new \InvalidArgumentException(sprintf('Property %s::$%s does not exist.', __CLASS__, $property));
454
        }
455
        return $this->{$property};
456
    }
457
}
458