QueryStatement::addColumn()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 7
rs 10
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   https://www.platine-php.com
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
     * The where SQL parts
60
     * @var array<int, mixed>
61
     */
62
    protected array $wheres = [];
63
64
    /**
65
     * The having SQL parts
66
     * @var array<int, mixed>
67
     */
68
    protected array $having = [];
69
70
    /**
71
     * The join SQL parts
72
     * @var array<int, mixed>
73
     */
74
    protected array $joins = [];
75
76
    /**
77
     * The table SQL parts
78
     * @var array<int, mixed>
79
     */
80
    protected array $tables = [];
81
82
    /**
83
     * The columns SQL parts
84
     * @var array<int, mixed>
85
     */
86
    protected array $columns = [];
87
88
    /**
89
     * The order SQL parts
90
     * @var array<int, mixed>
91
     */
92
    protected array $order = [];
93
94
    /**
95
     * The group SQL parts
96
     * @var string[]|Expression[]
97
     */
98
    protected array $group = [];
99
100
    /**
101
     * The from SQL parts
102
     * @var array<int, string>
103
     */
104
    protected array $from = [];
105
106
    /**
107
     * The query placeholders values
108
     * @var array<int, mixed>
109
     */
110
    protected array $values = [];
111
112
    /**
113
     * Whether need use distinct
114
     * @var bool
115
     */
116
    protected bool $distinct = false;
117
118
    /**
119
     * The limit value
120
     * @var int
121
     */
122
    protected int $limit = 0;
123
124
    /**
125
     * The offset value
126
     * @var int
127
     */
128
    protected int $offset = -1;
129
130
    /**
131
     * The insert table
132
     * @var string|null
133
     */
134
    protected ?string $intoTable = null;
135
136
    /**
137
     * @param Closure $callback
138
     * @param string $separator
139
     */
140
    public function addWhereGroup(Closure $callback, string $separator): void
141
    {
142
        $where = new WhereStatement();
143
        $callback($where);
144
145
        $this->wheres[] = [
146
            'type' => 'whereNested',
147
            'clause' => $where->getQueryStatement()->getWheres(),
148
            'separator' => $separator
149
        ];
150
    }
151
152
    /**
153
     * @param string|Closure|Expression $column
154
     * @param mixed $value
155
     * @param string $operator
156
     * @param string $separator
157
     */
158
    public function addWhere(
159
        string|Closure|Expression $column,
160
        mixed $value,
161
        string $operator,
162
        string $separator
163
    ): void {
164
        $this->wheres[] = [
165
            'type' => 'whereColumn',
166
            'column' => $this->closureToExpression($column),
167
            'value' => $this->closureToExpression($value),
168
            'operator' => $operator,
169
            'separator' => $separator
170
        ];
171
    }
172
173
    /**
174
     * @param string|Closure|Expression $column
175
     * @param string $pattern
176
     * @param string $separator
177
     * @param bool $not
178
     *
179
     * @return void
180
     */
181
    public function addWhereLike(
182
        string|Closure|Expression $column,
183
        string $pattern,
184
        string $separator,
185
        bool $not
186
    ): void {
187
        $this->wheres[] = [
188
            'type' => 'whereLike',
189
            'column' => $this->closureToExpression($column),
190
            'pattern' => $pattern,
191
            'separator' => $separator,
192
            'not' => $not
193
        ];
194
    }
195
196
    /**
197
     * @param string|Closure|Expression $column
198
     * @param mixed $value1
199
     * @param mixed $value2
200
     * @param string $separator
201
     * @param bool $not
202
     *
203
     * @return void
204
     */
205
    public function addWhereBetween(
206
        string|Closure|Expression $column,
207
        mixed $value1,
208
        mixed $value2,
209
        string $separator,
210
        bool $not
211
    ): void {
212
        $this->wheres[] = [
213
            'type' => 'whereBetween',
214
            'column' => $this->closureToExpression($column),
215
            'value1' => $this->closureToExpression($value1),
216
            'value2' => $this->closureToExpression($value2),
217
            'separator' => $separator,
218
            'not' => $not
219
        ];
220
    }
221
222
    /**
223
     * @param string|Closure|Expression $column
224
     * @param mixed $value
225
     * @param string $separator
226
     * @param bool $not
227
     *
228
     * @return void
229
     */
230
    public function addWhereIn(
231
        string|Closure|Expression $column,
232
        mixed $value,
233
        string $separator,
234
        bool $not
235
    ): void {
236
        $columnName = $this->closureToExpression($column);
237
238
        if ($value instanceof Closure) {
239
            $select = new SubQuery();
240
            $value($select);
241
242
            $this->wheres[] = [
243
                'type' => 'whereInSelect',
244
                'column' => $columnName,
245
                'subquery' => $select,
246
                'separator' => $separator,
247
                'not' => $not
248
            ];
249
        } else {
250
            $this->wheres[] = [
251
                'type' => 'whereIn',
252
                'column' => $columnName,
253
                'value' => $value,
254
                'separator' => $separator,
255
                'not' => $not
256
            ];
257
        }
258
    }
259
260
    /**
261
     * @param string|Closure|Expression $column
262
     * @param string $separator
263
     * @param bool $not
264
     *
265
     * @return void
266
     */
267
    public function addWhereNull(
268
        string|Closure|Expression $column,
269
        string $separator,
270
        bool $not
271
    ): void {
272
        $this->wheres[] = [
273
            'type' => 'whereNull',
274
            'column' => $this->closureToExpression($column),
275
            'separator' => $separator,
276
            'not' => $not
277
        ];
278
    }
279
280
    /**
281
     * @param string|Closure|Expression $column
282
     * @param string $separator
283
     *
284
     * @return void
285
     */
286
    public function addWhereNop(
287
        string|Closure|Expression $column,
288
        string $separator
289
    ): void {
290
        $this->wheres[] = [
291
            'type' => 'whereNop',
292
            'column' => $column,
293
            'separator' => $separator
294
        ];
295
    }
296
297
    /**
298
     * @param Closure $closure
299
     * @param string $separator
300
     * @param bool $not
301
     *
302
     * @return void
303
     */
304
    public function addWhereExists(Closure $closure, string $separator, bool $not): void
305
    {
306
        $select = new SubQuery();
307
        $closure($select);
308
309
        $this->wheres[] = [
310
            'type' => 'whereExists',
311
            'subquery' => $select,
312
            'separator' => $separator,
313
            'not' => $not
314
        ];
315
    }
316
317
    /**
318
     * @param string $type
319
     * @param string|array<int, string>|Closure $table
320
     * @param Closure|null $closure
321
     */
322
    public function addJoinClause(
323
        string $type,
324
        string|array|Closure $table,
325
        ?Closure $closure = null
326
    ): void {
327
        $join = null;
328
        if ($closure !== null) {
329
            $join = new Join();
330
            $closure($join);
331
        }
332
333
        if ($table instanceof Closure) {
0 ignored issues
show
introduced by
$table is never a sub-type of Closure.
Loading history...
334
            $table = Expression::fromClosure($table);
335
        }
336
337
        if (!is_array($table)) {
0 ignored issues
show
introduced by
The condition is_array($table) is always true.
Loading history...
338
            $table = [$table];
339
        }
340
341
        $this->joins[] = [
342
            'type' => $type,
343
            'table' => $table,
344
            'join' => $join
345
        ];
346
    }
347
348
    /**
349
     * @param Closure $closure
350
     * @param string $separator
351
     *
352
     * @return void
353
     */
354
    public function addHavingGroup(Closure $closure, string $separator): void
355
    {
356
        $having = new HavingStatement();
357
        $closure($having);
358
359
        $this->having[] = [
360
            'type' => 'havingNested',
361
            'conditions' => $having->getQueryStatement()->getHaving(),
362
            'separator' => $separator
363
        ];
364
    }
365
366
    /**
367
     * @param string|Closure|Expression $aggregate
368
     * @param mixed $value
369
     * @param string $operator
370
     * @param string $separator
371
     *
372
     * @return void
373
     */
374
    public function addHaving(
375
        string|Closure|Expression $aggregate,
376
        mixed $value,
377
        string $operator,
378
        string $separator
379
    ): void {
380
        $this->having[] = [
381
            'type' => 'havingCondition',
382
            'aggregate' => $this->closureToExpression($aggregate),
383
            'value' => $this->closureToExpression($value),
384
            'operator' => $operator,
385
            'separator' => $separator
386
        ];
387
    }
388
389
    /**
390
     * @param string|Closure|Expression $aggregate
391
     * @param mixed $value
392
     * @param string $separator
393
     * @param bool $not
394
     *
395
     * @return void
396
     */
397
    public function addHavingIn(
398
        string|Closure|Expression $aggregate,
399
        mixed $value,
400
        string $separator,
401
        bool $not
402
    ): void {
403
        $aggregateName = $this->closureToExpression($aggregate);
404
405
        if ($value instanceof Closure) {
406
            $select = new SubQuery();
407
            $value($select);
408
409
            $this->having[] = [
410
                'type' => 'havingInSelect',
411
                'aggregate' => $aggregateName,
412
                'subquery' => $select,
413
                'separator' => $separator,
414
                'not' => $not
415
            ];
416
        } else {
417
            $this->having[] = [
418
                'type' => 'havingIn',
419
                'aggregate' => $aggregateName,
420
                'value' => $value,
421
                'separator' => $separator,
422
                'not' => $not
423
            ];
424
        }
425
    }
426
427
    /**
428
     * @param string|Closure|Expression $aggregate
429
     * @param mixed $value1
430
     * @param mixed $value2
431
     * @param string $separator
432
     * @param bool $not
433
     *
434
     * @return void
435
     */
436
    public function addHavingBetween(
437
        string|Closure|Expression $aggregate,
438
        mixed $value1,
439
        mixed $value2,
440
        string $separator,
441
        bool $not
442
    ): void {
443
        $this->having[] = [
444
            'type' => 'havingBetween',
445
            'aggregate' => $this->closureToExpression($aggregate),
446
            'value1' => $this->closureToExpression($value1),
447
            'value2' => $this->closureToExpression($value2),
448
            'separator' => $separator,
449
            'not' => $not
450
        ];
451
    }
452
453
    /**
454
     * @param array<int, string> $tables
455
     */
456
    public function addTables(array $tables): void
457
    {
458
        $this->tables = $tables;
459
    }
460
461
    /**
462
     * @param array<int|string, mixed> $columns
463
     */
464
    public function addUpdateColumns(array $columns): void
465
    {
466
        foreach ($columns as $column => $value) {
467
            $this->columns[] = [
468
                'column' => $column,
469
                'value' => $this->closureToExpression($value)
470
            ];
471
        }
472
    }
473
474
    /**
475
     * @param string[]|Expression[]|Closure[] $columns
476
     * @param string $order
477
     *
478
     * @return void
479
     */
480
    public function addOrder(array $columns, string $order): void
481
    {
482
        foreach ($columns as &$column) {
483
            $column = $this->closureToExpression($column);
484
        }
485
        $orderValue = strtoupper($order);
486
487
        if (!in_array($orderValue, ['ASC', 'DESC'])) {
488
            $orderValue = 'ASC';
489
        }
490
491
        $this->order[] = [
492
            'columns' => $columns,
493
            'order' => $orderValue
494
        ];
495
    }
496
497
    /**
498
     * @param string[]|Expression[]|Closure[] $columns
499
     *
500
     * @return void
501
     */
502
    public function addGroupBy(array $columns): void
503
    {
504
        $cols = [];
505
        foreach ($columns as &$column) {
506
            $cols[] = $this->closureToExpression($column);
507
        }
508
509
        $this->group = $cols;
510
    }
511
512
    /**
513
     * @param string|Expression|Closure $column
514
     * @param string|null $alias
515
     *
516
     * @return void
517
     */
518
    public function addColumn(
519
        string|Expression|Closure $column,
520
        ?string $alias = null
521
    ): void {
522
        $this->columns[] = [
523
            'name' => $this->closureToExpression($column),
524
            'alias' => $alias
525
        ];
526
    }
527
528
    /**
529
     * @param bool $value
530
     */
531
    public function setDistinct(bool $value): void
532
    {
533
        $this->distinct = $value;
534
    }
535
536
    /**
537
     * @param int $value
538
     */
539
    public function setLimit(int $value): void
540
    {
541
        $this->limit = $value;
542
    }
543
544
    /**
545
     * @param int $value
546
     */
547
    public function setOffset(int $value): void
548
    {
549
        $this->offset = $value;
550
    }
551
552
    /**
553
     * @param string $table
554
     */
555
    public function setInto(string $table): void
556
    {
557
        $this->intoTable = $table;
558
    }
559
560
    /**
561
     * @param array<int, string> $from
562
     */
563
    public function setFrom(array $from): void
564
    {
565
        $this->from = $from;
566
    }
567
568
    /**
569
     * @param mixed $value
570
     */
571
    public function addValue(mixed $value): void
572
    {
573
        $this->values[] = $this->closureToExpression($value);
574
    }
575
576
    /**
577
     * @return array<int, mixed>
578
     */
579
    public function getWheres(): array
580
    {
581
        return $this->wheres;
582
    }
583
584
    /**
585
     * @return array<int, mixed>
586
     */
587
    public function getHaving(): array
588
    {
589
        return $this->having;
590
    }
591
592
    /**
593
     * @return array<int, mixed>
594
     */
595
    public function getJoins(): array
596
    {
597
        return $this->joins;
598
    }
599
600
    /**
601
     * @return bool
602
     */
603
    public function hasDistinct(): bool
604
    {
605
        return $this->distinct;
606
    }
607
608
    /**
609
     * @return array<int, string>
610
     */
611
    public function getTables(): array
612
    {
613
        return $this->tables;
614
    }
615
616
    /**
617
     * @return array<int, array<string, mixed>>
618
     */
619
    public function getColumns(): array
620
    {
621
        return $this->columns;
622
    }
623
624
    /**
625
     * @return array<int, array<string, mixed>>
626
     */
627
    public function getOrder(): array
628
    {
629
        return $this->order;
630
    }
631
632
    /**
633
     * @return string[]|Expression[]
634
     */
635
    public function getGroupBy(): array
636
    {
637
        return $this->group;
638
    }
639
640
    /**
641
     * @return int
642
     */
643
    public function getLimit(): int
644
    {
645
        return $this->limit;
646
    }
647
648
    /**
649
     * @return int
650
     */
651
    public function getOffset(): int
652
    {
653
        return $this->offset;
654
    }
655
656
    /**
657
     * @return string|null
658
     */
659
    public function getIntoTable(): ?string
660
    {
661
        return $this->intoTable;
662
    }
663
664
    /**
665
     * @return array<int, string>
666
     */
667
    public function getFrom(): array
668
    {
669
        return $this->from;
670
    }
671
672
    /**
673
     * @return array<int, mixed>
674
     */
675
    public function getValues(): array
676
    {
677
        return $this->values;
678
    }
679
680
    /**
681
     * @param mixed $value
682
     *
683
     * @return mixed|Expression
684
     */
685
    protected function closureToExpression(mixed $value): mixed
686
    {
687
        if ($value instanceof Closure) {
688
            return Expression::fromClosure($value);
689
        }
690
691
        return $value;
692
    }
693
}
694