• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

znframework / fullpack-edition / 8716966645

17 Apr 2024 05:48AM UTC coverage: 98.608% (-1.0%) from 99.589%
8716966645

push

github

zntr
Updated test.yml

10341 of 10487 relevant lines covered (98.61%)

33.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.72
/Internal/package-database/DB.php
1
<?php namespace ZN\Database;
2
/**
3
 * ZN PHP Web Framework
4
 * 
5
 * "Simplicity is the ultimate sophistication." ~ Da Vinci
6
 * 
7
 * @package ZN
8
 * @license MIT [http://opensource.org/licenses/MIT]
9
 * @author  Ozan UYKUN [ozan@znframework.com]
10
 */
11

12
use ZN\Base;
13
use ZN\Config;
14
use ZN\Datatype;
15
use ZN\Singleton;
16
use ZN\Request\URI;
17
use ZN\Request\Method;
18
use ZN\Protection\Json;
19
use ZN\DataTypes\Arrays;
20
use ZN\Filesystem\Converter;
21
use ZN\Database\Exception\UnconditionalException;
22
use ArrayObject;
23

24
#[\AllowDynamicProperties]
25

26
class DB extends Connection
27
{
28
    /**
29
     * Vartype Elements
30
     * 
31
     * @var array
32
     */
33
    protected $vartypeElements =
34
    [
35
        'int'     , 'smallint', 'tinyint'   , 'mediumint', 'bigint',
36
        'decimal' , 'double'  , 'float'     ,
37
        'char'    , 'varchar' , 
38
        'tinytext', 'text'    , 'mediumtext', 'longtext' ,
39
        'date'    , 'time'    , 'timestamp' , 'datetime' ,
40
        
41
        'integer' => 'int'
42
    ];
43

44
    /**
45
     * Statement Elements
46
     * 
47
     * @var array
48
     */
49
    protected $statementElements =
50
    [
51
        'autoincrement', 'primarykey', 'foreignkey', 'unique',
52
        'null'         , 'notnull'   ,
53
        'exists'       , 'notexists' ,
54
        'constraint'
55
    ];
56

57
    /**
58
     * Function Elements
59
     * 
60
     * @var array
61
     */
62
    protected $functionElements =
63
    [
64
        'ifnull' , 'nullif'      , 'abs'      , 'mod'      , 'asin'     ,
65
        'acos'   , 'atan'        , 'atan2'    , 'ceil'     , 'ceiling'  ,
66
        'cos'    , 'cot'         , 'crc32'    , 'degrees'  , 'exp'      ,
67
        'floor'  , 'ln'          , 'log10'    , 'log2'     , 'log'      ,
68
        'pi'     , 'pow'         , 'power'    , 'radians'  , 'rand'     ,
69
        'round'  , 'sign'        , 'sin'      , 'sqrt'     , 'tan'      ,
70
        'ascii'  , 'field'       , 'format'   , 'lower'    , 'upper'    ,
71
        'length' , 'ltrim'       , 'substring', 'ord'      , 'position' ,
72
        'quote'  , 'repeat'      , 'rtrim'    , 'soundex'  , 'space'    ,
73
        'substr' , 'trim'        , 'ucase'    , 'lcase'    , 'benchmark',
74
        'charset', 'coercibility', 'user'     , 'collation', 'database' ,
75
        'schema' , 'avg'         , 'min'      , 'max'      , 'count'    ,
76
        'sum'    , 'variance'    ,
77
        'ifelse'         => 'IF'             ,
78
        'charlength'     => 'CHAR_LENGTH'    ,
79
        'substringindex' => 'SUBSTRING_INDEX',
80
        'connectionid'   => 'CONNECTION_ID'  ,
81
        'currentuser'    => 'CURRENT_USER'   ,
82
        'lastinsertid'   => 'LAST_INSERT_ID' ,
83
        'systemuser'     => 'SYSTEM_USER'    ,
84
        'sessionuser'    => 'SESSION_USER'   ,
85
        'rowcount'       => 'ROW_COUNT'      ,
86
        'versioninfo'    => 'VERSION'
87
    ];
88

89
    /*
90
    |--------------------------------------------------------------------------
91
    | Scalar Variables
92
    |--------------------------------------------------------------------------
93
    |
94
    | Definitions of scaled of variables.
95
    |
96
    */
97

98
    private $select     , $where       , $distinct         , $highPriority, $lowPriority  ;
99
    private $delayed    , $procedure   , $outFile          , $characterSet, $into         ;
100
    private $forUpdate  , $quick       , $ignore           , $partition   , $straightJoin ;
101
    private $smallResult, $bigResult   , $bufferResult     , $cache       , $calcFoundRows;
102
    private $groupBy    , $having      , $orderBy          , $limit       , $join         ;
103
    private $transStart , $transError  , $duplicateCheck   , $duplicateCheckUpdate        ;
104
    private $joinType   , $joinTable   , $unionQuery = NULL, $caching = [], $jsonDecode   ;
105
    private $hashId     , $hashIdColumn, $isUpdate = false , $unset   = [], $object       ;
106
    private $preselect  , $results     , $returnQueryType  , $paging  = 'row'             ;
107

108
    /**
109
     * Callable talking queries.
110
     */
111
    use CallableTalkingQueries;
112

113
    public function preselect($preselect)
114
    {
115
        $this->preselect = $preselect . ' ';
×
116

117
        return $this;
×
118
    }
119

120
    /**
121
     * Defines SQL SELECT
122
     * 
123
     * @param string ...$condition
124
     * 
125
     * @return DB
126
     */
127
    public function select(...$condition) : DB
128
    {
129
        if( empty($condition[0]) )
24✔
130
        {
131
            $condition[0] = '*';
2✔
132
        }
133

134
        $condition = rtrim(implode(',', array_map(function($value)
135
        { 
136
            return preg_replace_callback('/(?<database>\w+\.)*(?<table>\w+\.\w+)/', function($data)
137
            {
138
                return $data['database'] . $this->prefix . $data['table'];
2✔
139
            }, $value);
24✔
140
            
141
        }, $condition)), ',');
24✔
142

143
        $this->select = ' '.$condition.' ';
24✔
144

145
        return $this;
24✔
146
    }
147

148
    /**
149
     * Defines SQL WHERE 
150
     * 
151
     * @param mixed  $column
152
     * @param string $value   = NULL
153
     * @param string $logical = NULL
154
     * 
155
     * @return DB
156
     */
157
    public function where($column, $value = NULL, string $logical = NULL) : DB
158
    {
159
        $this->buildWhereHavingClause($column, $value, $logical, __FUNCTION__);
250✔
160

161
        return $this;
250✔
162
    }
163

164
    /**
165
     * Defines SQL WHERE 
166
     * 
167
     * @param mixed  $column
168
     * @param string $value   = NULL
169
     * 
170
     * @return DB
171
     */
172
    public function whereAnd($column, $value = NULL) : DB
173
    {
174
        $this->where($column, $value, 'AND');
2✔
175

176
        return $this;
2✔
177
    }
178

179
    /**
180
     * Defines SQL WHERE 
181
     * 
182
     * @param mixed  $column
183
     * @param string $value   = NULL
184
     * 
185
     * @return DB
186
     */
187
    public function whereOr($column, $value = NULL) : DB
188
    {
189
        $this->where($column, $value, 'OR');
2✔
190

191
        return $this;
2✔
192
    }
193

194
    /**
195
     * WHERE NULL OR EMPTY
196
     * 
197
     * @param mixed  $column
198
     * @param string $logical = NULL
199
     * 
200
     * @return DB
201
     */
202
    public function whereEmpty($column, string $logical = NULL) : DB
203
    {
204
        $group[] = ['exp:' . $column, '""', 'or'];
4✔
205
        $group[] = ['exp:' . $column . ' is', 'null'];
4✔
206

207
        if( $logical !== NULL )
4✔
208
        {
209
            $group[] = $logical;
2✔
210
        }
211

212
        $this->whereGroup(...$group);
4✔
213

214
        return $this;
4✔
215
    }
216

217
    /**
218
     * WHERE NOT [NULL AND EMPTY]
219
     * 
220
     * @param mixed  $column
221
     * @param string $logical = NULL
222
     * 
223
     * @return DB
224
     */
225
    public function whereNotEmpty($column, string $logical = NULL) : DB
226
    {
227
        $group[] = ['exp:' . $column . ' !=', '""', 'and'];
4✔
228
        $group[] = ['exp:' . $column . ' is not', 'null'];
4✔
229

230
        if( $logical !== NULL )
4✔
231
        {
232
            $group[] = $logical;
2✔
233
        }
234

235
        $this->whereGroup(...$group);
4✔
236

237
        return $this;
4✔
238
    }
239

240
    /**
241
     * WHERE NULL
242
     * 
243
     * @param mixed  $column
244
     * @param string $logical = NULL
245
     * 
246
     * @return DB
247
     */
248
    public function whereNull($column, string $logical = NULL) : DB
249
    {
250
        $this->where('exp:' . $column . ' is', 'null', $logical);
2✔
251

252
        return $this;
2✔
253
    }
254

255
    /**
256
     * WHERE NOT NULL
257
     * 
258
     * @param mixed  $column
259
     * @param string $logical = NULL
260
     * 
261
     * @return DB
262
     */
263
    public function whereNotNull($column, string $logical = NULL) : DB
264
    {
265
        $this->where('exp:' . $column . ' is', 'not null', $logical);
2✔
266

267
        return $this;
2✔
268
    }
269

270
     /**
271
     * Defines SQL WHERE 
272
     * 
273
     * @param mixed  $column
274
     * @param string $value   = NULL
275
     * @param string $logical = NULL
276
     * 
277
     * @return DB
278
     */
279
    public function whereNot($column, $value = NULL, string $logical = NULL) : DB
280
    {
281
        $this->where($column . ' != ', $value, $logical);
2✔
282

283
        return $this;
2✔
284
    }
285

286
    /**
287
     * Defines SQL WHERE JSON_SEARCH IS NOT NULL
288
     * 
289
     * @param mixed  $column
290
     * @param string $value   = NULL
291
     * @param string $logical = NULL
292
     * 
293
     * @return DB
294
     */
295
    public function whereJson($column, $value = NULL, string $logical = NULL) : DB
296
    {
297
        $this->specialDefinedWhere($column, $value, $logical, __FUNCTION__);
2✔
298

299
        return $this;
2✔
300
    }
301

302
    /**
303
     * Defines SQL WHERE JSON_SEARCH IS NULL
304
     * 
305
     * @param mixed  $column
306
     * @param string $value   = NULL
307
     * @param string $logical = NULL
308
     * 
309
     * @return DB
310
     */
311
    public function whereNotJson($column, $value = NULL, string $logical = NULL) : DB
312
    {
313
        $this->specialDefinedWhere($column, $value, $logical, __FUNCTION__);
2✔
314

315
        return $this;
2✔
316
    }
317

318
    /**
319
     * Full Text
320
     * 
321
     * 5.7.4[added]
322
     * 
323
     * @param string $column
324
     * @param string $value
325
     * @param string $type = NULL
326
     * 
327
     * @return string
328
     */
329
    public function whereFullText($column, $value = NULL, string $type = NULL, string $logical = NULL) : DB
330
    {
331
        $this->where('exp:' . $this->db->fullText($column, $this->escapeStringAddNail($value), $type), '', $logical);
2✔
332

333
        return $this;
2✔
334
    }
335

336
    /**
337
     * Defines SQL WHERE BETWEEN value1 and value2
338
     * 
339
     * @param mixed  $column
340
     * @param string $value1  = NULL
341
     * @param string $value2  = NULL
342
     * @param string $logical = NULL
343
     * 
344
     * @return DB
345
     */
346
    public function whereBetween($column, string $value1 = NULL, string $value2 = NULL, string $logical = NULL) : DB
347
    {
348
        $this->where($column . ' between', $this->between($value1, $value2), $logical);
2✔
349

350
        return $this;
2✔
351
    }
352

353
    /**
354
     * Defines SQL WHERE LIKE %value%
355
     * 
356
     * @param mixed  $column
357
     * @param string $value   = NULL
358
     * @param string $logical = NULL
359
     * 
360
     * @return DB
361
     */
362
    public function whereLike($column, $value = NULL, string $logical = NULL) : DB
363
    {
364
        $this->where($column . ' like', $this->like($value, 'inside'), $logical);
2✔
365

366
        return $this;
2✔
367
    }
368

369
    /**
370
     * Defines SQL WHERE LIKE value%
371
     * 
372
     * @param mixed  $column
373
     * @param string $value   = NULL
374
     * @param string $logical = NULL
375
     * 
376
     * @return DB
377
     */
378
    public function whereStartLike($column, $value = NULL, string $logical = NULL) : DB
379
    {
380
        $this->where($column . ' like', $this->like($value, 'starting'), $logical);
4✔
381

382
        return $this;
4✔
383
    }
384

385
    /**
386
     * Defines SQL WHERE LIKE %value
387
     * 
388
     * @param mixed  $column
389
     * @param string $value   = NULL
390
     * @param string $logical = NULL
391
     * 
392
     * @return DB
393
     */
394
    public function whereEndLike($column, $value = NULL, string $logical = NULL) : DB
395
    {
396
        $this->where($column . ' like', $this->like($value, 'ending'), $logical);
2✔
397

398
        return $this;
2✔
399
    }
400

401
    /**
402
     * Defines SQL WHERE IN(...$values)
403
     * 
404
     * @param mixed  $column
405
     * @param array  $values  = []
406
     * @param string $logical = NULL
407
     * 
408
     * @return DB
409
     */
410
    public function whereIn($column, array $values = [], string $logical = NULL) : DB
411
    {
412
        $this->where($column . ' in', $this->in(...$values), $logical);
2✔
413

414
        return $this;
2✔
415
    }
416

417
    /**
418
     * Defines SQL WHERE NOT IN(...$values)
419
     * 
420
     * @param mixed  $column
421
     * @param array  $values  = []
422
     * @param string $logical = NULL
423
     * 
424
     * @return DB
425
     */
426
    public function whereNotIn($column, array $values = [], string $logical = NULL) : DB
427
    {
428
        $this->where($column . ' not in', $this->notIn(...$values), $logical);
2✔
429

430
        return $this;
2✔
431
    }
432

433
    /**
434
     * Defines SQL WHERE IN(SELECT * FROM $table)
435
     * 
436
     * @param mixed  $column
437
     * @param string $table
438
     * @param string $logical = NULL
439
     * 
440
     * @return DB
441
     */
442
    public function whereInTable($column, string $table, string $logical = NULL) : DB
443
    {
444
        $this->where($column . ' in', $this->inTable($table), $logical);
2✔
445

446
        return $this;
2✔
447
    }
448

449
    /**
450
     * Defines SQL WHERE IN(SELECT * FROM $table)
451
     * 
452
     * @param mixed  $column
453
     * @param string $table
454
     * @param string $logical = NULL
455
     * 
456
     * @return DB
457
     */
458
    public function whereInQuery($column, string $table, string $logical = NULL) : DB
459
    {
460
        $this->where($column . ' in', $this->inQuery($table), $logical);
2✔
461

462
        return $this;
2✔
463
    }
464

465
    /**
466
     * Defines SQL WHERE 
467
     * 
468
     * @param array ...$args
469
     * 
470
     * @return DB
471
     */
472
    public function whereGroup(...$args) : DB
473
    {
474
        $this->where .= $this->whereHavingGroup($args);
10✔
475

476
        return $this;
10✔
477
    }
478

479
    /** 
480
     * Having Group
481
     * 
482
     * @param array ...$args
483
     * 
484
     * @return DB
485
     */
486
    public function havingGroup(...$args) : DB
487
    {
488
        $this->having .= $this->whereHavingGroup($args);
2✔
489

490
        return $this;
2✔
491
    }
492

493
    /**
494
     * Defines SQL HAVING 
495
     * 
496
     * @param mixed  $column
497
     * @param string $value   = NULL
498
     * @param string $logical = NULL
499
     * 
500
     * @return DB
501
     */
502
    public function having($column, $value = NULL, string $logical = NULL) : DB
503
    {
504
        $this->buildWhereHavingClause($column, $value, $logical, __FUNCTION__);
2✔
505

506
        return $this;
2✔
507
    }
508

509
    /**
510
     * Caching Query
511
     * 
512
     * @param string $time
513
     * @param string $driver = NULL
514
     * 
515
     * @return DB
516
     */
517
    public function caching($time, string $driver = NULL) : DB
518
    {
519
        $this->caching['time']   = $time;
2✔
520
        $this->caching['driver'] = $driver ?? $this->config['cacheDriver'] ?? 'file';
2✔
521

522
        return $this;
2✔
523
    }
524

525
    /**
526
     * Clean Cache
527
     * 
528
     * @param string $driver = 'file'
529
     * 
530
     * @return bool
531
     */
532
    public function cleanCaching(string $driver = 'file') : bool
533
    {
534
        return Singleton::class('ZN\Cache\Processor')->driver($this->caching['driver'] ?? $driver)->delete($this->getEncryptedCacheQuery());
2✔
535
    }
536

537
    /**
538
     * Join table
539
     * 
540
     * @param string $table
541
     * @param string $condition
542
     * @param string $type = NULL
543
     * 
544
     * @return DB
545
     */
546
    public function join(string $table, string $condition, string $type = NULL) : DB
547
    {
548
        $tableEx = explode('.', $table);
18✔
549

550
        switch( count($tableEx) )
18✔
551
        {
552
            case 2:
18✔
553
                $table = $tableEx[0] . '.' . $this->prefix . $tableEx[1];
2✔
554
            break;
2✔
555

556
            case 1:
16✔
557
                $table   = $this->prefix.$table;
16✔
558
            break;
16✔
559
        }
560

561
        $type = strtoupper((string) $type);
18✔
562

563
        $this->joinType  = $type;
18✔
564
        $this->joinTable = $table;
18✔
565

566
        $this->join .= ' '.$type.' JOIN '.$table.' ON '.$condition.' ';
18✔
567

568
        return $this;
18✔
569
    }
570

571
    /**
572
     * Inner Join
573
     * 
574
     * @param string $mainTableAndColumn
575
     * @param string $otherTableAndColumn
576
     * @param string $operator = '='
577
     * 
578
     * @return DB
579
     */
580
    public function innerJoin(string $table, string $otherColumn, string $operator = '=') : DB
581
    {
582
        $this->buildJoinClause($table, $otherColumn, $operator, 'INNER');
2✔
583

584
        return $this;
2✔
585
    }
586

587
    /**
588
     * Outer Join
589
     * 
590
     * @param string $mainTableAndColumn
591
     * @param string $otherTableAndColumn
592
     * @param string $operator = '='
593
     * 
594
     * @return DB
595
     */
596
    public function outerJoin(string $table, string $otherColumn, string $operator = '=') : DB
597
    {
598
        $this->buildJoinClause($table, $otherColumn, $operator, 'FULL OUTER');
2✔
599

600
        return $this;
2✔
601
    }
602

603
    /**
604
     * Left Join
605
     * 
606
     * @param string $mainTableAndColumn
607
     * @param string $otherTableAndColumn
608
     * @param string $operator = '='
609
     * 
610
     * @return DB
611
     */
612
    public function leftJoin(string $table, string $otherColumn, string $operator = '=') : DB
613
    {
614
        $this->buildJoinClause($table, $otherColumn, $operator, 'LEFT');
10✔
615

616
        return $this;
10✔
617
    }
618

619
    /**
620
     * Right Join
621
     * 
622
     * @param string $mainTableAndColumn
623
     * @param string $otherTableAndColumn
624
     * @param string $operator = '='
625
     * 
626
     * @return DB
627
     */
628
    public function rightJoin(string $table, string $otherColumn, string $operator = '=') : DB
629
    {
630
        $this->buildJoinClause($table, $otherColumn, $operator, 'RIGHT');
4✔
631

632
        return $this;
4✔
633
    }
634

635
    /**
636
     * Group By
637
     * 
638
     * @param string ...$args
639
     * 
640
     * @return DB
641
     */
642
    public function groupBy(...$args) : DB
643
    {
644
        $this->groupBy .= implode(',', $args).', ';
8✔
645

646
        return $this;
8✔
647
    }
648

649
    /**
650
     * Order By
651
     * 
652
     * @param mixed  $condition
653
     * @param string $type = NULL
654
     * 
655
     * @return DB
656
     */
657
    public function orderBy($condition, string $type = NULL) : DB
658
    {
659
        if( is_string($condition) )
10✔
660
        {
661
            $this->orderBy .= $condition.' '.$type.', ';
8✔
662
        }
663
        else
664
        {
665
            if( ! empty($condition) ) foreach( $condition as $key => $val )
2✔
666
            {
667
                $this->orderBy .= $key.' '.$val.', ';
2✔
668
            }
669
        }
670

671
        return $this;
10✔
672
    }
673

674
    /**
675
     * Order By Field
676
     * 
677
     * @param string $field
678
     * @param array  $values
679
     * 
680
     * @return DB
681
     */
682
    public function orderByField(string $field, array $values) : DB
683
    {
684
        $revalues = [];
2✔
685

686
        foreach( $values as $value )
2✔
687
        {
688
            $revalues[] = $this->escapeStringAddNail($value ?? '', true);
2✔
689
        }
690

691
        return $this->orderBy('FIELD(' . $field . ', ' . implode(', ', $revalues) . ')');
2✔
692
    }
693

694
    /**
695
     * Order By Random
696
     * 
697
     * @return DB
698
     */
699
    public function orderByRandom() : DB
700
    {
701
        return $this->orderBy('rand()');
2✔
702
    }
703

704
    /**
705
     * Limit
706
     * 
707
     * @param int $start = NULL
708
     * @param int $limit = 0
709
     * 
710
     * @return DB
711
     */
712
    public function limit($start = NULL, int $limit = 0) : DB
713
    {
714
        if( $start < 0 )
18✔
715
        {
716
            $start = $this->paging(is_numeric($segment = URI::segment($start)) ? $segment : 1, $limit);
2✔
717

718
            $this->paging = 'page';
2✔
719
        }
720
        else if( $start === NULL )
16✔
721
        {
722
            $start = URI::segment(-1);
4✔
723
        }
724

725
        $start = (int) $start;
18✔
726

727
        $this->limit = $this->db->limit($start, $limit);
18✔
728
        
729
        return $this;
18✔
730
    }
731

732
    /**
733
     * protected paging
734
     */
735
    protected function paging($start, $limit)
736
    {
737
        if( $start == 0 )
2✔
738
        {
739
            return 1; // @codeCoverageIgnore
740
        }
741

742
        return ($start - 1) * $limit;
2✔
743
    }
744

745
    /**
746
     * Basic Query
747
     * 
748
     * @return DB
749
     */
750
    public function basic() : DB
751
    {
752
        $this->returnQueryType = 'basicQuery';
2✔
753

754
        return $this;
2✔
755
    }
756

757
    /**
758
     * Get Table
759
     * 
760
     * @param string $table  = NULL
761
     * @param string $return = 'object' - Options['object'|'array'|'json']
762
     * 
763
     * @return mixed
764
     */
765
    public function get(string $table = NULL, string $return = 'object')
766
    {
767
        $this->tableName = $table = $this->addPrefixForTableAndColumn($table, 'table');
408✔
768
     
769
        $finalQuery =     $this->preselect  . 
408✔
770
                          'SELECT '         . 
408✔
771
                          $this->distinct   . $this->highPriority . $this->straightJoin . 
408✔
772
                          $this->smallResult. $this->bigResult    . $this->bufferResult . 
408✔
773
                          $this->cache      . $this->calcFoundRows. $this->buildSelectClause()    .
408✔
774
                          ' FROM '          . 
408✔
775
                          $table.' '        . $this->partition    . $this->join         . 
408✔
776
                          $this->buildWhereClause()   . $this->buildGroupByClause()   . $this->buildHavingClause()    . 
408✔
777
                          $this->buildOrderByClause() . $this->limit        . $this->procedure    . 
408✔
778
                          $this->outFile    . $this->characterSet . $this->into         .
408✔
779
                          $this->forUpdate;
408✔
780

781
        if( $this->unionQuery !== NULL )
408✔
782
        {
783
            $finalQuery       = $this->unionQuery . ' ' . $finalQuery;
2✔
784
            $this->unionQuery = NULL;
2✔
785
        }
786

787
        $returnQuery = $this->returnQueryType ?? 'query';
408✔
788

789
        $isString = $this->string === true || $return === 'string';
408✔
790

791
        $finalQuery = $this->querySecurity($finalQuery, $isString);
408✔
792

793
        $this->resetSelectQueryVariables();
408✔
794

795
        if( $isString )
408✔
796
        {
797
            $this->string = NULL;
86✔
798

799
            return $finalQuery;
86✔
800
        }
801

802
        if( $this->transaction === true )
324✔
803
        {
804
            $this->transactionQueries[] = $finalQuery;
2✔
805

806
            return $this;
2✔
807
        }
808

809
        return $this->$returnQuery($finalQuery, $this->secure);
322✔
810
    }
811

812
    /**
813
     * Duplicate Check
814
     * 
815
     * @param string ...$args
816
     * 
817
     * @return DB
818
     */
819
    public function duplicateCheck(...$args) : DB
820
    {
821
        $this->duplicateCheck = $args;
38✔
822

823
        if( empty($this->duplicateCheck) )
38✔
824
        {
825
            $this->duplicateCheck[0] = '*';
10✔
826
        }
827

828
        return $this;
38✔
829
    }
830

831
    /**
832
     * Duplicate Check Update
833
     * 
834
     * @param string ...$args
835
     * 
836
     * @return DB
837
     */
838
    public function duplicateCheckUpdate(...$args) : DB
839
    {
840
        $this->duplicateCheck(...$args);
4✔
841

842
        $this->duplicateCheckUpdate = true;
4✔
843

844
        return $this;
4✔
845
    }
846

847
    /**
848
     * Real Escape String 
849
     * 
850
     * @param string $data
851
     * 
852
     * @return string
853
     */
854
    public function escapeString(string $data) : string
855
    {
856
        return $this->db->realEscapeString($data);
2✔
857
    }
858

859
    /**
860
     * Real Escape String 
861
     * 
862
     * @param string $data
863
     * 
864
     * @return string
865
     */
866
    public function realEscapeString(string $data) : string
867
    {
868
        return $this->db->realEscapeString($data);
6✔
869
    }
870

871
    /**
872
     * Get String Query
873
     * 
874
     * @param string $table = NULL
875
     * 
876
     * @return string
877
     */
878
    public function getString(string $table = NULL) : string
879
    {
880
        return $this->get($table, 'string');
2✔
881
    }
882

883
    /**
884
     * Set aliases
885
     * 
886
     * @param array $aliases
887
     * 
888
     * @return self
889
     */
890
    public function aliases(array $aliases)
891
    {
892
        $this->aliases = $aliases;
4✔
893

894
        return $this;
4✔
895
    }
896

897
    /**
898
     * Alias
899
     * 
900
     * @param string $string
901
     * @param string $alias
902
     * @param bool   $brackets = false
903
     * 
904
     * @return string
905
     */
906
    public function alias(string $string, string $alias, bool $brackets = false) : string
907
    {
908
        if( $brackets === true)
2✔
909
        {
910
            $string = $this->brackets($string);
2✔
911
        }
912

913
        return $string.' AS '.$alias;
2✔
914
    }
915

916
    /**
917
     * Brackets
918
     * 
919
     * @param string $string
920
     * 
921
     * @return string
922
     */
923
    public function brackets(string $string) : string
924
    {
925
        return ' ( '.$string.' ) ';
2✔
926
    }
927

928
    /**
929
     * Defines SQL ALL
930
     * 
931
     * @return DB
932
     */
933
    public function all() : DB
934
    {
935
        $this->distinct = ' ALL ';
2✔
936
        return $this;
2✔
937
    }
938

939
    /**
940
     * Defines SQL DISTINCT
941
     * 
942
     * @return DB
943
     */
944
    public function distinct() : DB
945
    {
946
        $this->distinct = ' DISTINCT ';
2✔
947
        return $this;
2✔
948
    }
949

950
    /**
951
     * Defines SQL DISTINCTROW
952
     * 
953
     * @return DB
954
     */
955
    public function distinctRow() : DB
956
    {
957
        $this->distinct = ' DISTINCTROW ';
2✔
958
        return $this;
2✔
959
    }
960

961
    /**
962
     * Defines SQL STRAIGHT_JOIN
963
     * 
964
     * @return DB
965
     */
966
    public function straightJoin() : DB
967
    {
968
        $this->straightJoin = ' STRAIGHT_JOIN ';
2✔
969
        return $this;
2✔
970
    }
971

972
    /**
973
     * Defines SQL HIGH_PRIORITY
974
     * 
975
     * @return DB
976
     */
977
    public function highPriority() : DB
978
    {
979
        $this->highPriority = ' HIGH_PRIORITY ';
2✔
980
        return $this;
2✔
981
    }
982

983
    /**
984
     * Defines SQL LOW_PRIORITY
985
     * 
986
     * @return DB
987
     */
988
    public function lowPriority() : DB
989
    {
990
        $this->lowPriority = ' LOW_PRIORITY ';
2✔
991
        return $this;
2✔
992
    }
993

994
    /**
995
     * Defines SQL QUICK
996
     * 
997
     * @return DB
998
     */
999
    public function quick() : DB
1000
    {
1001
        $this->quick = ' QUICK ';
2✔
1002
        return $this;
2✔
1003
    }
1004

1005
    /**
1006
     * Defines SQL DELAYED
1007
     * 
1008
     * @return DB
1009
     */
1010
    public function delayed() : DB
1011
    {
1012
        $this->delayed = ' DELAYED ';
2✔
1013
        return $this;
2✔
1014
    }
1015

1016
    /**
1017
     * Defines SQL IGNORE
1018
     * 
1019
     * @return DB
1020
     */
1021
    public function ignore() : DB
1022
    {
1023
        $this->ignore = ' IGNORE ';
2✔
1024
        return $this;
2✔
1025
    }
1026

1027
    /**
1028
     * Defines SQL PARTITION
1029
     * 
1030
     * @param string ...$args
1031
     * 
1032
     * @return DB
1033
     */
1034
    public function partition(...$args) : DB
1035
    {
1036
        $this->partition = $this->setMathFunction(__FUNCTION__, $args)->args;
2✔
1037
        return $this;
2✔
1038
    }
1039

1040
    /**
1041
     * Defines SQL PROCEDURE
1042
     * 
1043
     * @param string ...$args
1044
     * 
1045
     * @return DB
1046
     */
1047
    public function procedure(...$args) : DB
1048
    {
1049
        $this->procedure = $this->setMathFunction(__FUNCTION__, $args)->args;
2✔
1050
        return $this;
2✔
1051
    }
1052

1053
    /**
1054
     * Defines SQL INTO OUTFILE
1055
     * 
1056
     * @param string $file
1057
     * 
1058
     * @return DB
1059
     */
1060
    public function outFile(string $file) : DB
1061
    {
1062
        $this->outFile = 'INTO OUTFILE '."'".$file."'".' ';
2✔
1063
        return $this;
2✔
1064
    }
1065

1066
    /**
1067
     * Defines SQL INTO DUMPFILE
1068
     * 
1069
     * @param string $file
1070
     * 
1071
     * @return DB
1072
     */
1073
    public function dumpFile(string $file) : DB
1074
    {
1075
        $this->into = 'INTO DUMPFILE '."'".$file."'".' ';
2✔
1076

1077
        return $this;
2✔
1078
    }
1079

1080
    /**
1081
     * Defines SQL REFERENCES table(column)
1082
     * 
1083
     * 5.7.4[added]
1084
     * 
1085
     * @return string
1086
     */
1087
    public function references(string $table, string $column) : string
1088
    {
1089
        return $this->db->references($table, $column);
2✔
1090
    }
1091

1092
    /**
1093
     * Foreign Key
1094
     * 
1095
     * 5.7.4[added]
1096
     * 
1097
     * @param string $column 
1098
     * @param string $references
1099
     * 
1100
     * @return string
1101
     */
1102
    public function foreignKey($column = NULL, $references = NULL) : string
1103
    {
1104
        return $this->db->foreignKey($column, $references);
64✔
1105
    }
1106

1107
    /**
1108
     * Defines SQL CHARACTER SET
1109
     * 
1110
     * @param string $set
1111
     * @param bool   $return = false
1112
     * 
1113
     * @return mixed
1114
     */
1115
    public function characterSet(string $set, bool $return = false)
1116
    {
1117
        $string = 'CHARACTER SET '.$set.' ';
6✔
1118

1119
        if( $return === false )
6✔
1120
        {
1121
            $this->characterSet = $string;
2✔
1122
            return $this;
2✔
1123
        }
1124
        else
1125
        {
1126
            return $string;
4✔
1127
        }
1128
    }
1129

1130
    /**
1131
     * Character Set
1132
     * 
1133
     * @param string $set
1134
     * 
1135
     * @return string
1136
     */
1137
    public function cset(string $set) : string
1138
    {
1139
        if( empty($set) )
4✔
1140
        {
1141
            $set = $this->config['charset'];
2✔
1142
        }
1143

1144
        return $this->characterSet($set, true);
4✔
1145
    }
1146

1147
    /**
1148
     * Defines SQL COLLATE
1149
     * 
1150
     * @param string $set
1151
     * 
1152
     * @return string
1153
     */
1154
    public function collate(string $set = NULL) : string
1155
    {
1156
        if( empty($set) )
4✔
1157
        {
1158
            $set = $this->config['collation'];
2✔
1159
        }
1160

1161
        return 'COLLATE '.$set.' ';
4✔
1162
    }
1163

1164

1165
    /**
1166
     * Sets encoding
1167
     * 
1168
     * @param string $charset = 'utf8'
1169
     * @param string $collate = 'utf8_general_ci'
1170
     * 
1171
     * @return string
1172
     */
1173
    public function encoding(string $charset = 'utf8', string $collate = 'utf8_general_ci') : string
1174
    {
1175
        $encoding  = $this->cset($charset);
2✔
1176
        $encoding .= $this->collate($collate);
2✔
1177

1178
        return $encoding;
2✔
1179
    }
1180

1181
    /**
1182
     * Defines SQL INTO
1183
     * 
1184
     * @param string $varname1
1185
     * @param string $varname2
1186
     * 
1187
     * @return DB
1188
     */
1189
    public function into(string $varname1, string $varname2 = NULL) : DB
1190
    {
1191
        $this->into = 'INTO '.$varname1.' ';
2✔
1192

1193
        if( ! empty($varname2) )
2✔
1194
        {
1195
            $this->into .= ', '.$varname2.' ';
2✔
1196
        }
1197

1198
        return $this;
2✔
1199
    }
1200

1201
    /**
1202
     * Defines SQL FOR UPDATE
1203
     * 
1204
     * @return DB
1205
     */
1206
    public function forUpdate() : DB
1207
    {
1208
        $this->forUpdate = ' FOR UPDATE ';
2✔
1209

1210
        return $this;
2✔
1211
    }
1212

1213
    /**
1214
     * Defines SQL LOCK IN SHARE MODE
1215
     * 
1216
     * @return DB
1217
     */
1218
    public function lockInShareMode() : DB
1219
    {
1220
        $this->forUpdate = ' LOCK IN SHARE MODE ';
2✔
1221

1222
        return $this;
2✔
1223
    }
1224

1225
    /**
1226
     * Defines SQL SQL_SMALL_RESULT
1227
     * 
1228
     * @return DB
1229
     */
1230
    public function smallResult() : DB
1231
    {
1232
        $this->smallResult = ' SQL_SMALL_RESULT ';
2✔
1233

1234
        return $this;
2✔
1235
    }
1236

1237
    /**
1238
     * Defines SQL SQL_BIG_RESULT
1239
     * 
1240
     * @return DB
1241
     */
1242
    public function bigResult() : DB
1243
    {
1244
        $this->bigResult = ' SQL_BIG_RESULT ';
2✔
1245

1246
        return $this;
2✔
1247
    }
1248

1249
    /**
1250
     * Defines SQL SQL_BUFFER_RESULT
1251
     * 
1252
     * @return DB
1253
     */
1254
    public function bufferResult() : DB
1255
    {
1256
        $this->bufferResult = ' SQL_BUFFER_RESULT ';
2✔
1257

1258
        return $this;
2✔
1259
    }
1260

1261
    /**
1262
     * Defines SQL SQL_CACHE
1263
     * 
1264
     * @return DB
1265
     */
1266
    public function cache() : DB
1267
    {
1268
        $this->cache = ' SQL_CACHE ';
2✔
1269

1270
        return $this;
2✔
1271
    }
1272

1273
    /**
1274
     * Defines SQL SQL_NO_CACHE
1275
     * 
1276
     * @return DB
1277
     */
1278
    public function noCache() : DB
1279
    {
1280
        $this->cache = ' SQL_NO_CACHE ';
2✔
1281

1282
        return $this;
2✔
1283
    }
1284

1285
    /**
1286
     * Defines SQL SQL_CALC_FOUND_ROWS
1287
     * 
1288
     * @return DB
1289
     */
1290
    public function calcFoundRows() : DB
1291
    {
1292
        $this->calcFoundRows = ' SQL_CALC_FOUND_ROWS ';
2✔
1293

1294
        return $this;
2✔
1295
    }
1296

1297
    /**
1298
     * Defines SQL UNION
1299
     * 
1300
     * @param string $table = NULL
1301
     * 
1302
     * @return DB
1303
     */
1304
    public function union(string $table = NULL, $name = 'UNION') : DB
1305
    {
1306
        $this->unionQuery .= $this->get($table, 'string') . ' ' . $name;
2✔
1307

1308
        return $this;
2✔
1309
    }
1310

1311
    /**
1312
     * Defines SQL UNION ALL
1313
     * 
1314
     * @param string $table = NULL
1315
     * 
1316
     * @return DB
1317
     */
1318
    public function unionAll(string $table = NULL) : DB
1319
    {
1320
        $this->union($table, 'UNION ALL');
2✔
1321

1322
        return $this;
2✔
1323
    }
1324

1325
    /**
1326
     * Json columns decoder
1327
     * 
1328
     * @param variadic $columns
1329
     * 
1330
     * @return DB
1331
     */
1332
    public function jsonDecode(...$columns)
1333
    {
1334
        $this->jsonDecode = ! empty($columns) ? $columns : '*';
2✔
1335

1336
        return $this;
2✔
1337
    }
1338

1339
    /**
1340
     * Basic Query
1341
     * 
1342
     * @param string $query
1343
     * @param array  $secure = []
1344
     * 
1345
     * @return DB
1346
     */
1347
    public function query(string $query, array $secure = [])
1348
    {
1349
        $secure     = $this->secure ?: $secure; $this->secure     = [];    
356✔
1350
        $caching    = $this->caching;           $this->caching    = [];
356✔
1351
        $tableName  = $this->tableName;         $this->tableName  = '';
356✔
1352
        $jsonDecode = $this->jsonDecode;        $this->jsonDecode = [];
356✔
1353
        $paging     = $this->paging;            
356✔
1354

1355
        return (new self($this->config))->setQueryByDriver($query, $secure, 
356✔
1356
        [
1357
            'caching'    => $caching, 
356✔
1358
            'tableName'  => $tableName,
356✔
1359
            'jsonDecode' => $jsonDecode,
356✔
1360
            'paging'     => $paging
356✔
1361
        ]);
1362
    }
1363

1364
    /**
1365
     * Exec Basic Query
1366
     * 
1367
     * @param string $query
1368
     * @param array  $secure = []
1369
     * 
1370
     * @return bool
1371
     */
1372
    public function execQuery(string $query, array $secure = []) : bool
1373
    {
1374
        $this->secure = $this->secure ?: $secure;
4✔
1375

1376
        return $this->db->exec($this->querySecurity($query), $this->secure);
4✔
1377
    }
1378

1379
    /**
1380
     * Basic Query
1381
     * 
1382
     * @param string $query
1383
     * @param array  $secure = []
1384
     * 
1385
     * @return DB
1386
     */
1387
    public function basicQuery(string $query, array $secure = []) : DB
1388
    {
1389
        return $this->setQueryByDriver($query, $secure);
4✔
1390
    }
1391

1392
    /**
1393
     * Trans Query
1394
     * 
1395
     * @param string $query
1396
     * @param array  $secure = []
1397
     * 
1398
     * @return DB
1399
     */
1400
    public function transQuery(string $query, array $secure = []) : DB
1401
    {
1402
        return $this->setQueryByDriver($query, $secure);
10✔
1403
    }
1404

1405
    /**
1406
     * Multi Query
1407
     * 
1408
     * @param string $query
1409
     * @param array  $secure = []
1410
     * 
1411
     * @return bool
1412
     */
1413
    public function multiQuery(string $query, array $secure = []) : bool
1414
    {
1415
        $this->secure = $this->secure ?: $secure;
6✔
1416

1417
        return $this->db->multiQuery($this->querySecurity($query), $this->secure);
6✔
1418
    }
1419

1420
    /**
1421
     * Start transaction query
1422
     * 
1423
     * @return DB
1424
     */
1425
    public function transStart() : DB
1426
    {
1427
        $this->transStart = $this->db->transStart();
10✔
1428

1429
        $this->transaction = true;
10✔
1430

1431
        return $this;
10✔
1432
    }
1433

1434
    /**
1435
     * End transaction query
1436
     * 
1437
     * @return bool
1438
     */
1439
    public function transEnd()
1440
    {
1441
        $this->runTransactionQueries();
10✔
1442

1443
        if( ! empty($this->transError) )
10✔
1444
        {
1445
            $this->db->transRollback();
6✔
1446
        }
1447
        else
1448
        {
1449
            $this->db->transCommit();
8✔
1450
        }
1451

1452
        $status = ! (bool) $this->transError;
10✔
1453

1454
        $this->resetTransactionQueryVariables();
10✔
1455

1456
        return $status;
10✔
1457
    }
1458

1459
    /**
1460
     * Transaction queryies builder
1461
     * 
1462
     * @param callback $callback
1463
     * 
1464
     * @return bool
1465
     */
1466
    public function transaction($callback) : bool
1467
    {
1468
        $this->transStart();
4✔
1469

1470
        $this->transaction = true;
4✔
1471

1472
        $callback();
4✔
1473

1474
        $this->runTransactionQueries();
4✔
1475

1476
        return $this->transEnd();
4✔
1477
    }
1478

1479
    /**
1480
     * Get Insert ID
1481
     * 
1482
     * @return int|string
1483
     */
1484
    public function insertID()
1485
    {
1486
        return $this->db->insertId();
12✔
1487
    }
1488

1489
    /**
1490
     * Set postgres driver returning id
1491
     * 
1492
     * @param string $returningId
1493
     * 
1494
     * @return self
1495
     */
1496
    public function returningId(string $returningId)
1497
    {
1498
        Properties::$returningId = $returningId;
2✔
1499

1500
        return $this;
2✔
1501
    }
1502

1503
    /**
1504
     * Get table status
1505
     * 
1506
     * @param string $table = NULL
1507
     * 
1508
     * @return DB
1509
     */
1510
    public function status(string $table = NULL) : DB
1511
    {
1512
        $table = Base::presuffix($this->addPrefixForTableAndColumn($table), "'");
6✔
1513

1514
        $query = "SHOW TABLE STATUS FROM " . $this->config['database'] . " LIKE $table";
6✔
1515

1516
        $this->runQuery($query);
6✔
1517

1518
        return $this;
6✔
1519
    }
1520

1521
    /**
1522
     * Increment
1523
     * 
1524
     * @param string $table     = NULL
1525
     * @param mixed  $columns   = []
1526
     * @param int    $increment = 1
1527
     * 
1528
     * @return bool
1529
     */
1530
    public function increment(string $table = NULL, $columns = [], int $increment = 1)
1531
    {
1532
        return $this->setIncrementDecrement($table, $columns, $increment, 'increment');
6✔
1533
    }
1534

1535
    /**
1536
     * Decrement
1537
     * 
1538
     * @param string $table     = NULL
1539
     * @param mixed  $columns   = []
1540
     * @param int    $decrement = 1
1541
     * 
1542
     * @return bool
1543
     */
1544
    public function decrement(string $table = NULL, $columns = [], int $decrement = 1)
1545
    {
1546
        return $this->setIncrementDecrement($table, $columns, $decrement, 'decrement');
6✔
1547
    }
1548

1549
    /**
1550
     * Insert CSV
1551
     * 
1552
     * @param string $table
1553
     * @param string $file
1554
     * 
1555
     * @return bool
1556
     */
1557
    public function insertCSV(string $table, string $file) : bool
1558
    {
1559
        $this->convertCSVData($file);
4✔
1560
        
1561
        array_map(function($data) use($table)
1562
        {
1563
            $this->duplicateCheck()->insert(Base::prefix($table, 'ignore:'), $data);
4✔
1564
            
1565
        }, $file);
4✔
1566
        
1567
        return true;
4✔
1568
    }
1569

1570
    /**
1571
     * Insert 
1572
     * 
1573
     * @param string $table = NULL
1574
     * @param array  $datas = []
1575
     * 
1576
     * @return bool
1577
     */
1578
    public function insert(string $table = NULL, array $datas = [])
1579
    {
1580
        if( isset($datas[0]) && is_array($datas[0]) )
136✔
1581
        {
1582
            $insertQuery = $this->multiInsert($table, $datas);
2✔
1583
        }
1584
        else
1585
        {
1586
            $this->isHashIdColumn($datas);
136✔
1587

1588
            $this->ignoreData($table, $datas);
136✔
1589

1590
            $datas = $this->addPrefixForTableAndColumn($datas, 'column');
136✔
1591
            
1592
            $this->buildDataValuesQueryForInsert($datas, $data, $values, $duplicateCheckWhere);
136✔
1593
            
1594
            $this->duplicateCheckProcess($duplicateCheckWhere, $table, $datas, $return);
136✔
1595

1596
            if( isset($return) )
136✔
1597
            {
1598
                return $return;
28✔
1599
            }
1600
    
1601
            $insertQuery = $this->buildInsertQuery($table, $data, $values);
108✔
1602
        }
1603
        
1604
        $this->resetInsertQueryVariables();
108✔
1605

1606
        if( $return = $this->runQuery($insertQuery) )
108✔
1607
        {
1608
            if( is_string($this->object) )
82✔
1609
            {
1610
                Properties::$returningId = $processColumn = $this->object; $this->object = NULL;
4✔
1611

1612
                $insertId = $this->insertId(); Properties::$returningId = 'id';
4✔
1613

1614
                return $this->where($processColumn, $insertId)->get($table)->row();
4✔
1615
            }
1616
        }
1617

1618
        return $return;
104✔
1619
    }
1620

1621
    /**
1622
     * Object
1623
     * 
1624
     * @param string $processColumn = 'id'
1625
     * 
1626
     * @return self
1627
     */
1628
    public function object(string $processColumn = 'id')
1629
    {
1630
        $this->object = $processColumn;
6✔
1631

1632
        return $this;
6✔
1633
    }
1634

1635
    /**
1636
     * Unset
1637
     * 
1638
     * @param variadic ...$argument
1639
     * 
1640
     * @return self
1641
     */
1642
    public function unset(...$columns)
1643
    {
1644
        $this->unset = $columns;
2✔
1645

1646
        return $this;
2✔
1647
    }
1648

1649
    /**
1650
     * Is update
1651
     *
1652
     * @return boolean
1653
     */
1654
    public function isUpdate() : bool
1655
    {
1656
        return $this->isUpdate;
2✔
1657
    }
1658

1659
    /**
1660
     * Set hash id column
1661
     * 
1662
     * @param string $column
1663
     * 
1664
     * @return self
1665
     */
1666
    public function hashIdColumn(string $column)
1667
    {
1668
        $this->hashIdColumn = $column;
2✔
1669

1670
        return $this;
2✔
1671
    }
1672

1673
    /**
1674
     * Create hash id
1675
     * 
1676
     * @param array $data
1677
     * 
1678
     * @return string
1679
     */
1680
    public function createHashId(array $data) : string
1681
    {
1682
        $output = '';
2✔
1683

1684
        foreach( $data as $value )
2✔
1685
        {
1686
            $output .= json_encode($value);
2✔
1687
        }
1688

1689
        $output .= microtime();
2✔
1690

1691
        return md5($output);
2✔
1692
    }
1693

1694
    /**
1695
     * Get hash Id 
1696
     * 
1697
     * @return string
1698
     */
1699
    public function hashId()
1700
    {
1701
        return $this->hashId;
2✔
1702
    }
1703

1704
    /**
1705
     * Update 
1706
     * 
1707
     * @param string $table = NULL
1708
     * @param array  $datas = []
1709
     * 
1710
     * @return bool
1711
     */
1712
    public function update(string $table = NULL, array $datas = [])
1713
    {
1714
        $this->ignoreData($table, $datas);
44✔
1715

1716
        $datas = $this->addPrefixForTableAndColumn($datas, 'column');
44✔
1717
        
1718
        $this->buildDataValuesQueryForUpdate($datas, $data);
44✔
1719

1720
        $updateQuery = $this->buildUpdateQuery($table, $data, $where);
44✔
1721

1722
        $this->resetUpdateQueryVariables();
44✔
1723

1724
        if( $return = $this->runQuery($updateQuery) )
44✔
1725
        {
1726
            if( $this->object )
32✔
1727
            {
1728
                $this->object = NULL;
2✔
1729

1730
                return $this->where('exp:' . str_ireplace('WHERE ', '', $where))->get($table)->row(-1);
2✔
1731
            }
1732
        }
1733

1734
        return $return;
42✔
1735
    }
1736

1737
    /**
1738
     * Delete 
1739
     * 
1740
     * @param string $table = NULL
1741
     * 
1742
     * @return bool
1743
     */
1744
    public function delete(string $table = NULL)
1745
    {
1746
        if( empty($this->where) )
80✔
1747
        {
1748
            throw new UnconditionalException();
2✔
1749
        }
1750

1751
        $deleteQuery = $this->buildDeleteQuery($table);
78✔
1752

1753
        $this->resetDeleteQueryVariables();
78✔
1754

1755
        return $this->runQuery($deleteQuery);
78✔
1756
    }
1757

1758
    /**
1759
     * Get total rows
1760
     * 
1761
     * @param bool $real = false
1762
     * 
1763
     * @return int
1764
     */
1765
    public function totalRows(bool $total = false) : int
1766
    {
1767
        if( $total === true )
80✔
1768
        {
1769
            return $this->query($this->db->cleanLimit($this->stringQuery()))->totalRows();
10✔
1770
        }
1771

1772
        return $this->db->numRows();
80✔
1773
    }
1774

1775
    /**
1776
     * Get total columns
1777
     * 
1778
     * @return int
1779
     */
1780
    public function totalColumns() : int
1781
    {
1782
        return $this->db->numFields();
8✔
1783
    }
1784

1785
    /**
1786
     * Get columns
1787
     * 
1788
     * @return array
1789
     */
1790
    public function columns() : array
1791
    {
1792
        return $this->db->columns();
44✔
1793
    }
1794

1795
    /**
1796
     * Get table result
1797
     * 
1798
     * @param string $type = 'objects' - Options[object|array|json]
1799
     * 
1800
     * @return mixed
1801
     */
1802
    public function result(string $type = 'object', $usageRow = false)
1803
    {
1804
        $this->getCacheResult($type, $results);
222✔
1805

1806
        if( empty($results) )
222✔
1807
        {
1808
            $results = $this->results = ($this->results ?? $this->db->result($type, $this->jsonDecode ?? NULL, $usageRow));
220✔
1809
        }
1810

1811
        if( $type === 'json' )
222✔
1812
        {
1813
            return Json::encode($results);
2✔
1814
        }
1815

1816
        return $results;
220✔
1817
    }
1818

1819
    /**
1820
     * Get result json
1821
     * 
1822
     * @return string
1823
     */
1824
    public function resultJson() : string
1825
    {
1826
        return $this->result('json');
2✔
1827
    }
1828

1829
    /**
1830
     * Get result array
1831
     * 
1832
     * @return array
1833
     */
1834
    public function resultArray() : array
1835
    {
1836
        return $this->result('array');
6✔
1837
    }
1838

1839
    /**
1840
     * Get fetch array
1841
     * 
1842
     * @return array
1843
     */
1844
    public function fetchArray() : array
1845
    {
1846
        return $this->db->fetchArray();
6✔
1847
    }
1848

1849
    /**
1850
     * Get fetch assoc
1851
     * 
1852
     * @return array
1853
     */
1854
    public function fetchAssoc() : array
1855
    {
1856
        return $this->db->fetchAssoc();
6✔
1857
    }
1858

1859
    /**
1860
     * Get fetch array
1861
     * 
1862
     * @param string $type = 'assoc' - Options[assoc|array|row]
1863
     * 
1864
     * @return array
1865
     */
1866
    public function fetch(string $type = 'assoc') : array
1867
    {
1868
        if( $type === 'assoc' )
2✔
1869
        {
1870
            return $this->db->fetchAssoc();
2✔
1871
        }
1872
        elseif( $type === 'array')
2✔
1873
        {
1874
            return $this->db->fetchArray();
2✔
1875
        }
1876
        else
1877
        {
1878
            return $this->db->fetchRow();
2✔
1879
        }
1880
    }
1881

1882
    /**
1883
     * Get fetch row
1884
     * 
1885
     * @param bool $printable = false
1886
     * 
1887
     * @return mixed
1888
     */
1889
    public function fetchRow(bool $printable = false)
1890
    {
1891
        $row = $this->db->fetchRow();
8✔
1892

1893
        if( $printable === false )
8✔
1894
        {
1895
            return $row;
8✔
1896
        }
1897
        else
1898
        {
1899
            return current((array) $row);
2✔
1900
        }
1901
    }
1902

1903
    /**
1904
     * Get table row
1905
     * 
1906
     * @param mixed $printable = 0
1907
     * 
1908
     * @return mixed
1909
     */
1910
    public function row($printable = 0)
1911
    {
1912
        $result = $this->result('object', true);
160✔
1913

1914
        if( $printable < 0 )
160✔
1915
        {
1916
            $index = count($result) + $printable;
4✔
1917

1918
            return isset($result[$index]) ? (object) $result[$index] : false;
4✔
1919
        }
1920
        else
1921
        {
1922
            if( $printable === true )
156✔
1923
            {
1924
                $resultObject = new ArrayObject($result[0] ?? []);
48✔
1925

1926
                return $resultObject->getIterator()->current();
48✔
1927
            }
1928

1929
            return isset($result[$printable]) ? (object) $result[$printable] : false;
126✔
1930
        }
1931
    }
1932

1933
    /**
1934
     * Get table column value
1935
     * 
1936
     * @param string $column = NULL - added 5.6.5
1937
     * 
1938
     * @return string
1939
     */
1940
    public function value(string $column = NULL)
1941
    {
1942
        if( preg_match('/[a-z]\w+/i', $column ?? '') )
48✔
1943
        {
1944
            return $this->row()->$column ?? false;
2✔
1945
        }
1946

1947
        return $this->row(true);
46✔
1948
    }
1949

1950
    /**
1951
     * Get affected rows
1952
     * 
1953
     * @return int
1954
     */
1955
    public function affectedRows() : int
1956
    {
1957
        return $this->db->affectedRows();
6✔
1958
    }
1959

1960
    /**
1961
     * Column Data
1962
     * 
1963
     * @param string $column = NULL
1964
     * 
1965
     * @return array
1966
     */
1967
    public function columnData(string $column = NULL)
1968
    {
1969
        return $this->db->columnData($column);
10✔
1970
    }
1971

1972
    /**
1973
     * Table Name
1974
     * 
1975
     * @return string
1976
     */
1977
    public function tableName() : string
1978
    {
1979
        return $this->tableName;
2✔
1980
    }
1981

1982
    /**
1983
     * Pagination
1984
     * 
1985
     * @param string $url      = NULL
1986
     * @param array  $settings = []
1987
     * @param bool   $output   = true
1988
     * 
1989
     * @return string
1990
     */
1991
    public function pagination(string $url = NULL, array $settings = [], bool $output = true)
1992
    {
1993
        $pagcon   = Config::get('ViewObjects', 'pagination');
8✔
1994
        $getLimit = $this->db->getLimitValues($this->stringQuery());
8✔
1995
        $start    = $getLimit['start'] ?? NULL;
8✔
1996
        $limit    = $getLimit['limit'] ?? NULL;
8✔
1997

1998
        $settings['totalRows'] = $this->totalRows(true);
8✔
1999
        $settings['limit']     = ! empty($limit) ? $limit : $pagcon['limit'];
8✔
2000
        $settings['start']     = $start ?? $pagcon['start'];
8✔
2001
        $settings['paging']    = $this->paging;
8✔
2002

2003
        if( $settings['paging'] === 'page' )
8✔
2004
        {
2005
            $settings['start'] = floor($settings['start'] / $settings['limit'] + 1);
4✔
2006
        }
2007

2008
        if( ! empty($url) )
8✔
2009
        {
2010
            $settings['url'] = $url; // @codeCoverageIgnore
2011
        }
2012

2013
        $return = $output === true
8✔
2014
                ? Singleton::class('ZN\Pagination\Paginator')->create(NULL, $settings)
8✔
2015
                : $settings;
8✔
2016

2017
        return $return;
8✔
2018
    }
2019

2020
    /**
2021
     * Is Exists
2022
     * 
2023
     * @param string $table
2024
     * @param string $column
2025
     * @param string $value
2026
     * 
2027
     * @param bool
2028
     */
2029
    public function isExists(string $table, string $column, string $value) : bool
2030
    {
2031
        return (bool) $this->where($column, $value)->get($table)->totalRows();
6✔
2032
    }
2033

2034
    /**
2035
     * Simple Result
2036
     * 
2037
     * @param string $table
2038
     * @param string $column = NULL
2039
     * @param string $value  = NULL
2040
     * 
2041
     * @return object
2042
     */
2043
    public function simpleResult(string $table, string $column = NULL, $value = NULL, $type = 'result')
2044
    {
2045
        if( $column !== NULL && $value !== NULL )
12✔
2046
        {
2047
            $this->where($column, $value);
6✔
2048
        }
2049

2050
        return $this->get($table)->$type();
12✔
2051
    }
2052

2053
    /**
2054
     * Simple Result Array
2055
     * 
2056
     * @param string $table
2057
     * @param string $column = NULL
2058
     * @param string $value  = NULL
2059
     * 
2060
     * @return array
2061
     */
2062
    public function simpleResultArray(string $table, string $column = NULL, $value = NULL)
2063
    {
2064
        return $this->simpleResult($table, $column, $value, 'resultArray');
2✔
2065
    }
2066

2067
    /**
2068
     * Simple Row
2069
     * 
2070
     * @param string $table
2071
     * @param string $column = NULL
2072
     * @param string $value  = NULLL
2073
     * 
2074
     * @return object
2075
     */
2076
    public function simpleRow(string $table, string $column = NULL, $value = NULL)
2077
    {
2078
        return $this->simpleResult($table, $column, $value, 'row');
2✔
2079
    }
2080

2081
    /**
2082
     * Simple Total Rows
2083
     * 
2084
     * @param string $table
2085
     * 
2086
     * @return int
2087
     */
2088
    public function simpleTotalRows(string $table) : int
2089
    {
2090
        return $this->simpleResult($table, NULL, NULL, 'totalRows');
2✔
2091
    }
2092

2093
    /**
2094
     * Simple Total Columns
2095
     * 
2096
     * @param string $table 
2097
     * 
2098
     * @return int
2099
     */
2100
    public function simpleTotalColumns(string $table) : int
2101
    {
2102
        return $this->simpleResult($table, NULL, NULL, 'totalColumns');
2✔
2103
    }
2104

2105
    /**
2106
     * Simple Columns
2107
     * 
2108
     * @param string $table
2109
     * 
2110
     * @return array
2111
     */
2112
    public function simpleColumns(string $table) : array
2113
    {
2114
        return $this->simpleResult($table, NULL, NULL, 'columns');
2✔
2115
    }
2116

2117
    /**
2118
     * Simple Column Data
2119
     * 
2120
     * @param string $table
2121
     * @param string $column
2122
     * 
2123
     * @return stdClass
2124
     */
2125
    public function simpleColumnData(string $table, string $column = NULL) : \stdClass
2126
    {
2127
        return $this->get($table)->columnData($column);
2✔
2128
    }
2129

2130
    /**
2131
     * Simple Update
2132
     * 
2133
     * @param string $table
2134
     * @param string $data
2135
     * @param string $column
2136
     * @param string $value
2137
     * 
2138
     * @return bool
2139
     */
2140
    public function simpleUpdate(string $table, array $data, string $column, string $value)
2141
    {
2142
        return $this->where($column, $value)->update($table, $data);
2✔
2143
    }
2144

2145
    /**
2146
     * Simple Delete
2147
     * 
2148
     * @param string $table
2149
     * @param string $column
2150
     * @param string $value
2151
     * 
2152
     * @return bool
2153
     */
2154
    public function simpleDelete(string $table, string $column, string $value)
2155
    {
2156
        return $this->where($column, $value)->delete($table);
2✔
2157
    }
2158

2159
    /**
2160
     * Switch Case
2161
     * 
2162
     * @param string $switch
2163
     * @param array  $conditions = []
2164
     * @param bool   $return     = false
2165
     * 
2166
     * @return mixed
2167
     */
2168
    public function switchCase(string $switch, array $conditions = [], bool $return = false)
2169
    {
2170
        $case  = ' CASE '.$switch;
4✔
2171

2172
        $alias = '';
4✔
2173

2174
        if( isset($conditions['as']) )
4✔
2175
        {
2176
            $alias = ' as ' . $conditions['as'] . ' ';
2✔
2177

2178
            unset($conditions['as']);
2✔
2179
        }
2180

2181
        if( is_array($conditions) ) foreach( $conditions as $key => $val )
4✔
2182
        {
2183
            if( strtolower($key) === 'default' || strtolower($key) === 'else' )
2✔
2184
            {
2185
                $key = ' ELSE ';
2✔
2186
            }
2187
            else
2188
            {
2189
                $key = ' WHEN ' . $key . ' THEN ';
2✔
2190
            }
2191

2192
            $case .= $key . $val;
2✔
2193
        }
2194

2195
        $case .= ' END ' . $alias;
4✔
2196

2197
        if( $return === true )
4✔
2198
        {
2199
            return $case;
2✔
2200
        }
2201
        else
2202
        {
2203
            $this->selectFunctions[] = $case;
2✔
2204

2205
            return $this;
2✔
2206
        }
2207
    }
2208

2209
    /**
2210
     * Vartype
2211
     * 
2212
     * @param mixed  $type
2213
     * @param string $len    = NULL
2214
     * @param bool   $output = true
2215
     * 
2216
     * @return string
2217
     */
2218
    public function vartype(string $type, int $len = NULL, bool $output = true) : string
2219
    {
2220
        return $this->db->variableTypes($type, $len, $output);
2✔
2221
    }
2222

2223
    /**
2224
     * Property
2225
     * 
2226
     * @param mixed  $type
2227
     * @param string $col    = NULL
2228
     * @param bool   $output = true
2229
     * 
2230
     * @return string
2231
     */
2232
    public function property($type, string $col = NULL, bool $output = true) : string
2233
    {
2234
        if( is_array($type) )
2✔
2235
        {
2236
            $state = '';
2✔
2237

2238
            foreach( $type as $key => $val )
2✔
2239
            {
2240
                if( ! is_numeric($key) )
2✔
2241
                {
2242
                    $state .= $this->db->statements($key, $val);
2✔
2243
                }
2244
                else
2245
                {
2246
                    $state .= $this->db->statements($val);
2✔
2247
                }
2248
            }
2249

2250
            return $state;
2✔
2251
        }
2252
        else
2253
        {
2254
            return $this->db->statements($type, $col, $output);
2✔
2255
        }
2256
    }
2257

2258
    /**
2259
     * Defines SQL DEFAULT
2260
     * 
2261
     * @param string $default = NULL
2262
     * @param string $bool    = false
2263
     * 
2264
     * @return string
2265
     */
2266
    public function defaultValue(string $default = NULL, bool $type = false) : string
2267
    {
2268
        if( ! is_numeric($default) )
2✔
2269
        {
2270
            $default = Base::presuffix($default, '"');
2✔
2271
        }
2272

2273
        return $this->db->statements('default', $default, $type);
2✔
2274
    }
2275

2276
    /**
2277
     * Defines SQL LIKE Operators
2278
     * 
2279
     * @param string $value
2280
     * @param string $type = 'starting' - Options[starting|ending|inside]
2281
     * 
2282
     * @return string
2283
     */
2284
    public function like(string $value, string $type = 'starting') : string
2285
    {
2286
        $operator = $this->db->operator(__FUNCTION__);
10✔
2287

2288
        if( $type === "inside" )
10✔
2289
        {
2290
            $value = $operator.$value.$operator;
2✔
2291
        }
2292

2293
        // İle Başlayan
2294
        if( $type === "starting" )
10✔
2295
        {
2296
            $value = $value.$operator;
4✔
2297
        }
2298

2299
        // İle Biten
2300
        if( $type === "ending" )
10✔
2301
        {
2302
            $value = $operator.$value;
4✔
2303
        }
2304

2305
        return $value;
10✔
2306
    }
2307

2308
    /**
2309
     * Defines SQL BETWEEN
2310
     * 
2311
     * @param string $value1
2312
     * @param string $value2
2313
     * 
2314
     * @return string
2315
     */
2316
    public function between(string $value1, string $value2) : string
2317
    {
2318
        return $this->escapeStringAddNail($value1, true).' AND '.$this->escapeStringAddNail($value2, true);
2✔
2319
    }
2320

2321
    /**
2322
     * Defines SQL NOT IN
2323
     * 
2324
     * @param string ...$value 
2325
     * 
2326
     * @return string
2327
     */
2328
    public function notIn(...$value) : string
2329
    {
2330
        return $this->buildInClause('in', ...$value);
2✔
2331
    }
2332

2333
    /**
2334
     * Defines SQL IN
2335
     * 
2336
     * @param string ...$value 
2337
     * 
2338
     * @return string
2339
     */
2340
    public function in(...$value) : string
2341
    {
2342
        return $this->buildInClause(__FUNCTION__, ...$value);
2✔
2343
    }
2344

2345
    /**
2346
     * protected IN Table
2347
     * 
2348
     * @param string ...$value 
2349
     * 
2350
     * @return string
2351
     */
2352
    public function inTable(...$value) : string
2353
    {
2354
        return $this->buildInClause(__FUNCTION__, ...$value);
2✔
2355
    }
2356

2357
    /**
2358
     * protected IN Query
2359
     * 
2360
     * @param string ...$value 
2361
     * 
2362
     * @return string
2363
     */
2364
    public function inQuery(...$value) : string
2365
    {
2366
        return $this->buildInClause(__FUNCTION__, ...$value);
2✔
2367
    }
2368

2369
    /**
2370
     * protected is hash id column
2371
     */
2372
    protected function isHashIdColumn(&$datas)
2373
    {
2374
        $this->hashId = NULL;
136✔
2375

2376
        if( $this->hashIdColumn )
136✔
2377
        {
2378
            $this->hashId = $datas[$this->hashIdColumn] = $this->createHashId($datas);
2✔
2379

2380
            $this->hashIdColumn = NULL;
2✔
2381
        }
2382
    }
136✔
2383

2384
    /**
2385
     * protected build insert query
2386
     */
2387
    protected function buildInsertQuery($table, $data, $values)
2388
    {
2389
        return 'INSERT '.
2390
                $this->lowPriority.
108✔
2391
                $this->delayed.
108✔
2392
                $this->highPriority.
108✔
2393
                $this->ignore.
108✔
2394
                ' INTO '.
108✔
2395
                $this->addPrefixForTableAndColumn($table).
108✔
2396
                $this->partition.
108✔
2397
                $this->buildInsertValuesClause($data, $values) . 
108✔
2398
                $this->db->getInsertExtrasByDriver();
108✔
2399
    }
2400

2401
    /**
2402
     * protected duplicate check process
2403
     */
2404
    protected function duplicateCheckProcess($duplicateCheckWhere, $table, $datas, &$return = NULL)
2405
    {
2406
        $this->isUpdate = false;
136✔
2407
        
2408
        if( ! empty($duplicateCheckWhere) && $this->where($duplicateCheckWhere)->count('*')->get($table)->value() )
136✔
2409
        {
2410
            $this->duplicateCheck = NULL; $return = false;
28✔
2411

2412
            if( $this->duplicateCheckUpdate === true )
28✔
2413
            {
2414
                $this->duplicateCheckUpdate = NULL;
4✔
2415

2416
                $this->isUpdate = true;
4✔
2417

2418
                $return = $this->where($duplicateCheckWhere)->update($table, $datas);
4✔
2419
            }
2420
        }
2421
    }
136✔
2422

2423
    /**
2424
     * protected build data values query
2425
     */
2426
    protected function buildDataValuesQueryForInsert($datas, &$data, &$values, &$duplicateCheckWhere)
2427
    {
2428
        $data = ''; $values = ''; $duplicateCheckWhere = [];
136✔
2429
    
2430
        foreach( $datas as $key => $value )
136✔
2431
        {
2432
            if( $this->isExpressionExists($key) )
132✔
2433
            {
2434
                $key = $this->clearExpression($key); $isExp = true;
2✔
2435
            }
2436

2437
            $this->isNonscalarValueEncodeJson($value);
132✔
2438

2439
            $data .= Base::suffix($key, ',');
132✔
2440
            
2441
            if( ! empty($this->duplicateCheck) && ($this->duplicateCheck[0] === '*' || in_array($key, $this->duplicateCheck)) )
132✔
2442
            {
2443
                $duplicateCheckWhere[] = [$key . ' = ', $value, 'and'];
36✔
2444
            }
2445

2446
            $value = $this->nailEncode($value);
132✔
2447

2448
            if( isset($isExp) )
132✔
2449
            {
2450
                $values .= Base::suffix($value, ','); unset($isExp);
2✔
2451
            }
2452
            else
2453
            {
2454
                $values .= Base::suffix(Base::presuffix($value, "'"), ',');
130✔
2455
            }
2456
        }
2457
    }
136✔
2458

2459
    /**
2460
     * protected multi insert
2461
     */
2462
    protected function multiInsert($table, $datas)
2463
    {
2464
        $data  = $datas[0]; unset($datas[0]);
2✔
2465

2466
        $query = $this->string()->insert($table, $data);
2✔
2467
        
2468
        foreach( $datas as $values )
2✔
2469
        {
2470
            $value = '';
2✔
2471

2472
            foreach( $values as $val )
2✔
2473
            {
2474
                $value .= Base::suffix(Base::presuffix($this->nailEncode($val), "'"), ',');
2✔
2475
            }
2476

2477
            $query .= ', (' . rtrim($value, ',') . ')';
2✔
2478
        } 
2479

2480
        return Base::suffix($query, ';');
2✔
2481
    }
2482

2483
    /**
2484
     * protected build data values query for update
2485
     */
2486
    protected function buildDataValuesQueryForUpdate($datas, &$data)
2487
    {
2488
        $data = '';
44✔
2489
        
2490
        foreach( $datas as $key => $value )
44✔
2491
        {
2492
            $this->isNonscalarValueEncodeJson($value);
44✔
2493

2494
            $value = $this->nailEncode($value);
44✔
2495

2496
            if( $this->isExpressionExists($key) )
44✔
2497
            {
2498
                $key = $this->clearExpression($key); // @codeCoverageIgnore
2499
            }
2500
            else
2501
            {
2502
                $value = Base::presuffix($value, "'");
44✔
2503
            }
2504

2505
            $data .= $key . '=' . Base::suffix($value, ',');
44✔
2506
        }
2507
    }
44✔
2508

2509
    /**
2510
     * protected build update query
2511
     */
2512
    protected function buildUpdateQuery($table, $data, &$where = NULL)
2513
    {
2514
        $where = $this->buildWhereClause();
44✔
2515

2516
        return 'UPDATE '.
2517
                $this->lowPriority.
44✔
2518
                $this->ignore.
44✔
2519
                $this->addPrefixForTableAndColumn($table).
44✔
2520
                $this->join.
44✔
2521
                ' SET ' . substr($data, 0, -1) .
44✔
2522
                $where.
44✔
2523
                $this->buildOrderByClause().
44✔
2524
                $this->limit . 
44✔
2525
                $this->db->getInsertExtrasByDriver();
44✔
2526
    }
2527

2528
    /**
2529
     * protected build delete query
2530
     */
2531
    protected function buildDeleteQuery($table)
2532
    {
2533
        return 'DELETE '.
2534
                $this->lowPriority.
78✔
2535
                $this->quick.
78✔
2536
                $this->ignore.
78✔
2537
                $this->deleteJoinTables($table).
78✔
2538
                ' FROM '.
78✔
2539
                $this->addPrefixForTableAndColumn($table).
78✔
2540
                $this->join.
78✔
2541
                $this->partition.
78✔
2542
                $this->buildWhereClause().
78✔
2543
                $this->buildOrderByClause().
78✔
2544
                $this->limit;
78✔
2545
    }
2546

2547
    /**
2548
     * protected run transaction queries
2549
     */
2550
    protected function runTransactionQueries()
2551
    {
2552
        if( $this->transactionQueries )
10✔
2553
        {
2554
            foreach( $this->transactionQueries as $query )
10✔
2555
            {
2556
                $this->transQuery($query);
10✔
2557
            }
2558
        }
2559
    }
10✔
2560

2561
    /**
2562
     * protected special defined where
2563
     */
2564
    protected function specialDefinedWhere($column, $value = NULL, string $logical = NULL, $type = 'whereJson')
2565
    {
2566
        $this->where('exp:' . $this->db->$type($column, $this->escapeStringAddNail((string) $value)), '', $logical, 'where');
4✔
2567
    }
4✔
2568

2569
    /**
2570
     * protected IN
2571
     * 
2572
     * @param string    $type = 'in'
2573
     * @param string ...$value 
2574
     * 
2575
     * @return string
2576
     */
2577
    protected function buildInClause($type = 'in', ...$value)
2578
    {
2579
        $query = '(';
8✔
2580
        $type  = strtolower($type);
8✔
2581

2582
        foreach( $value as $val )
8✔
2583
        {
2584
            if( $type === 'in' )
8✔
2585
            {
2586
                $query .= $this->escapeStringAddNail($val, true);
4✔
2587
            }
2588
            elseif( $type === 'intable' )
4✔
2589
            {
2590
                $query .= $this->getString($val);
2✔
2591
            }
2592
            else
2593
            {
2594
                $query .= $val;
2✔
2595
            }
2596

2597
            $query .= ',';
8✔
2598
        }
2599

2600
        return rtrim($query, ',') . ')';
8✔
2601
    }
2602

2603
    /**
2604
     * protected is nonscalar value encode json
2605
     */
2606
    protected function isNonscalarValueEncodeJson(&$value)
2607
    {
2608
        if( ! is_scalar($value) )
152✔
2609
        {
2610
            $value = Json::encode($value);
4✔
2611
        }
2612
    }
152✔
2613

2614
    /**
2615
     * protected Select
2616
     * 
2617
     * @return string
2618
     */
2619
    protected function buildSelectClause()
2620
    {
2621
        if( ! empty($this->selectFunctions) )
408✔
2622
        {
2623
            $selectFunctions = rtrim(implode(',', $this->selectFunctions), ',');
40✔
2624

2625
            if( empty($this->select) )
40✔
2626
            {
2627
                $this->select = $selectFunctions;
40✔
2628
            }
2629
            else
2630
            {
2631
                $this->select .= ',' . $selectFunctions; // @codeCoverageIgnore
2632
            }
2633
        }
2634

2635
        if( empty($this->select) )
408✔
2636
        {
2637
            $this->select = ' * ';
366✔
2638
        }
2639

2640
        return $this->select;
408✔
2641
    }
2642

2643
    /**
2644
     * protected Values
2645
     * 
2646
     * @param string $data
2647
     * @param string $values
2648
     * 
2649
     * @return string
2650
     */
2651
    protected function buildInsertValuesClause($data, $values)
2652
    {
2653
        return ' ('.rtrim($data, ',').') VALUES ('.rtrim($values, ',').')';
108✔
2654
    }
2655

2656
    /**
2657
     * protected Result Cache
2658
     * 
2659
     * @param string $type
2660
     */
2661
    protected function getCacheResult($type, &$results = [])
2662
    {
2663
        if( ! empty($this->caching) )
222✔
2664
        {
2665
            $driver = $this->caching['driver'] ?? 'file';
2✔
2666

2667
            $cache = Singleton::class('ZN\Cache\Processor');
2✔
2668

2669
            if( $cacheResult = $cache->driver($driver)->select($this->getEncryptedCacheQuery()) )
2✔
2670
            {
2671
                $results = $cacheResult; // @codeCoverageIgnore
2672
            }
2673
            else
2674
            {
2675
                $cache->driver($driver)->insert($this->getEncryptedCacheQuery(), $results = $this->db->result($type), $this->caching['time'] ?? 0);
2✔
2676
            }
2677
        }
2678
    }
222✔
2679

2680
    /**
2681
     * protected Ignore Data
2682
     * 
2683
     * @param string & $table
2684
     * @param string & $data
2685
     */
2686
    protected function ignoreData(&$table, &$data)
2687
    {
2688
        $table = $table ?? '';
156✔
2689
        
2690
        $methods = ['ignore', 'post', 'get', 'request'];        
156✔
2691

2692
        if( stristr($table, ':') )
156✔
2693
        {
2694
            $tableEx = explode(':', $table);
22✔
2695
            $method  = $tableEx[0];
22✔
2696
            $table   = $tableEx[1];
22✔
2697

2698
            if( in_array($method, $methods) )
22✔
2699
            {
2700
                if( $method !== 'ignore' )
22✔
2701
                {
2702
                    $data = Method::$method();
16✔
2703
                }
2704

2705
                $columns = array_flip($this->setQueryByDriver('SELECT * FROM ' . $table . ' LIMIT 1')->columns());
22✔
2706
                $data    = array_intersect_key($data, $columns);
22✔
2707

2708
                $this->unsetData($data);
22✔
2709
            }
2710
        }
2711
    }
156✔
2712

2713
    /**
2714
     * protected unset data
2715
     */
2716
    protected function unsetData(&$data)
2717
    {
2718
        # The ID column is removed by default.
2719
        if( $find = preg_grep('/(^(id)$)/i', array_keys($data)) )
22✔
2720
        {
2721
            $id = current($find); unset($data[$id]);
2✔
2722
        }
2723

2724
        # The columns you specified are removed.
2725
        if( ! empty($this->unset) )
22✔
2726
        {
2727
            foreach( $this->unset as $column )
2✔
2728
            {
2729
                unset($data[$column]);
2✔
2730
            }
2731

2732
            $this->unset = [];
2✔
2733
        }
2734
    }
22✔
2735

2736
    /**
2737
     * protected CSV
2738
     * 
2739
     * @param string & $data
2740
     */
2741
    protected function convertCSVData(&$data)
2742
    {
2743
        $csv       = Converter::CSVToArray($data);
4✔
2744
        $csvColumn = $csv[0];
4✔
2745

2746
        array_shift($csv);
4✔
2747

2748
        $csvDatas  = $csv;
4✔
2749
        $data      = array_map(function($d) use($csvColumn)
2750
        {
2751
            return array_combine($csvColumn, $d);
4✔
2752
        }, $csvDatas);
4✔
2753
    }
4✔
2754

2755
    /**
2756
     * protected Delete Join Tables
2757
     * 
2758
     * @param string $table
2759
     * 
2760
     * @return string
2761
     */
2762
    protected function deleteJoinTables($table)
2763
    {
2764
        if( $this->join )
78✔
2765
        {
2766
            $joinType = strtolower($this->joinType ?? '');
2✔
2767

2768
            if( $joinType === 'inner' )
2✔
2769
            {
2770
                $joinTables = $this->addPrefixForTableAndColumn($table) . ', ' . $this->joinTable; // @codeCoverageIgnore
2771
            }
2772
            elseif( $joinType === 'right' )
2✔
2773
            {
2774
                $joinTables = $this->joinTable; // @codeCoverageIgnore
2775
            }
2776
            else
2777
            {
2778
                $joinTables = $this->addPrefixForTableAndColumn($table);
2✔
2779
            }
2780

2781
            $this->joinType  = NULL;
2✔
2782
            $this->joinTable = NULL;
2✔
2783

2784
            return Base::presuffix($joinTables, ' ');
2✔
2785
        }
2786

2787
        return NULL;
76✔
2788
    }
2789

2790
    /**
2791
     * protected Where Key Control
2792
     * 
2793
     * @param string $column
2794
     * @param string $value
2795
     * 
2796
     * @return string
2797
     */
2798
    protected function whereKeyControl($column, $value)
2799
    {
2800
        $keys   = ['between', 'in'];
256✔
2801
        $column = trim($column);
256✔
2802

2803
        if( in_array(strtolower(Datatype::divide($column, ' ', -1)), $keys) || $this->isExpressionExists($column) )
256✔
2804
        {
2805
            return $value;
26✔
2806
        }
2807

2808
        return $this->escapeStringAddNail($value);
234✔
2809
    }
2810

2811
    /**
2812
     * protected Equal Control
2813
     * 
2814
     * @param string $column
2815
     * 
2816
     * @return string
2817
     */
2818
    protected function setEqualClause($column)
2819
    {
2820
        $column = $column ?? ''; $control = trim($column);
264✔
2821

2822
        if( strstr($column, '.') )
264✔
2823
        {
2824
            $control = str_replace('.', '', $control);
2✔
2825
        }
2826

2827
        if( preg_match('/^\w+$/', $control) )
264✔
2828
        {
2829
            $column .= ' = ';
204✔
2830
        }
2831

2832
        return $column;
264✔
2833
    }
2834

2835
    /**
2836
     * protected Where Having
2837
     * 
2838
     * @param mixed  $column
2839
     * @param string $value
2840
     * @param string $logical
2841
     * 
2842
     * @return string
2843
     */
2844
    protected function whereHaving($column, $value, $logical)
2845
    {
2846
        if( $value !== '' )
264✔
2847
        {
2848
            $value = $this->whereKeyControl($column, $value);
256✔
2849
        }
2850

2851
        $this->convertVartype($column, $value);
264✔
2852

2853
        $column = $this->setEqualClause($column);
264✔
2854

2855
        return ' '.$this->tablePrefixColumnControl($column).' '.$value.' '.$logical.' ';
264✔
2856
    }
2857

2858
    /**
2859
     * protected Where
2860
     * 
2861
     * @param mixed  $column
2862
     * @param string $value
2863
     * @param string $logical
2864
     * @param string $type = 'where'
2865
     * 
2866
     * @return DB
2867
     */
2868
    protected function buildWhereHavingClause($column, $value, $logical, $type = 'where')
2869
    {   
2870
        if( is_array($column) )
252✔
2871
        {
2872
            $columns = func_get_args();
38✔
2873

2874
            if( isset($columns[0][0]) && is_array($columns[0][0]) )
38✔
2875
            {
2876
                $columns = $columns[0];
38✔
2877
            }
2878

2879
            foreach( $columns as $col )
38✔
2880
            {
2881
                if( is_array($col) )
38✔
2882
                {
2883
                    $c = $col[0] ?? '';
38✔
2884
                    $v = $col[1] ?? '';
38✔
2885
                    $l = $col[2] ?? 'and';
38✔
2886

2887
                    $this->$type .= $this->whereHaving($c, $v, $l);
38✔
2888
                }
2889
            }
2890
        }
2891
        else
2892
        {
2893
            $this->$type .= $this->whereHaving($column, $value, $logical ?: 'and');
234✔
2894
        }
2895

2896
        return $this;
252✔
2897
    }
2898

2899
    /**
2900
     * protected Where Having Group
2901
     * 
2902
     * @param array $condition = []
2903
     * 
2904
     * @return string
2905
     */
2906
    protected function whereHavingGroup($conditions = [])
2907
    {
2908
        $con = [];
12✔
2909

2910
        // @codeCoverageIgnoreStart
2911
        if( isset($conditions[0][0]) && is_array($conditions[0][0]) )
2912
        {
2913
            $con        = Arrays\GetElement::last($conditions);
2914
            $conditions = $conditions[0];
2915
        }
2916
        // @codeCoverageIgnoreEnd
2917

2918
        $getLast = Arrays\GetElement::last($conditions);
12✔
2919

2920
        if( is_string($con) )
12✔
2921
        {
2922
            $conjunction = $con; // @codeCoverageIgnore
2923
        }
2924
        else
2925
        {
2926
            if( is_string($getLast) )
12✔
2927
            {
2928
                $conjunction = $getLast;
8✔
2929
                array_pop($conditions);
8✔
2930
            }
2931
            else
2932
            {
2933
                $conjunction = 'and';
8✔
2934
            }
2935
        }
2936

2937
        $whereGroup = '';
12✔
2938

2939
        if( is_array($conditions) ) foreach( $conditions as $column )
12✔
2940
        {
2941
            $col     = $column[0] ?? '';
12✔
2942
            $value   = $column[1] ?? '';
12✔
2943
            $logical = $column[2] ?? 'and';
12✔
2944

2945
            $whereGroup .= $this->whereHaving($col, $value, $logical);
12✔
2946
        }
2947

2948
        return ' ( '.$this->whereHavingConjuctionClean($whereGroup).' ) '.$conjunction.' ';
12✔
2949
    }
2950

2951
    /**
2952
     * protected Where Having Conjuction Control
2953
     * 
2954
     * @param string $type
2955
     * 
2956
     * @return string
2957
     */
2958
    protected function whereHavingConjuctionControl($type)
2959
    {
2960
        if( ! empty($this->$type) )
448✔
2961
        {
2962
            $this->$type = $this->whereHavingConjuctionClean($this->$type) ?: $this->$type;
264✔
2963

2964
            $return = ' '.strtoupper($type).' '.$this->$type;
264✔
2965

2966
            $this->$type = NULL;
264✔
2967

2968
            return $return;
264✔
2969
        }
2970
    }
412✔
2971

2972
    /**
2973
     * protected Where Having Conjuction Clean
2974
     * 
2975
     * @param string $str
2976
     * 
2977
     * @return string
2978
     * 
2979
     * @codeCoverageIgnore
2980
     */
2981
    protected function whereHavingConjuctionClean($str)
2982
    {
2983
        if( ! empty($str) )
2984
        {
2985
            $str = strtolower($orgstr = trim($str));
2986

2987
            switch( substr($str, -3) )
2988
            {
2989
                case 'and' :
2990
                case 'xor' :
2991
                case 'not' :
2992
                return substr($orgstr, 0, -3);
2993
            }
2994

2995
            switch( substr($str, -2) )
2996
            {
2997
                case 'or' :
2998
                case '||' :
2999
                case '&&' :
3000
                return substr($orgstr, 0, -2);
3001
            }
3002

3003
            switch( substr($str, -1) )
3004
            {
3005
                case '!' :
3006
                return substr($orgstr, 0, -1);
3007
            }
3008
        }
3009

3010
        return $str;
3011
    }
3012

3013
    /**
3014
     * protected Where
3015
     * 
3016
     * @return string
3017
     */
3018
    protected function buildWhereClause()
3019
    {
3020
        return $this->whereHavingConjuctionControl('where');
448✔
3021
    }
3022

3023
    /**
3024
     * protected Having
3025
     * 
3026
     * @return string
3027
     */
3028
    protected function buildHavingClause()
3029
    {
3030
        return $this->whereHavingConjuctionControl('having');
408✔
3031
    }
3032

3033
    /**
3034
     * protected Join
3035
     * 
3036
     * @param string $tableAndColumn = ''
3037
     * @param string $otherColumn    = ''
3038
     * @param string $operator       = '='
3039
     * @param string $type           = 'INNER'
3040
     * 
3041
     * @param object
3042
     */
3043
    protected function buildJoinClause($tableAndColumn = '', $otherColumn = '', $operator = '=', $type = 'INNER')
3044
    {
3045
        $condition = $this->tablePrefixColumnControl($tableAndColumn, $table).' '.
16✔
3046
                     $operator.' '.
16✔
3047
                     $this->tablePrefixColumnControl($otherColumn).' ';
16✔
3048
        
3049
        $this->join($table, $condition, $type);
16✔
3050
    }
16✔
3051

3052
    /**
3053
     * protected Table Prefix Column Control
3054
     * 
3055
     * @param string $column
3056
     * @param string & $table = NULL
3057
     * 
3058
     * @return string
3059
     */
3060
    protected function tablePrefixColumnControl($column, &$table = NULL)
3061
    {
3062
        $column = explode('.', $column);
278✔
3063

3064
        # For table
3065
        switch( $count = count($column) )
278✔
3066
        {
3067
            case 3 : $table = $column[0] . '.' . $column[1]; break;
278✔
3068
            case 1 : 
278✔
3069
            case 2 :
16✔
3070
            default: $table = $column[0]; break;
278✔
3071
        }
3072

3073
        # For column
3074
        switch( $count )
3075
        {
3076
            case 2 : return $this->prefix . $column[0] . '.' . $column[1];
278✔
3077
            case 3 : return $column[0] . '.' . $this->prefix . $column[1] . '.' . $column[2];
262✔
3078
            case 1 : 
262✔
3079

3080
            default: return $column[0];
262✔
3081
        }
3082
    }
3083

3084
    /**
3085
     * protected Group By
3086
     * 
3087
     * @return mixed
3088
     */
3089
    protected function buildGroupByClause()
3090
    {
3091
        if( ! empty($this->groupBy) )
408✔
3092
        {
3093
            return ' GROUP BY '.rtrim($this->groupBy, ', ');
8✔
3094
        }
3095

3096
        return false;
404✔
3097
    }
3098

3099
    /**
3100
     * protected Order By
3101
     * 
3102
     * @return mixed
3103
     */
3104
    protected function buildOrderByClause()
3105
    {
3106
        if( ! empty($this->orderBy) )
444✔
3107
        {
3108
            return ' ORDER BY '.rtrim($this->orderBy, ', ');
10✔
3109
        }
3110

3111
        return false;
434✔
3112
    }
3113

3114
    /**
3115
     * protected Increment & Decrement
3116
     * 
3117
     * @param string $table
3118
     * @param array  $columns
3119
     * @param int    $incdec
3120
     * @param string $type
3121
     * 
3122
     * @return bool
3123
     */
3124
    protected function setIncrementDecrement($table, $columns, $incdec, $type)
3125
    {
3126
        $newColumns = [];
12✔
3127

3128
        $table   = $this->addPrefixForTableAndColumn($table);
12✔
3129
        $columns = $this->addPrefixForTableAndColumn($columns, 'column');
12✔
3130
        $incdec  = $type === 'increment' ? abs($incdec) : -abs($incdec);
12✔
3131

3132
        if( is_array($columns) ) foreach( $columns as $v )
12✔
3133
        {
3134
            $newColumns[$v] = "$v + $incdec";
4✔
3135
        }
3136
        else
3137
        {
3138
            $newColumns = [$columns => "$columns + $incdec"];
8✔
3139
        }
3140

3141
        $data = '';
12✔
3142

3143
        foreach( $newColumns as $key => $value )
12✔
3144
        {
3145
            $data .= $key.'='.$value.',';
12✔
3146
        }
3147

3148
        $set = ' SET '.substr($data, 0, -1);
12✔
3149

3150
        $updateQuery = 'UPDATE '.$this->prefix.$table.$set.$this->buildWhereClause();
12✔
3151

3152
        $this->where = NULL;
12✔
3153

3154
        if( $this->string === true )
12✔
3155
        {
3156
            return $updateQuery; // @codeCoverageIgnore
3157
        }
3158

3159
        if( $this->transaction === true )
12✔
3160
        {
3161
            $this->transactionQueries[] = $updateQuery; // @codeCoverageIgnore
3162

3163
            return $this; // @codeCoverageIgnore
3164
        }
3165

3166
        return $this->db->query($updateQuery);
12✔
3167
    }
3168

3169
    /**
3170
     * Query
3171
     * 
3172
     * @param string $query
3173
     * @param array  $secure = []
3174
     * @param mixed  $data   = NULL
3175
     * 
3176
     * @return DB 
3177
     */
3178
    public function setQueryByDriver(string $query, array $secure = [], $data = NULL)
3179
    {
3180
        $this->stringQuery = $query;
368✔
3181
        $this->caching     = $data['caching']    ?? [];
368✔
3182
        $this->tableName   = $data['tableName']  ?? '';
368✔
3183
        $this->jsonDecode  = $data['jsonDecode'] ?? [];
368✔
3184
        $this->paging      = $data['paging'];
368✔
3185

3186
        if( empty($this->caching) || ! Singleton::class('ZN\Cache\Processor')->select($this->getEncryptedCacheQuery()) )
368✔
3187
        {
3188
            $this->secure = $this->secure ?: $secure;
368✔
3189

3190
            $this->db->query($this->querySecurity($query), $secure);
368✔
3191

3192
            if( ! empty($this->transStart) )
368✔
3193
            {
3194
                $transError = $this->db->error();
10✔
3195

3196
                if( ! empty($transError) )
10✔
3197
                {
3198
                    $this->transError = $transError;
6✔
3199
                }
3200
            }
3201
        }
3202

3203
        return $this;
368✔
3204
    }
3205

3206
    /**
3207
     * protected Cache Query
3208
     * 
3209
     * @return string
3210
     */
3211
    protected function getEncryptedCacheQuery()
3212
    {
3213
        return md5(Json::encode($this->config) . $this->stringQuery());
4✔
3214
    }
3215
    
3216
    /**
3217
     * protected reset transaction query variables
3218
     */
3219
    protected function resetTransactionQueryVariables()
3220
    {
3221
        $this->transStart         = NULL;
10✔
3222
        $this->transError         = NULL;
10✔
3223
        $this->transaction        = false;
10✔
3224
        $this->transactionQueries = [];
10✔
3225
    }
10✔
3226

3227
    /**
3228
     * protected Select Reset Query
3229
     */
3230
    protected function resetSelectQueryVariables()
3231
    {
3232
        $this->distinct        = NULL;
408✔
3233
        $this->highPriority    = NULL;
408✔
3234
        $this->straightJoin    = NULL;
408✔
3235
        $this->smallResult     = NULL;
408✔
3236
        $this->bigResult       = NULL;
408✔
3237
        $this->bufferResult    = NULL;
408✔
3238
        $this->cache           = NULL;
408✔
3239
        $this->calcFoundRows   = NULL;
408✔
3240
        $this->preselect       = NULL;
408✔
3241
        $this->select          = NULL;
408✔
3242
        $this->table           = NULL;
408✔
3243
        $this->where           = NULL;
408✔
3244
        $this->groupBy         = NULL;
408✔
3245
        $this->having          = NULL;
408✔
3246
        $this->orderBy         = NULL;
408✔
3247
        $this->limit           = NULL;
408✔
3248
        $this->join            = NULL;
408✔
3249
        $this->selectFunctions = NULL;
408✔
3250
        $this->table           = NULL;
408✔
3251
        $this->partition       = NULL;
408✔
3252
        $this->procedure       = NULL;
408✔
3253
        $this->outFile         = NULL;
408✔
3254
        $this->characterSet    = NULL;
408✔
3255
        $this->into            = NULL;
408✔
3256
        $this->forUpdate       = NULL;
408✔
3257
        $this->returnQueryType  = NULL;
408✔
3258
    }
408✔
3259

3260
    /**
3261
     * protected Reset Insert Query
3262
     */
3263
    protected function resetInsertQueryVariables()
3264
    {
3265
        $this->column          = NULL;
108✔
3266
        $this->table           = NULL;
108✔
3267
        $this->highPriority    = NULL;
108✔
3268
        $this->lowPriority     = NULL;
108✔
3269
        $this->partition       = NULL;
108✔
3270
        $this->ignore          = NULL;
108✔
3271
        $this->delayed         = NULL;
108✔
3272
        $this->duplicateCheck  = NULL;
108✔
3273
        $this->duplicateCheckUpdate = NULL;
108✔
3274
    }
108✔
3275

3276
    /**
3277
     * protected Reset Update Query
3278
     */
3279
    protected function resetUpdateQueryVariables()
3280
    {
3281
        $this->where           = NULL;
44✔
3282
        $this->lowPriority     = NULL;
44✔
3283
        $this->ignore          = NULL;
44✔
3284
        $this->orderBy         = NULL;
44✔
3285
        $this->limit           = NULL;
44✔
3286
        $this->table           = NULL;
44✔
3287
        $this->join            = NULL;
44✔
3288
        $this->column          = NULL;
44✔
3289
    }
44✔
3290

3291
    /**
3292
     * protected Reset Delete Query
3293
     */
3294
    protected function resetDeleteQueryVariables()
3295
    {
3296
        $this->where           = NULL;
78✔
3297
        $this->lowPriority     = NULL;
78✔
3298
        $this->quick           = NULL;
78✔
3299
        $this->ignore          = NULL;
78✔
3300
        $this->join            = NULL;
78✔
3301
        $this->partition       = NULL;
78✔
3302
        $this->orderBy         = NULL;
78✔
3303
        $this->limit           = NULL;
78✔
3304
        $this->table           = NULL;
78✔
3305
    }
78✔
3306
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc