Completed
Push — master ( d1730c...d58317 )
by BENOIT
26:43
created

DeleteQueryBuilder   D

Complexity

Total Complexity 50

Size/Duplication

Total Lines 466
Duplicated Lines 0 %

Coupling/Cohesion

Components 9
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 466
rs 4.7169
c 0
b 0
f 0
wmc 50
lcom 9
cbo 2

29 Methods

Rating   Name   Duplication   Size   Complexity  
A make() 0 8 2
A withMainKeyword() 0 6 1
A deleteOnlyFromTables() 0 6 1
A withFlags() 0 6 1
A withAddedFlags() 0 11 3
A from() 0 6 1
A withPartitions() 0 6 1
A withAddedPartitions() 0 10 3
A join() 0 9 2
A innerJoin() 0 9 2
A outerJoin() 0 9 2
A leftJoin() 0 9 2
A leftOuterJoin() 0 9 2
A rightJoin() 0 9 2
A rightOuterJoin() 0 9 2
A fullJoin() 0 9 2
A fullOuterJoin() 0 9 2
A resetJoins() 0 6 1
A withoutJoin() 0 6 1
A where() 0 6 2
A andWhere() 0 9 2
A orWhere() 0 9 2
A orderBy() 0 6 1
A andOrderBy() 0 6 1
A limit() 0 6 1
A end() 0 6 1
A getValues() 0 20 4
A __toString() 0 4 1
A __get() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like DeleteQueryBuilder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DeleteQueryBuilder, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace BenTools\Where\DeleteQuery;
4
5
use BenTools\Where\Expression\Expression;
6
7
/**
8
 * Class SelectQuery
9
 *
10
 * @property $mainKeyword
11
 * @property $flags
12
 * @property $tables
13
 * @property $from
14
 * @property $joins
15
 * @property $partitions
16
 * @property $where
17
 * @property $orderBy
18
 * @property $limit
19
 * @property $end
20
 */
21
final class DeleteQueryBuilder
22
{
23
24
    /**
25
     * @var string
26
     */
27
    private $mainKeyword = 'DELETE';
28
29
    /**
30
     * @var array
31
     */
32
    private $flags = [];
33
34
    /**
35
     * @var array
36
     */
37
    private $tables = [];
38
39
    /**
40
     * @var string
41
     */
42
    private $from;
43
44
    /**
45
     * @var array
46
     */
47
    private $partitions = [];
48
49
    /**
50
     * @var array
51
     */
52
    private $joins = [];
53
54
    /**
55
     * @var Expression
56
     */
57
    private $where;
58
59
    /**
60
     * @var array
61
     */
62
    private $orderBy = [];
63
64
    /**
65
     * @var int
66
     */
67
    private $limit;
68
69
    /**
70
     * @var string
71
     */
72
    private $end = ';';
73
74
    /**
75
     * @param Expression[]|string[] ...$tables
76
     * @return DeleteQueryBuilder
77
     */
78
    public static function make(...$tables): self
79
    {
80
        $query = new self;
81
        if (0 !== func_num_args()) {
82
            $query->tables = $tables;
83
        }
84
        return $query;
85
    }
86
87
    /**
88
     * @param string $keyword
89
     * @return DeleteQueryBuilder
90
     */
91
    public function withMainKeyword(string $keyword): self
92
    {
93
        $clone = clone $this;
94
        $clone->mainKeyword = $keyword;
95
        return $clone;
96
    }
97
98
    /**
99
     * @param Expression[]|string[] ...$tables
100
     * @return DeleteQueryBuilder
101
     */
102
    public function deleteOnlyFromTables(...$tables): self
103
    {
104
        $clone = clone $this;
105
        $clone->tables = $tables;
106
        return $clone;
107
    }
108
109
    /**
110
     * @param string[] ...$flags
111
     * @return DeleteQueryBuilder
112
     */
113
    public function withFlags(string ...$flags): self
114
    {
115
        $clone = clone $this;
116
        $clone->flags = $flags;
117
        return $clone;
118
    }
119
120
    /**
121
     * @param string[] ...$flags
122
     * @return DeleteQueryBuilder
123
     */
124
    public function withAddedFlags(string ...$flags): self
125
    {
126
        $clone = clone $this;
127
        $existingFlags = array_map('strtoupper', $clone->flags);
128
        foreach ($flags as $flag) {
129
            if (!in_array(strtoupper($flag), $existingFlags, true)) {
130
                $clone->flags[] = $flag;
131
            }
132
        }
133
        return $clone;
134
    }
135
136
    /**
137
     * @param string $table
138
     * @return DeleteQueryBuilder
139
     */
140
    public function from(string $table = null): self
141
    {
142
        $clone = clone $this;
143
        $clone->from = $table;
144
        return $clone;
145
    }
146
147
    /**
148
     * @param string[] ...$partitions
149
     * @return DeleteQueryBuilder
150
     */
151
    public function withPartitions(string ...$partitions): self
152
    {
153
        $clone = clone $this;
154
        $clone->partitions = $partitions;
155
        return $clone;
156
    }
157
158
    /**
159
     * @param string[] ...$partitions
160
     * @return DeleteQueryBuilder
161
     */
162
    public function withAddedPartitions(string ...$partitions): self
163
    {
164
        $clone = clone $this;
165
        foreach ($partitions as $partition) {
166
            if (!in_array($partition, $clone->partitions, true)) {
167
                $clone->partitions[] = $partition;
168
            }
169
        }
170
        return $clone;
171
    }
172
173
    /**
174
     * @param string                 $table
175
     * @param string|Expression|null $expression
176
     * @param array                  ...$values
177
     * @return DeleteQueryBuilder
178
     * @throws \InvalidArgumentException
179
     */
180
    public function join(string $table, $expression = null, ...$values): self
181
    {
182
        $clone = clone $this;
183
        $clone->joins[$table] = [
184
            't' => 'JOIN',
185
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
186
        ];
187
        return $clone;
188
    }
189
190
    /**
191
     * @param string                 $table
192
     * @param string|Expression|null $expression
193
     * @param array                  ...$values
194
     * @return DeleteQueryBuilder
195
     * @throws \InvalidArgumentException
196
     */
197
    public function innerJoin(string $table, $expression = null, ...$values): self
198
    {
199
        $clone = clone $this;
200
        $clone->joins[$table] = [
201
            't' => 'INNER JOIN',
202
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
203
        ];
204
        return $clone;
205
    }
206
207
    /**
208
     * @param string                 $table
209
     * @param string|Expression|null $expression
210
     * @param array                  ...$values
211
     * @return DeleteQueryBuilder
212
     * @throws \InvalidArgumentException
213
     */
214
    public function outerJoin(string $table, $expression = null, ...$values): self
215
    {
216
        $clone = clone $this;
217
        $clone->joins[$table] = [
218
            't' => 'OUTER JOIN',
219
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
220
        ];
221
        return $clone;
222
    }
223
224
    /**
225
     * @param string                 $table
226
     * @param string|Expression|null $expression
227
     * @param array                  ...$values
228
     * @return DeleteQueryBuilder
229
     * @throws \InvalidArgumentException
230
     */
231
    public function leftJoin(string $table, $expression = null, ...$values): self
232
    {
233
        $clone = clone $this;
234
        $clone->joins[$table] = [
235
            't' => 'LEFT JOIN',
236
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
237
        ];
238
        return $clone;
239
    }
240
241
    /**
242
     * @param string                 $table
243
     * @param string|Expression|null $expression
244
     * @param array                  ...$values
245
     * @return DeleteQueryBuilder
246
     * @throws \InvalidArgumentException
247
     */
248
    public function leftOuterJoin(string $table, $expression = null, ...$values): self
249
    {
250
        $clone = clone $this;
251
        $clone->joins[$table] = [
252
            't' => 'LEFT OUTER JOIN',
253
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
254
        ];
255
        return $clone;
256
    }
257
258
    /**
259
     * @param string                 $table
260
     * @param string|Expression|null $expression
261
     * @param array                  ...$values
262
     * @return DeleteQueryBuilder
263
     * @throws \InvalidArgumentException
264
     */
265
    public function rightJoin(string $table, $expression = null, ...$values): self
266
    {
267
        $clone = clone $this;
268
        $clone->joins[$table] = [
269
            't' => 'RIGHT JOIN',
270
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
271
        ];
272
        return $clone;
273
    }
274
275
    /**
276
     * @param string                 $table
277
     * @param string|Expression|null $expression
278
     * @param array                  ...$values
279
     * @return DeleteQueryBuilder
280
     * @throws \InvalidArgumentException
281
     */
282
    public function rightOuterJoin(string $table, $expression = null, ...$values): self
283
    {
284
        $clone = clone $this;
285
        $clone->joins[$table] = [
286
            't' => 'RIGHT OUTER JOIN',
287
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
288
        ];
289
        return $clone;
290
    }
291
292
    /**
293
     * @param string                 $table
294
     * @param string|Expression|null $expression
295
     * @param array                  ...$values
296
     * @return DeleteQueryBuilder
297
     * @throws \InvalidArgumentException
298
     */
299
    public function fullJoin(string $table, $expression = null, ...$values): self
300
    {
301
        $clone = clone $this;
302
        $clone->joins[$table] = [
303
            't' => 'FULL JOIN',
304
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
305
        ];
306
        return $clone;
307
    }
308
309
    /**
310
     * @param string                 $table
311
     * @param string|Expression|null $expression
312
     * @param array                  ...$values
313
     * @return DeleteQueryBuilder
314
     * @throws \InvalidArgumentException
315
     */
316
    public function fullOuterJoin(string $table, $expression = null, ...$values): self
317
    {
318
        $clone = clone $this;
319
        $clone->joins[$table] = [
320
            't' => 'FULL OUTER JOIN',
321
            'c' => null !== $expression ? Expression::where($expression, ...$values) : null,
322
        ];
323
        return $clone;
324
    }
325
326
    /**
327
     * Reset all JOIN clauses.
328
     *
329
     * @return DeleteQueryBuilder
330
     */
331
    public function resetJoins(): self
332
    {
333
        $clone = clone $this;
334
        $clone->joins = [];
335
        return $clone;
336
    }
337
338
    /**
339
     * Remove a specific JOIN clause.
340
     *
341
     * @param string $table
342
     * @return DeleteQueryBuilder
343
     */
344
    public function withoutJoin(string $table)
345
    {
346
        $clone = clone $this;
347
        unset($clone->joins[$table]);
348
        return $clone;
349
    }
350
351
    /**
352
     * @param string|Expression|null $expression
353
     * @param array                  ...$values
354
     * @return DeleteQueryBuilder
355
     * @throws \InvalidArgumentException
356
     */
357
    public function where($expression = null, ...$values): self
358
    {
359
        $clone = clone $this;
360
        $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...
361
        return $clone;
362
    }
363
364
    /**
365
     * @param string|Expression $expression
366
     * @param array             ...$values
367
     * @return DeleteQueryBuilder
368
     * @throws \InvalidArgumentException
369
     */
370
    public function andWhere($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->and(Expression::where($expression, ...$values));
377
        return $clone;
378
    }
379
380
    /**
381
     * @param string|Expression $expression
382
     * @param array             ...$values
383
     * @return DeleteQueryBuilder
384
     * @throws \InvalidArgumentException
385
     */
386
    public function orWhere($expression, ...$values): self
387
    {
388
        if (null === $this->where) {
389
            return $this->where(Expression::where($expression, ...$values));
390
        }
391
        $clone = clone $this;
392
        $clone->where = $clone->where->or(Expression::where($expression, ...$values));
393
        return $clone;
394
    }
395
396
    /**
397
     * @param string[] ...$groupBy
398
     * @return DeleteQueryBuilder
399
     */
400
    public function orderBy(string ...$orderBy): self
401
    {
402
        $clone = clone $this;
403
        $clone->orderBy = $orderBy;
404
        return $clone;
405
    }
406
407
    /**
408
     * @param string[] ...$groupBy
409
     * @return DeleteQueryBuilder
410
     */
411
    public function andOrderBy(string ...$orderBy): self
412
    {
413
        $clone = clone $this;
414
        $clone->orderBy = array_merge($clone->orderBy, $orderBy);
415
        return $clone;
416
    }
417
418
    /**
419
     * @param int|null $limit
420
     * @return DeleteQueryBuilder
421
     */
422
    public function limit(int $limit = null): self
423
    {
424
        $clone = clone $this;
425
        $clone->limit = $limit;
426
        return $clone;
427
    }
428
429
    /**
430
     * @param string|null $end
431
     * @return DeleteQueryBuilder
432
     */
433
    public function end(string $end = null): self
434
    {
435
        $clone = clone $this;
436
        $clone->end = $end;
437
        return $clone;
438
    }
439
440
    /**
441
     * @return array
442
     */
443
    public function getValues(): array
444
    {
445
        $generator = function (Expression ...$expressions) {
446
            foreach ($expressions as $expression) {
447
                foreach ($expression->getValues() as $key => $value) {
448
                    if (is_numeric($key)) {
449
                        yield $value;
450
                    } else {
451
                        yield $key => $value;
452
                    }
453
                }
454
            }
455
        };
456
457
        $expressions = array_filter(array_merge(array_column($this->joins, 'c'), [$this->where]), function ($expression) {
458
            return $expression instanceof Expression;
459
        });
460
461
        return iterator_to_array($generator(...$expressions));
462
    }
463
464
    /**
465
     * @return string
466
     */
467
    public function __toString(): string
468
    {
469
        return DeleteQueryStringifier::stringify($this);
470
    }
471
472
    /**
473
     * Read-only properties.
474
     *
475
     * @param $property
476
     * @return mixed
477
     * @throws \InvalidArgumentException
478
     */
479
    public function __get($property)
480
    {
481
        if (!property_exists($this, $property)) {
482
            throw new \InvalidArgumentException(sprintf('Property %s::$%s does not exist.', __CLASS__, $property));
483
        }
484
        return $this->{$property};
485
    }
486
}
487