Passed
Push — master ( 014b36...c0bcf8 )
by RN
01:47
created

Dolphin::getFields()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 6
c 0
b 0
f 0
nc 4
nop 2
dl 0
loc 11
rs 10
1
<?php
2
/**
3
 * The Query builder API.
4
 *
5
 * @author RN Kushwaha <[email protected]>
6
 * @since v0.0.1 <Date: 12th April, 2019>
7
 */
8
9
namespace Dolphin\Mapper;
10
11
use Dolphin\Connections\Connection;
12
use Dolphin\Builders\QueryBuilder;
13
use Dolphin\Builders\WhereQueryBuilder;
14
use Dolphin\Builders\JoinQueryBuilder;
15
use Dolphin\Builders\InsertQueryBuilder;
16
use Dolphin\Parsers\WhereQueryParser;
17
use Dolphin\Utils\Utils;
18
use \Exception;
19
20
/**
21
 * This class provides some nice features to interact with the Database
22
 * Elegant Query builder
23
 * Method Chaining
24
 * Prepared Statement using named parameter like status = :status
25
 * Raw Query Option
26
 * Join Clause
27
 * Where Clause
28
 * WhereRaw Clause
29
 * orWhere Clause [TODO]
30
 * WhereIn Clause
31
 * WhereNotIn Clause
32
 * WhereNull Clause
33
 * WhereNotNull Clause
34
 * GroupBy Clause
35
 * Having Clause
36
 * OrderBy Clause.
37
 *
38
 * Aggregations like
39
 * Count()
40
 * Max() [TODO]
41
 * Min() [TODO]
42
 * First()
43
 * Last() [TODO]
44
 * Avg() [TODO]
45
 * fetchColumn [TODO]
46
 * union() [TODO]
47
 * delete()
48
 * update()
49
 * insert()
50
 * truncate()
51
 * havingRaw() [TODO]
52
 * exists() [TODO]
53
 */
54
class Dolphin
55
{
56
    protected $fields = array();
57
    public $table;
58
    public $className;
59
    protected $groupBy;
60
    protected $orderBy;
61
    protected $having;
62
    protected $join = array();
63
    protected $leftJoin = array();
64
    protected $rightJoin = array();
65
    protected $crossJoin = array();
66
    protected $where = array();
67
    protected $whereIn = array();
68
    protected $whereNotIn = array();
69
    protected $whereNull = array();
70
    protected $whereNotNull = array();
71
    protected $limit;
72
    protected $offset;
73
    protected $results;
74
75
    private function getFields(array $args, bool $quote = true){
76
        $fldAr = array();
77
        $qb = new QueryBuilder();
78
79
        foreach ($args as $arg) {
80
            foreach (explode(',', $arg) as $ar) {
81
                $fldAr[] = ($quote === true) ? $qb->quote(trim($ar)) : trim($ar);
82
            }
83
        }
84
85
        return $fldAr;
86
    }
87
88
    public function select()
89
    {
90
        $args = func_get_args();
91
        $fldAr = $this->getFields($args, true);
92
        $this->fields = array_merge($this->fields, $fldAr);
93
94
        return $this;
95
    }
96
97
    public function selectRaw()
98
    {
99
        $args = func_get_args();
100
        $fldAr = $fldAr = $this->getFields($args, false);
0 ignored issues
show
Unused Code introduced by
The assignment to $fldAr is dead and can be removed.
Loading history...
101
        $this->fields = array_merge($this->fields, $fldAr);
102
103
        return $this;
104
    }
105
106
    public function join($join, $mixedParam, $param3 = null, $param4 = null, $mixedParam2 = null)
107
    {
108
        $this->join = array_merge($this->join, [[$join, $mixedParam, $param3, $param4, $mixedParam2]]);
109
110
        return $this;
111
    }
112
113
    public function leftJoin($leftJoin, $mixedParam, $param3 = null, $param4 = null, $mixedParam2 = null)
114
    {
115
        $this->leftJoin = array_merge($this->leftJoin, [[$leftJoin, $mixedParam, $param3, $param4, $mixedParam2]]);
116
117
        return $this;
118
    }
119
120
    public function rightJoin($rightJoin, $mixedParam, $param3 = null, $param4 = null, $mixedParam2 = null)
121
    {
122
        $this->rightJoin = array_merge($this->rightJoin, [[$rightJoin, $mixedParam, $param3, $param4, $mixedParam2]]);
123
124
        return $this;
125
    }
126
127
    public function crossJoin($crossJoin, $params = null)
128
    {
129
        $this->crossJoin = array_merge($this->crossJoin, [[$crossJoin, $params]]);
130
131
        return $this;
132
    }
133
134
    /**
135
     * @throws Exception
136
     */
137
    public function where()
138
    {
139
        $args = func_get_args();
140
        if(func_num_args()===2){
141
            $this->where = array_merge($this->where, [[$args[0], '=', $args[1]]]);
142
            return $this;
143
        } elseif(func_num_args()===3){
144
            $this->where = array_merge($this->where, [[$args[0], $args[1], $args[2]]]);
145
            return $this;
146
        }
147
148
        throw new Exception('Where parameter contains invalid number of parameters', 1);
149
    }
150
151
    public function whereIn($whereIn, $params = array())
152
    {
153
        $this->whereIn = array_merge($this->whereIn, [[$whereIn, $params]]);
154
155
        return $this;
156
    }
157
158
    public function whereNotIn($whereNotIn, $params = array())
159
    {
160
        $this->whereNotIn = array_merge($this->whereNotIn, [[$whereNotIn, $params]]);
161
162
        return $this;
163
    }
164
165
    public function whereNull($whereNull)
166
    {
167
        $this->whereNull = array_merge($this->whereNull, [$whereNull]);
168
169
        return $this;
170
    }
171
172
    public function whereNotNull($whereNotNull)
173
    {
174
        $this->whereNotNull = array_merge($this->whereNotNull, [$whereNotNull]);
175
176
        return $this;
177
    }
178
179
    public function offset($offset)
180
    {
181
        $this->offset = $offset;
182
183
        return $this;
184
    }
185
186
    public function limit($limit)
187
    {
188
        $this->limit = $limit;
189
190
        return $this;
191
    }
192
193
    public function orderBy($orderBy)
194
    {
195
        $this->orderBy = $orderBy;
196
197
        return $this;
198
    }
199
200
    public function groupBy($groupBy)
201
    {
202
        $this->groupBy = $groupBy;
203
204
        return $this;
205
    }
206
207
    public function having($having)
208
    {
209
        $this->having = $having;
210
211
        return $this;
212
    }
213
214
    /**
215
     * Builds Query added by method chaining.
216
     * It has the main logic of ORM
217
     */
218
    protected function buildQuery()
219
    {
220
        $tblWithPrefix = $this->table;
221
        $qb     = new QueryBuilder();
222
        $jqb    = new JoinQueryBuilder();
223
        $wqb    = new WhereQueryBuilder();
224
        $prefix = $qb->getPrefix();
225
        $tbl    = str_replace($prefix, '', $tblWithPrefix);
226
        $query  = [];
227
228
        $query[] = 'SELECT';
229
        $startQuery = join(', ', $this->fields);
230
        if (empty($this->fields)) {
231
            $startQuery = $qb->quote($tbl).'.*';
232
        }
233
        
234
        $query[] = $startQuery;
235
        $query[] = 'FROM';
236
        $query[] = $qb->quote($tblWithPrefix).' AS '.$qb->quote($tbl);
237
238
        $allJoinQuery = $jqb->buildAllJoinQuery(
239
                                $this->join, 
240
                                $this->leftJoin, 
241
                                $this->rightJoin, 
242
                                $this->crossJoin
243
                            );
244
        if (count($allJoinQuery)) {
245
            $query = array_merge($query, $allJoinQuery);
246
        }
247
248
        $allWhereQuery = $wqb->buildAllWhereQuery(
249
                                    $this->where, 
250
                                    $this->whereIn, 
251
                                    $this->whereNotIn, 
252
                                    $this->whereNull, 
253
                                    $this->whereNotNull
254
                                );
255
256
        if (count($allWhereQuery)) {
257
            $query = array_merge($query, $allWhereQuery);
258
        }
259
260
        if (!empty($this->groupBy)) {
261
            $query[] = 'GROUP BY';
262
            $query[] = $this->groupBy;
263
        }
264
265
        if (!empty($this->having)) {
266
            $query[] = 'HAVING';
267
            $query[] = $this->having;
268
        }
269
270
        if (!empty($this->orderBy)) {
271
            $query[] = 'ORDER BY';
272
            $query[] = $this->orderBy;
273
        }
274
275
        if (!empty($this->limit)) {
276
            $query[] = 'LIMIT';
277
278
            if (!empty($this->offset)) {
279
                $query[] = $this->offset.',';
280
            }
281
282
            $query[] = $this->limit;
283
        }
284
285
        return join(' ', $query);
286
    }
287
288
    protected function reset()
289
    {
290
        $this->fields = array();
291
        $this->table = null;
292
        $this->className = null;
293
        $this->groupBy = null;
294
        $this->orderBy = null;
295
        $this->having = null;
296
        $this->join = array();
297
        $this->leftJoin = array();
298
        $this->rightJoin = array();
299
        $this->crossJoin = array();
300
        $this->where = array();
301
        $this->whereIn = array();
302
        $this->whereNotIn = array();
303
        $this->whereNull = array();
304
        $this->whereNotNull = array();
305
        $this->limit = null;
306
        $this->offset = null;
307
    }
308
309
    public function prepare($query, $fetchRows = 'all')
310
    {
311
        $qb   = new QueryBuilder();
312
        $wqp  = new WhereQueryParser();
313
        $util = new Utils();
314
        
315
        try {
316
            $ar = $wqp->parseWhereQuery($this->where);
317
            $stmt = Connection::get()->prepare($qb->queryPrefix($query));
318
            $stmt->execute($ar);
319
320
            if ($fetchRows == 'first') {
321
                $rows = $stmt->fetch(\PDO::FETCH_OBJ);
322
                $this->results = $rows;
323
                // now turn this stdClass object to the object type of calling model
324
                $rows = $util->turnObject($this->className, $rows);
325
                // Reset class variables
326
                $this->reset();
327
328
                return $rows;
329
            }
330
331
            $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
332
            $this->results = $rows;
333
            $rows = $util->turnObjects($this->className, $rows);
334
335
            // Reset class variables
336
            $this->reset();
337
338
            return $rows;
339
        } catch (\PDOException $ex) {
340
            throw new \PDOException($ex->getMessage(), 1);
341
        } catch (Exception $e) {
342
            throw new Exception($e->getMessage(), 1);
343
        }
344
    }
345
346
    public function query($query, $fetchRows = 'all')
347
    {
348
        $qb = new QueryBuilder();
349
350
        try {
351
            $obj = Connection::get()->query($qb->queryPrefix($query), \PDO::FETCH_OBJ);
352
353
            if ($fetchRows == 'count') {
354
                $data = $obj->fetchColumn();
355
            }
356
357
            // Reset class variables
358
            $this->reset();
359
360
            return isset($data) ? $data : $obj;
361
        } catch (\PDOException $ex) {
362
            throw new \PDOException($ex->getMessage(), 1);
363
        } catch (Exception $e) {
364
            throw new Exception($e->getMessage(), 1);
365
        }
366
    }
367
368
    public function get()
369
    {
370
        return $this->prepare($this->buildQuery());
371
    }
372
373
    public function first()
374
    {
375
        $query = $this->buildQuery();
376
377
        if (!strripos($query, 'LIMIT 1')) {
378
            $query .= ' LIMIT 1';
379
        }
380
381
        return $this->prepare($query, 'first');
382
    }
383
384
    /**
385
     * It fetches the row by primary key
386
     * 
387
     * @since v0.0.5 
388
     */
389
    public function find($id)
390
    {
391
        $this->where('id = :id', $id);
392
        
393
        return $this->first();
394
    }
395
396
    /**
397
     * It fetches the row by primary key
398
     * 
399
     * @param int $id
400
     * @return object $row
401
     * @throws Exception
402
     * @since v0.0.5 
403
     */
404
    public function findOrFail($id)
405
    {
406
        $this->where('id = :id', $id);
407
        
408
        $row = $this->first();
409
410
        if($row == null ){
411
            throw new Exception("The record does not exists!");
412
        }
413
414
        return $row;
415
    }
416
417
    public function count()
418
    {
419
        $this->fields = null;
420
        $query = $this->buildQuery();
421
        $query = str_replace('SELECT * ', 'SELECT COUNT(*) as count ', $query);
422
423
        return $this->query($query, 'count');
424
    }
425
426
    /**
427
     * It truncates the table
428
     * 
429
     * @return boolean
430
     * @throws Exception
431
     * @since v0.0.5 
432
     */
433
    public function truncate()
434
    {
435
        $qb = new QueryBuilder();
436
        $query = "TRUNCATE ".$this->table;
437
        
438
        try{
439
            Connection::get()->query($qb->queryPrefix($query));
440
        } catch(Exception $e){
441
            throw new Exception($e->getMessage());
442
        }
443
444
        return true;
445
    }
446
447
    /**
448
     * It inserts the new rows
449
     * 
450
     * @param array $rows
451
     * @return integer $lastInsertedId
452
     * @throws Exception
453
     * @since v0.0.5 
454
     */
455
    public function insert($rows)
456
    {
457
        $iqb = new InsertQueryBuilder();
458
        return $iqb->insert($rows, $this->table);
459
    }
460
461
    /**
462
     * It updates the rows
463
     * 
464
     * @param array $row
465
     * @return boolean
466
     * @throws Exception
467
     * @since v0.0.5 
468
     */
469
    public function update($row)
470
    {
471
        $qb    = new QueryBuilder();
472
        $wqb   = new WhereQueryBuilder();
473
        $query = "UPDATE ".$this->table." SET ";
474
        $ar    = array();
475
        
476
        foreach($row as $key => $val){
477
            $ar[':'.$key] = $val;
478
            $query.= $qb->quote($key)." =:".$key.",";
479
        }
480
481
        $query = rtrim($query, ",");
482
        
483
        try{
484
            $whereQuery = $wqb->buildAllWhereQuery(
485
                                $this->where, 
486
                                $this->whereIn, 
487
                                $this->whereNotIn, 
488
                                $this->whereNull, 
489
                                $this->whereNotNull
490
                            );
491
            $query.= " ".join(" ", $whereQuery);
492
            $stmt = Connection::get()->prepare($qb->queryPrefix($query));
493
            $stmt->execute($ar);
494
            $this->reset();
495
        } catch(Exception $e){
496
            throw new Exception($e->getMessage());
497
        }
498
499
        return true;
500
    }
501
502
    /**
503
     * It deleted the rows matched by where clause
504
     * 
505
     * @return boolean
506
     * @throws Exception
507
     * @since v0.0.5 
508
     */
509
    public function delete()
510
    {
511
        $qb = new QueryBuilder();
512
        $wqb = new WhereQueryBuilder();
513
        $query = "DELETE FROM ".$this->table;
514
        
515
        try{
516
            $whereQuery = $wqb->buildAllWhereQuery(
517
                                    $this->where, 
518
                                    $this->whereIn, 
519
                                    $this->whereNotIn, 
520
                                    $this->whereNull, 
521
                                    $this->whereNotNull
522
                                );
523
            $query.= " ".join(" ", $whereQuery);
524
            Connection::get()->query($qb->queryPrefix($query));
525
            $this->reset();
526
        } catch(Exception $e){
527
            throw new Exception($e->getMessage());
528
        }
529
530
        return true;
531
    }
532
533
}
534