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

DeleteQueryBuilder   C

Complexity

Total Complexity 47

Size/Duplication

Total Lines 453
Duplicated Lines 0 %

Coupling/Cohesion

Components 9
Dependencies 2

Importance

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