• 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

98.51
/Internal/package-database/Connection.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\Support;
15
use ZN\Helpers\Logger;
16
use ZN\DataTypes\Arrays;
17
use ZN\Database\Exception\InvalidArgumentException;
18

19
class Connection
20
{
21
    /**
22
     * Keeps database drivers
23
     * 
24
     * @var array
25
     */
26
    protected $drivers =
27
    [
28
        'odbc'      => 'ODBC', 
29
        'mysqli'    => 'MySQLi',
30
        'oracle'    => 'Oracle',
31
        'postgres'  => 'Postgres',
32
        'sqlite'    => 'SQLite',
33
        'sqlserver' => 'SQLServer'
34
    ];
35

36
    /**
37
     * Keeps database driver
38
     * 
39
     * @var object
40
     */
41
    protected $db;
42

43
    /**
44
     * Keeps database config
45
     * 
46
     * @var array
47
     */
48
    protected $config;
49

50
    /**
51
     * Keeps database default config
52
     * 
53
     * @var array
54
     */
55
    protected $defaultConfig;
56

57
    /**
58
     * Keeps table prefix
59
     * 
60
     * @var string
61
     */
62
    protected $prefix;
63

64
    /**
65
     * Keeps secure data
66
     * 
67
     * @var array
68
     */
69
    protected $secure = [];
70

71
    /**
72
     * Keeps aliases data
73
     * 
74
     * @var array
75
     */
76
    protected $aliases = [];
77

78
    /**
79
     * Select table name
80
     * 
81
     * @var string
82
     */
83
    protected $table;
84

85
    /**
86
     * Keeps table name
87
     * 
88
     * @var string
89
     */
90
    protected $tableName;
91

92
    /**
93
     * Get string query
94
     * 
95
     * @var string
96
     */
97
    protected $stringQuery;
98

99
    /**
100
     * Get string queries
101
     * 
102
     * @var array
103
     */
104
    protected $stringQueries;
105

106
    /**
107
     * Keeps select functions
108
     * 
109
     * @var array
110
     */
111
    protected $selectFunctions;
112

113
    /**
114
     * Keeps column
115
     * 
116
     * @var array
117
     */
118
    protected $column;
119

120
    /**
121
     * Keep database driver
122
     * 
123
     * @var string
124
     */
125
    protected $driver;
126

127
    /**
128
     * Keeps string query
129
     * 
130
     * @var string
131
     */
132
    protected $string;
133

134
    /**
135
     * Transaction queries
136
     * 
137
     * @var bool
138
     */
139
    protected $transaction;
140

141
    /**
142
     * Keeps transaction queries
143
     * 
144
     * @var array
145
     */
146
    protected $transactionQueries;
147

148
    /**
149
     * Magic construtor
150
     * 
151
     * @param array $config
152
     * 
153
     * @return void
154
     */
155
    public function __construct(array $config = [])
156
    {
157
        $this->defaultConfig = Config::default('ZN\Database\DatabaseDefaultConfiguration')
406✔
158
                                     ::get('Database', 'database');
406✔
159
        $this->config        = array_merge($this->defaultConfig, $config);
406✔
160
        $this->db            = $this->runDriver();
406✔
161
        $this->prefix        = $this->config['prefix'];
406✔
162
        Properties::$prefix  = $this->prefix;
406✔
163

164
        $this->db->connect($this->config);
406✔
165
    }
406✔
166

167
    /**
168
     * Magic Debug Info
169
     */
170
    public function __debugInfo()
171
    {
172
        return ['return' => $this->stringQuery ?: 'This is a general object, please call the sub method!'];
2✔
173
    }
174

175
    /**
176
     * Restructure
177
     * 
178
     * @param array $config
179
     * 
180
     * @return void
181
     */
182
    public function restruct(array $config = [])
183
    {
184
        $this->__construct($config);
×
185
    }
×
186

187
    /**
188
     * Alias different connection
189
     * 
190
     * @param mixed $connectName = NULL
191
     * 
192
     * @return Connection
193
     */
194
    public function new($connectName = NULL) : Connection
195
    {
196
        return $this->differentConnection($connectName);
54✔
197
    }
198

199
    /**
200
     * Creates different connection
201
     * 
202
     * @param mixed $connectName = NULL
203
     * 
204
     * @return Connection
205
     */
206
    public function differentConnection($connectName = NULL) : Connection
207
    {
208
        $getCalledClass = get_called_class();
88✔
209

210
        if( empty($connectName) )
88✔
211
        {
212
            return new $getCalledClass;
22✔
213
        }
214

215
        $config          = $this->defaultConfig;
66✔
216
        $configDifferent = $config['differentConnection'];
66✔
217

218
        if( is_string($connectName) && isset($configDifferent[$connectName]) )
66✔
219
        {
220
            $connection = $configDifferent[$connectName];
2✔
221
        }
222
        elseif( is_array($connectName) )
64✔
223
        {
224
            $connection = $connectName;
62✔
225
        }
226
        else
227
        {
228
            throw new InvalidArgumentException('Error', 'invalidInput', 'Mixed $connectName');
2✔
229
        }
230

231
        foreach( $config as $key => $val )
64✔
232
        {
233
            if( $key !== 'differentConnection' )
64✔
234
            {
235
                if( ! isset($connection[$key]) )
64✔
236
                {
237
                    $connection[$key] = $val;
64✔
238
                }
239
            }
240
        }
241

242
        return new $getCalledClass($connection);
64✔
243
    }
244

245
    /**
246
     * Get var types
247
     * 
248
     * @param void
249
     * 
250
     * @return array
251
     */
252
    public function vartypes() : array
253
    {
254
        return $this->db->vartypes();
2✔
255
    }
256

257
    /**
258
     * Sets table name
259
     * 
260
     * @param string $table
261
     * 
262
     * @return Connection
263
     * 
264
     * @codeCoverageIgnore
265
     */
266
    public function table(string $table) : Connection
267
    {
268
        $this->table       = ' '.$this->prefix.$table.' ';
269
        $this->tableName   = $this->prefix.$table;
270
        Properties::$table = $this->tableName;
271

272
        return $this;
273
    }
274

275
    /**
276
     * Sets column
277
     * 
278
     * @param string $col
279
     * @param mixed  $val = NULL
280
     * 
281
     * @return Connection
282
     */
283
    public function column(string $col, $val = NULL) : Connection
284
    {
285
        $this->column[$col] = $val;
2✔
286

287
        return $this;
2✔
288
    }
289

290
    /**
291
     * Converts string query
292
     * 
293
     * @param void
294
     * 
295
     * @return Connection
296
     */
297
    public function string() : Connection
298
    {
299
        $this->string = true;
98✔
300

301
        return $this;
98✔
302
    }
303

304
    /**
305
     * Get string query
306
     * 
307
     * @param void
308
     * 
309
     * @return string
310
     */
311
    public function stringQuery() : string
312
    {
313
        if( ! empty($this->stringQuery) )
186✔
314
        {
315
            return $this->stringQuery;
172✔
316
        }
317

318
        return false;
14✔
319
    }
320

321
    /**
322
     * Get string queries
323
     * 
324
     * @param void
325
     * 
326
     * @return array|false
327
     */
328
    public function stringQueries()
329
    {
330
        if( ! empty($this->stringQueries) )
4✔
331
        {
332
            return $this->stringQueries;
2✔
333
        }
334

335
        return false;
2✔
336
    }
337

338
    /**
339
     * Sets query security
340
     * 
341
     * @param array $data
342
     * 
343
     * @return Connection
344
     */
345
    public function secure(array $data) : Connection
346
    {
347
        $this->secure = $data;
4✔
348

349
        return $this;
4✔
350
    }
351

352
    /**
353
     * Defines function
354
     * 
355
     * @param string ...$args
356
     * 
357
     * @return mixed
358
     */
359
    public function func(...$args)
360
    {
361
        $array = $args;
4✔
362

363
        array_shift($array);
4✔
364

365
        $math  = $this->setMathFunction(isset($args[0]) ? strtoupper($args[0] ?? '') : false, $array);
4✔
366

367
        if( $math->return === true )
4✔
368
        {
369
            return $math->args;
2✔
370
        }
371
        else
372
        {
373
            $this->selectFunctions[] = $math->args;
2✔
374

375
            return $this;
2✔
376
        }
377
    }
378

379
    /**
380
     * Get database query error
381
     * 
382
     * @param void
383
     * 
384
     * @return string
385
     */
386
    public function error()
387
    {
388
        return $this->db->error();
64✔
389
    }
390

391
    /**
392
     * Close database connection
393
     * 
394
     * @param void
395
     * 
396
     * @return bool
397
     */
398
    public function close()
399
    {
400
        return $this->db->close();
2✔
401
    }
402

403
    /**
404
     * Get database version
405
     * 
406
     * @param void
407
     * 
408
     * @return string
409
     */
410
    public function version()
411
    {
412
        return $this->db->version();
6✔
413
    }
414

415
    /**
416
     * protected escape string add nail
417
     * 
418
     * @param mixed $value
419
     * @param mixed $numeric = false
420
     * 
421
     * @return string
422
     */
423
    protected function escapeStringAddNail($value, $numeric = false)
424
    {
425
        if( $numeric === true && is_numeric($value) )
252✔
426
        {
427
            return $value;
6✔
428
        }
429

430
        return Base::presuffix($this->nailEncode($value), "'");
246✔
431
    }
432

433
    /**
434
     * protected exp
435
     * 
436
     * @param string $column = ''
437
     * @param string $exp    = 'exp'
438
     * 
439
     * @return string
440
     */
441
    protected function isExpressionExists($column = '', $exp = 'exp')
442
    {
443
        return stristr($column, $exp . ':');
296✔
444
    }
445

446
    /**
447
     * @param string $column
448
     * @param string $ext = 'exp'
449
     * 
450
     * @return string
451
     */
452
    protected function clearExpression($column, $exp = 'exp')
453
    {
454
        return str_ireplace($exp . ':', '', $column ?? '');
268✔
455
    }
456

457
    /**
458
     * protected clear nail
459
     * 
460
     * @param string 
461
     * 
462
     * @return string
463
     */
464
    protected function clearNail($value)
465
    {
466
        return trim((string) $value, '\'');
266✔
467
    }
468

469
    /**
470
     * protected convert type
471
     * 
472
     * @param string &$column
473
     * @param string &$value 
474
     * 
475
     * @param void
476
     */
477
    protected function convertVartype(&$column = '', &$value = '')
478
    {
479
        $clearValue = $this->clearNail($value);
266✔
480

481
        if( $this->isExpressionExists($column, $type = 'int') )
266✔
482
        {
483
            $value = (int) $clearValue;
2✔
484
        }
485
        elseif( $this->isExpressionExists($column, $type = 'float') )
266✔
486
        {
487
            $value = (float) $clearValue;
2✔
488
        }
489
        else
490
        {
491
            $type = 'exp';
266✔
492
        }
493

494
        $column = $this->clearExpression($column, $type);
266✔
495
    }
266✔
496

497
    /**
498
     * protected query security
499
     * 
500
     * @param string $query
501
     * @param string $isString = false
502
     * 
503
     * @return string
504
     */
505
    protected function querySecurity($query, $isString = false)
506
    {
507
        if( ! empty($this->secure) )
552✔
508
        {
509
            $query = $this->applySecure($query);
4✔
510
        }
511

512
        if( ! empty($this->aliases) )
552✔
513
        {
514
            $query = $this->applyAliases($query);
4✔
515
        }
516

517
        $this->applyNullable($query);
552✔
518
       
519
        if( $isString === false && ($this->config['queryLog'] ?? NULL) === true )
552✔
520
        {
521
            Logger::report('DatabaseQueries', $query, 'DatabaseQueries'); // @codeCoverageIgnore
522
        }
523

524
        $this->stringQueries[] = $this->stringQuery = $query;
552✔
525

526
        return $query;
552✔
527
    }
528

529
    /**
530
     * protected apply nullable
531
     */
532
    protected function applyNullable(&$query)
533
    {
534
        $query = str_ireplace('\'null\'', 'null', $query ?? '');
552✔
535
    }
552✔
536

537
    /**
538
     * protected apply secure
539
     */
540
    protected function applySecure($query)
541
    {
542
        $query = $query ?? '';
4✔
543

544
        $secure = $this->secure; $this->secure = []; $secureParams = [];
4✔
545

546
        if( is_numeric(key($secure)) )
4✔
547
        {
548
            $strex  = explode('?', $query);
2✔
549
            $newstr = '';
2✔
550

551
            if( ! empty($strex) ) for( $i = 0; $i < count($strex) - 1; $i++ )
2✔
552
            {
553
                $sec = $secure[$i] ?? NULL;
2✔
554

555
                $newstr .= $strex[$i].$this->escapeStringAddNail($sec);
2✔
556
            }
557

558
            $query = $newstr . end($strex);
2✔
559
        }
560
        else
561
        {
562
            foreach( $secure as $k => $v )
2✔
563
            {
564
                $this->convertVartype($k, $v);
2✔
565

566
                $secureParams[$k] = $this->escapeStringAddNail($v);
2✔
567
            }
568
        }
569

570
        return str_replace(array_keys($secureParams), array_values($secureParams), $query);
4✔
571
    }
572

573
    /**
574
     * protected apply aliases
575
     */
576
    protected function applyAliases($query)
577
    {
578
        $aliases = $this->aliases; $this->aliases = [];
4✔
579

580
        foreach( $aliases as $alias => $origin )
4✔
581
        {
582
            $query = preg_replace
4✔
583
            (
584
                [
585
                    '/(^|\s)' . $this->prefix . $alias . '($|\s)/i', 
4✔
586
                    '/(^|\W)' . $this->prefix . $alias . '($|\W)/i'
4✔
587
                ], 
588
                [
589
                    '$1' . $this->prefix . $origin . ' ' . $alias . '$2', 
4✔
590
                    '$1' . $alias . '$2'
4✔
591
                ], 
592
                $query
593
            );
594
        }
595

596
        return $query;
4✔
597
    }
598

599
    /**
600
     * Sets math functions
601
     * 
602
     * @param string $type
603
     * @param array  $args
604
     * 
605
     * @return object
606
     */
607
    protected function setMathFunction($type, $args)
608
    {
609
        $type    = strtoupper($type ?? '');
44✔
610
        $getLast = Arrays\GetElement::last($args) ?? '';
44✔
611
        $asparam = ' ';
44✔
612

613
        if( $getLast === true )
44✔
614
        {
615
            array_pop($args);
2✔
616

617
            $return = true;
2✔
618
            $as     = Arrays\GetElement::last($args) ?? '';
2✔
619

620
            // @codeCoverageIgnoreStart
621
            if( stripos(trim($as), 'as') === 0 )
622
            {
623
                $asparam .= $as;
624
                array_pop($args);
625
            }
626
            // @codeCoverageIgnoreEnd
627
        }
628
        else
629
        {
630
            $return = false;
42✔
631
        }
632

633
        // @codeCoverageIgnoreStart
634
        if( stripos(trim($getLast), 'as') === 0 )
635
        {
636
            $asparam .= $getLast;
637
            array_pop($args);
638
        }
639
        // @codeCoverageIgnoreEnd
640

641
        $args = $type.'('.rtrim(implode(',', $args), ',').')'.$asparam;
44✔
642

643
        return (object) 
644
        [
645
            'args'   => $args,
44✔
646
            'return' => $return
44✔
647
        ];
648
    }
649

650
    /**
651
     * Run driver
652
     * 
653
     * @param array $settings = []
654
     * 
655
     * @return object
656
     */
657
    protected function runDriver($settings = [])
658
    {
659
        $this->driver = preg_replace('/(\w+)(\:\w+)*/', '$1', $this->config['driver']);
406✔
660

661
        return $this->getDriver(NULL, $settings);
406✔
662
    }
663

664
    /**
665
     * protected get driver library
666
     * 
667
     * @param string $suffix   = 'Driver'
668
     * @param array  $settings = []
669
     * 
670
     * @return object
671
     */
672
    protected function getDriver($suffix = NULL, $settings = [])
673
    {
674
        Support::driver(array_keys($this->drivers), $this->driver);
406✔
675

676
        $class = 'ZN\Database\\' . $this->drivers[$this->driver] . '\\DB' . $suffix;
406✔
677

678
        return new $class($settings);
406✔
679
    }
680

681
    /**
682
     * protected encode nail
683
     * 
684
     * @param string $data
685
     * 
686
     * @return string
687
     */
688
    protected function nailEncode($data)
689
    {
690
        if( $data === NULL )
278✔
691
        {
692
            return 'NULL';
2✔
693
        }
694

695
        return str_replace(["'", "\&#39;", "\\&#39;"], "&#39;", $data);
278✔
696
    }
697

698
    /**
699
     * protected run exec query
700
     * 
701
     * @param string $query
702
     * @param string $type = 'query'
703
     * 
704
     * @return mixed
705
     */
706
    protected function runQuery($query, $type = 'query')
707
    {
708
        // @codeCoverageIgnoreStart
709
        if( $this->string === true )
710
        {
711
            $this->string = NULL;
712

713
            return $query;
714
        }
715
        // @codeCoverageIgnoreEnd
716

717
        if( $this->transaction === true )
208✔
718
        {
719
            $this->transactionQueries[] = $query;
8✔
720

721
            return $this;
8✔
722
        }
723

724
        if( empty($query) )
208✔
725
        {
726
            $this->stringQuery = NULL;
10✔
727

728
            return false;
10✔
729
        }
730

731
        $this->db->$type($this->querySecurity($query), $this->secure);
204✔
732

733
        return ! (bool) $this->db->error();
204✔
734
    }
735

736
    /**
737
     * protected run exec query
738
     * 
739
     * @param string $query
740
     * 
741
     * @return string
742
     */
743
    protected function runExecQuery($query)
744
    {
745
        return $this->runQuery($query, 'exec');
86✔
746
    }
747

748
    /**
749
     * Sets table name
750
     * 
751
     * @param mixed  $p    = NULL
752
     * @param string $name = 'table'
753
     * 
754
     * @return string
755
     */
756
    protected function addPrefixForTableAndColumn($p = NULL, $name = 'table')
757
    {
758
        if( $name === 'prefix' )
528✔
759
        {
760
            return $this->$name.$p;
10✔
761
        }
762

763
        if( $name === 'table' )
526✔
764
        {
765
            $p = $this->prefix.$p;
518✔
766
        }
767

768
        if( ! empty($this->$name) )
526✔
769
        {
770
            $data = $this->$name;
2✔
771

772
            $this->$name = NULL;
2✔
773

774
            return $data;
2✔
775
        }
776
        else
777
        {
778
            return $p;
526✔
779
        }
780
    }
781

782
    /**
783
     * Magic destructor
784
     * 
785
     * @param void
786
     * 
787
     * @return void
788
     */
789
    public function __destruct()
790
    {
791
        $this->db->close();
392✔
792
    }
392✔
793
}
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

© 2025 Coveralls, Inc