Passed
Push — develop ( bc0387...6879d5 )
by nguereza
03:17
created

QueryStatement   B

Complexity

Total Complexity 49

Size/Duplication

Total Lines 570
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 49
eloc 161
c 2
b 0
f 0
dl 0
loc 570
rs 8.48

38 Methods

Rating   Name   Duplication   Size   Complexity  
A getJoins() 0 3 1
A setLimit() 0 3 1
A getLimit() 0 3 1
A addColumn() 0 5 1
A addUpdateColumns() 0 6 2
A addValue() 0 3 1
A setFrom() 0 3 1
A getGroupBy() 0 3 1
A addWhereLike() 0 8 1
A getOffset() 0 3 1
A closureToExpression() 0 7 2
A getOrder() 0 3 1
A getIntoTable() 0 3 1
A getDistinct() 0 3 1
A getTables() 0 3 1
A addGroupBy() 0 7 2
A getValues() 0 3 1
A addJoinClause() 0 20 4
A addWhereExists() 0 10 1
A addHavingIn() 0 22 2
A addWhereNop() 0 6 1
A setOffset() 0 3 1
A addHavingGroup() 0 9 1
A getHaving() 0 3 1
A addWhere() 0 8 1
A addTables() 0 3 1
A addHaving() 0 8 1
A addWhereGroup() 0 9 1
A addWhereIn() 0 22 2
A getColumns() 0 3 1
A setInto() 0 3 1
A addOrder() 0 14 4
A getFrom() 0 3 1
A addHavingBetween() 0 9 1
A getWheres() 0 3 1
A addWhereBetween() 0 9 1
A addWhereNull() 0 7 1
A setDistinct() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like QueryStatement 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.

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 QueryStatement, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Platine Database
5
 *
6
 * Platine Database is the abstraction layer using PDO with support of query and schema builder
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine Database
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a copy
13
 * of this software and associated documentation files (the "Software"), to deal
14
 * in the Software without restriction, including without limitation the rights
15
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 * copies of the Software, and to permit persons to whom the Software is
17
 * furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in all
20
 * copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
 * SOFTWARE.
29
 */
30
31
/**
32
 *  @file QueryStatement.php
33
 *
34
 *  The Base class for SQL query statement
35
 *
36
 *  @package    Platine\Database\Query
37
 *  @author Platine Developers Team
38
 *  @copyright  Copyright (c) 2020
39
 *  @license    http://opensource.org/licenses/MIT  MIT License
40
 *  @link   http://www.iacademy.cf
41
 *  @version 1.0.0
42
 *  @filesource
43
 */
44
45
declare(strict_types=1);
46
47
namespace Platine\Database\Query;
48
49
use Closure;
50
51
/**
52
 * Class QueryStatement
53
 *
54
 * @package Platine\Database\Query
55
 */
56
class QueryStatement
57
{
58
59
    /**
60
     * The where SQL parts
61
     * @var array
62
     */
63
    protected array $wheres = [];
64
65
    /**
66
     * The having SQL parts
67
     * @var array
68
     */
69
    protected array $having = [];
70
71
    /**
72
     * The join SQL parts
73
     * @var array
74
     */
75
    protected array $joins = [];
76
77
    /**
78
     * The table SQL parts
79
     * @var array
80
     */
81
    protected array $tables = [];
82
83
    /**
84
     * The columns SQL parts
85
     * @var array
86
     */
87
    protected array $columns = [];
88
89
    /**
90
     * The order SQL parts
91
     * @var array
92
     */
93
    protected array $order = [];
94
95
    /**
96
     * The group SQL parts
97
     * @var array
98
     */
99
    protected array $group = [];
100
101
    /**
102
     * The from SQL parts
103
     * @var array
104
     */
105
    protected array $from = [];
106
107
    /**
108
     * The query placeholders values
109
     * @var array
110
     */
111
    protected array $values = [];
112
113
    /**
114
     * Whether need use distinct
115
     * @var bool
116
     */
117
    protected bool $distinct = false;
118
119
    /**
120
     * The limit value
121
     * @var int
122
     */
123
    protected int $limit = 0;
124
125
    /**
126
     * The offset value
127
     * @var int
128
     */
129
    protected int $offset = -1;
130
131
    /**
132
     * The insert table
133
     * @var string
134
     */
135
    protected string $intoTable = '';
136
137
    /**
138
     * @param Closure $callback
139
     * @param string $separator
140
     */
141
    public function addWhereGroup(Closure $callback, string $separator): void
142
    {
143
        $where = new WhereStatement();
144
        $callback($where);
145
146
        $this->wheres[] = [
147
            'type' => 'whereNested',
148
            'clause' => $where->getQueryStatement()->getWheres(),
149
            'separator' => $separator
150
        ];
151
    }
152
153
    /**
154
     * @param string|Closure|Expression $column
155
     * @param mixed $value
156
     * @param string $operator
157
     * @param string $separator
158
     */
159
    public function addWhere($column, $value, string $operator, string $separator): void
160
    {
161
        $this->wheres[] = [
162
            'type' => 'whereColumn',
163
            'column' => $this->closureToExpression($column),
164
            'value' => $this->closureToExpression($value),
165
            'operator' => $operator,
166
            'separator' => $separator
167
        ];
168
    }
169
170
    /**
171
     * @param string|Closure|Expression $column
172
     * @param string $pattern
173
     * @param string $separator
174
     * @param bool $not
175
     */
176
    public function addWhereLike($column, string $pattern, string $separator, bool $not): void
177
    {
178
        $this->wheres[] = [
179
            'type' => 'whereLike',
180
            'column' => $this->closureToExpression($column),
181
            'pattern' => $pattern,
182
            'separator' => $separator,
183
            'not' => $not
184
        ];
185
    }
186
187
    /**
188
     * @param string|Closure|Expression $column
189
     * @param mixed $value1
190
     * @param mixed $value2
191
     * @param string $separator
192
     * @param bool $not
193
     */
194
    public function addWhereBetween($column, $value1, $value2, string $separator, bool $not): void
195
    {
196
        $this->wheres[] = [
197
            'type' => 'whereBetween',
198
            'column' => $this->closureToExpression($column),
199
            'value1' => $this->closureToExpression($value1),
200
            'value2' => $this->closureToExpression($value2),
201
            'separator' => $separator,
202
            'not' => $not
203
        ];
204
    }
205
206
    /**
207
     * @param string|Closure|Expression $column
208
     * @param mixed $value
209
     * @param string $separator
210
     * @param bool $not
211
     */
212
    public function addWhereIn($column, $value, string $separator, bool $not): void
213
    {
214
        $column = $this->closureToExpression($column);
215
216
        if ($value instanceof Closure) {
217
            $select = new SubQuery();
218
            $value($select);
219
220
            $this->wheres[] = [
221
                'type' => 'whereInSelect',
222
                'column' => $column,
223
                'subquery' => $select,
224
                'separator' => $separator,
225
                'not' => $not
226
            ];
227
        } else {
228
            $this->wheres[] = [
229
                'type' => 'whereIn',
230
                'column' => $column,
231
                'value' => $value,
232
                'separator' => $separator,
233
                'not' => $not
234
            ];
235
        }
236
    }
237
238
    /**
239
     * @param string|Closure|Expression $column
240
     * @param string $separator
241
     * @param bool $not
242
     */
243
    public function addWhereNull($column, string $separator, bool $not): void
244
    {
245
        $this->wheres[] = [
246
            'type' => 'whereNull',
247
            'column' => $this->closureToExpression($column),
248
            'separator' => $separator,
249
            'not' => $not
250
        ];
251
    }
252
253
    /**
254
     * @param string|Closure|Expression $column
255
     * @param string $separator
256
     */
257
    public function addWhereNop($column, string $separator): void
258
    {
259
        $this->wheres[] = [
260
            'type' => 'whereNop',
261
            'column' => $column,
262
            'separator' => $separator
263
        ];
264
    }
265
266
    /**
267
     * @param Closure $closure
268
     * @param string $separator
269
     * @param bool $not
270
     */
271
    public function addWhereExists(Closure $closure, string $separator, bool $not): void
272
    {
273
        $select = new SubQuery();
274
        $closure($select);
275
276
        $this->wheres[] = [
277
            'type' => 'whereExists',
278
            'subquery' => $select,
279
            'separator' => $separator,
280
            'not' => $not
281
        ];
282
    }
283
284
    /**
285
     * @param string $type
286
     * @param string|array $table
287
     * @param Closure|null $closure
288
     */
289
    public function addJoinClause(string $type, $table, Closure $closure = null): void
290
    {
291
        $join = null;
292
        if ($closure !== null) {
293
            $join = new Join();
294
            $closure($join);
295
        }
296
297
        if ($table instanceof Closure) {
0 ignored issues
show
introduced by
$table is never a sub-type of Closure.
Loading history...
298
            $table = Expression::fromClosure($table);
299
        }
300
301
        if (!is_array($table)) {
302
            $table = [$table];
303
        }
304
305
        $this->joins[] = [
306
            'type' => $type,
307
            'table' => $table,
308
            'join' => $join
309
        ];
310
    }
311
312
    /**
313
     * @param Closure $closure
314
     * @param string $separator
315
     */
316
    public function addHavingGroup(Closure $closure, string $separator): void
317
    {
318
        $having = new HavingStatement();
319
        $closure($having);
320
321
        $this->having[] = [
322
            'type' => 'havingNested',
323
            'conditions' => $having->getQueryStatement()->getHaving(),
324
            'separator' => $separator
325
        ];
326
    }
327
328
    /**
329
     * @param string|Closure|Expression $aggregate
330
     * @param mixed $value
331
     * @param string $operator
332
     * @param string $separator
333
     */
334
    public function addHaving($aggregate, $value, string $operator, string $separator): void
335
    {
336
        $this->having[] = [
337
            'type' => 'havingCondition',
338
            'aggregate' => $this->closureToExpression($aggregate),
339
            'value' => $this->closureToExpression($value),
340
            'operator' => $operator,
341
            'separator' => $separator
342
        ];
343
    }
344
345
    /**
346
     * @param string|Closure|Expression $aggregate
347
     * @param mixed $value
348
     * @param string $separator
349
     * @param bool $not
350
     */
351
    public function addHavingIn($aggregate, $value, string $separator, bool $not): void
352
    {
353
        $aggregate = $this->closureToExpression($aggregate);
354
355
        if ($value instanceof Closure) {
356
            $select = new SubQuery();
357
            $value($select);
358
359
            $this->having[] = [
360
                'type' => 'havingInSelect',
361
                'aggregate' => $aggregate,
362
                'subquery' => $select,
363
                'separator' => $separator,
364
                'not' => $not
365
            ];
366
        } else {
367
            $this->having[] = [
368
                'type' => 'havingIn',
369
                'aggregate' => $aggregate,
370
                'value' => $value,
371
                'separator' => $separator,
372
                'not' => $not
373
            ];
374
        }
375
    }
376
377
    /**
378
     * @param string|Closure|Expression $aggregate
379
     * @param mixed $value1
380
     * @param mixed $value2
381
     * @param string $separator
382
     * @param bool $not
383
     */
384
    public function addHavingBetween($aggregate, $value1, $value2, string $separator, bool $not): void
385
    {
386
        $this->having[] = [
387
            'type' => 'havingBetween',
388
            'aggregate' => $this->closureToExpression($aggregate),
389
            'value1' => $this->closureToExpression($value1),
390
            'value2' => $this->closureToExpression($value2),
391
            'separator' => $separator,
392
            'not' => $not
393
        ];
394
    }
395
396
    /**
397
     * @param array $tables
398
     */
399
    public function addTables(array $tables): void
400
    {
401
        $this->tables = $tables;
402
    }
403
404
    /**
405
     * @param array $columns
406
     */
407
    public function addUpdateColumns(array $columns): void
408
    {
409
        foreach ($columns as $column => $value) {
410
            $this->columns[] = [
411
                'column' => $column,
412
                'value' => $this->closureToExpression($value)
413
            ];
414
        }
415
    }
416
417
    /**
418
     * @param string[]|Expression[]|Closure[] $columns
419
     * @param string $order
420
     */
421
    public function addOrder(array $columns, string $order): void
422
    {
423
        foreach ($columns as &$column) {
424
            $column = $this->closureToExpression($column);
425
        }
426
        $order = strtoupper($order);
427
428
        if ($order !== 'ASC' && $order !== 'DESC') {
429
            $order = 'ASC';
430
        }
431
432
        $this->order[] = [
433
            'columns' => $columns,
434
            'order' => $order
435
        ];
436
    }
437
438
    /**
439
     * @param string[]|Expression[]|Closure[] $columns
440
     */
441
    public function addGroupBy(array $columns): void
442
    {
443
        foreach ($columns as &$column) {
444
            $column = $this->closureToExpression($column);
445
        }
446
447
        $this->group = $columns;
448
    }
449
450
    /**
451
     * @param string|Expression|Closure $column
452
     * @param string|null $alias
453
     */
454
    public function addColumn($column, ?string $alias = null): void
455
    {
456
        $this->columns[] = [
457
            'name' => $this->closureToExpression($column),
458
            'alias' => $alias
459
        ];
460
    }
461
462
    /**
463
     * @param bool $value
464
     */
465
    public function setDistinct(bool $value): void
466
    {
467
        $this->distinct = $value;
468
    }
469
470
    /**
471
     * @param int $value
472
     */
473
    public function setLimit(int $value): void
474
    {
475
        $this->limit = $value;
476
    }
477
478
    /**
479
     * @param int $value
480
     */
481
    public function setOffset(int $value): void
482
    {
483
        $this->offset = $value;
484
    }
485
486
    /**
487
     * @param string $table
488
     */
489
    public function setInto(string $table): void
490
    {
491
        $this->intoTable = $table;
492
    }
493
494
    /**
495
     * @param array $from
496
     */
497
    public function setFrom(array $from): void
498
    {
499
        $this->from = $from;
500
    }
501
502
    /**
503
     * @param mixed $value
504
     */
505
    public function addValue($value): void
506
    {
507
        $this->values[] = $this->closureToExpression($value);
508
    }
509
510
    /**
511
     * @return array
512
     */
513
    public function getWheres(): array
514
    {
515
        return $this->wheres;
516
    }
517
518
    /**
519
     * @return array
520
     */
521
    public function getHaving(): array
522
    {
523
        return $this->having;
524
    }
525
526
    /**
527
     * @return array
528
     */
529
    public function getJoins(): array
530
    {
531
        return $this->joins;
532
    }
533
534
    /**
535
     * @return bool
536
     */
537
    public function getDistinct(): bool
538
    {
539
        return $this->distinct;
540
    }
541
542
    /**
543
     * @return array
544
     */
545
    public function getTables(): array
546
    {
547
        return $this->tables;
548
    }
549
550
    /**
551
     * @return array
552
     */
553
    public function getColumns(): array
554
    {
555
        return $this->columns;
556
    }
557
558
    /**
559
     * @return array
560
     */
561
    public function getOrder(): array
562
    {
563
        return $this->order;
564
    }
565
566
    /**
567
     * @return array
568
     */
569
    public function getGroupBy(): array
570
    {
571
        return $this->group;
572
    }
573
574
    /**
575
     * @return int
576
     */
577
    public function getLimit(): int
578
    {
579
        return $this->limit;
580
    }
581
582
    /**
583
     * @return int
584
     */
585
    public function getOffset(): int
586
    {
587
        return $this->offset;
588
    }
589
590
    /**
591
     * @return string
592
     */
593
    public function getIntoTable(): string
594
    {
595
        return $this->intoTable;
596
    }
597
598
    /**
599
     * @return array
600
     */
601
    public function getFrom(): array
602
    {
603
        return $this->from;
604
    }
605
606
    /**
607
     * @return array
608
     */
609
    public function getValues(): array
610
    {
611
        return $this->values;
612
    }
613
614
    /**
615
     * @param mixed $value
616
     *
617
     * @return mixed|Expression
618
     */
619
    protected function closureToExpression($value)
620
    {
621
        if ($value instanceof Closure) {
622
            return Expression::fromClosure($value);
623
        }
624
625
        return $value;
626
    }
627
}
628