Passed
Branch master (8f17c6)
by RN
04:17 queued 31s
created

Dolphin   F

Complexity

Total Complexity 60

Size/Duplication

Total Lines 502
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 229
dl 0
loc 502
rs 3.6
c 1
b 0
f 1
wmc 60

32 Methods

Rating   Name   Duplication   Size   Complexity  
A leftJoin() 0 5 1
A selectRaw() 0 15 3
A rightJoin() 0 5 1
A select() 0 16 3
A join() 0 5 1
A crossJoin() 0 5 1
A table() 0 20 2
A whereNotNull() 0 5 1
A buildAllWhereQuery() 0 8 1
A having() 0 5 1
A limit() 0 5 1
B buildQuery() 0 54 9
A buildAllJoinQuery() 0 7 1
A offset() 0 5 1
A query() 0 19 5
A insert() 0 4 1
A orderBy() 0 5 1
A delete() 0 15 2
A whereIn() 0 5 1
A whereNull() 0 5 1
A prepare() 0 31 4
A get() 0 3 1
A count() 0 7 1
A update() 0 24 3
A find() 0 5 1
A groupBy() 0 5 1
A reset() 0 19 1
A truncate() 0 12 2
A whereNotIn() 0 5 1
A first() 0 11 2
A findOrFail() 0 11 2
A where() 0 12 3

How to fix   Complexity   

Complex Class

Complex classes like Dolphin often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Dolphin, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * The Query builder API.
4
 *
5
 * @author RN Kushwaha <[email protected]>
6
 *
7
 * @since v0.0.1 <Date: 12th April, 2019>
8
 */
9
10
namespace Dolphin\Mapper;
11
12
use Dolphin\Connections\Connection;
13
use Dolphin\Builders\QueryBuilder;
14
use Dolphin\Builders\WhereQueryBuilder;
15
use Dolphin\Builders\JoinQueryBuilder;
16
use Dolphin\Builders\InsertQueryBuilder;
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
    protected $table;
58
    public $tableName;
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
    /**
76
     * It returns the table name to Query from
77
     * Used internally
78
     */
79
    protected function table()
80
    {
81
        $class = $this->tableName;
82
        $ref   = new \ReflectionClass($class);
83
        $qb    = new QueryBuilder();
84
        $util  = new Utils();
85
86
        if ($ref->hasProperty('table')) {
87
            $tableCheck = $ref->getProperty('table');
88
            $tableCheck->setAccessible(true);
89
            $tableName = $tableCheck->getValue(new $class());
90
        } else {
91
            $tableName = explode('\\', $class);
92
            $tableName = $util->decamelize(end($tableName));
93
        }
94
95
        $prefix = $qb->getPrefix();
96
        $this->table = $prefix.$tableName;
97
98
        return $this->table;
99
    }
100
101
    public function select()
102
    {
103
        $args = func_get_args();
104
        $fldAr = array();
105
        $qb = new QueryBuilder();
106
107
        foreach ($args as $arg) {
108
            $argsAr = explode(',', $arg);
109
            foreach ($argsAr as $ar) {
110
                $fldAr[] = $qb->quote(trim($ar));
111
            }
112
        }
113
114
        $this->fields = array_merge($this->fields, $fldAr);
115
116
        return $this;
117
    }
118
119
    public function selectRaw()
120
    {
121
        $args = func_get_args();
122
        $fldAr = array();
123
124
        foreach ($args as $arg) {
125
            $argsAr = explode(',', $arg);
126
            foreach ($argsAr as $ar) {
127
                $fldAr[] = trim($ar);
128
            }
129
        }
130
131
        $this->fields = array_merge($this->fields, $fldAr);
132
133
        return $this;
134
    }
135
136
    public function join($join, $mixedParam, $param3 = null, $param4 = null, $mixedParam2 = null)
137
    {
138
        $this->join = array_merge($this->join, [[$join, $mixedParam, $param3, $param4, $mixedParam2]]);
139
140
        return $this;
141
    }
142
143
    public function leftJoin($leftJoin, $mixedParam, $param3 = null, $param4 = null, $mixedParam2 = null)
144
    {
145
        $this->leftJoin = array_merge($this->leftJoin, [[$leftJoin, $mixedParam, $param3, $param4, $mixedParam2]]);
146
147
        return $this;
148
    }
149
150
    public function rightJoin($rightJoin, $mixedParam, $param3 = null, $param4 = null, $mixedParam2 = null)
151
    {
152
        $this->rightJoin = array_merge($this->rightJoin, [[$rightJoin, $mixedParam, $param3, $param4, $mixedParam2]]);
153
154
        return $this;
155
    }
156
157
    public function crossJoin($crossJoin, $params = null)
158
    {
159
        $this->crossJoin = array_merge($this->crossJoin, [[$crossJoin, $params]]);
160
161
        return $this;
162
    }
163
164
    public function where()
165
    {
166
        $args = func_get_args();
167
        if(func_num_args()===2){
168
            $this->where = array_merge($this->where, [[$args[0], '=', $args[1]]]);
169
        } elseif(func_num_args()===3){
170
            $this->where = array_merge($this->where, [[$args[0], $args[1], $args[2]]]);
171
        } else{
172
            throw new Exception('Where parameter contains invalid number of parameters', 1);
173
        }
174
175
        return $this;
176
    }
177
178
    public function whereIn($whereIn, $params = array())
179
    {
180
        $this->whereIn = array_merge($this->whereIn, [[$whereIn, $params]]);
181
182
        return $this;
183
    }
184
185
    public function whereNotIn($whereNotIn, $params = array())
186
    {
187
        $this->whereNotIn = array_merge($this->whereNotIn, [[$whereNotIn, $params]]);
188
189
        return $this;
190
    }
191
192
    public function whereNull($whereNull)
193
    {
194
        $this->whereNull = array_merge($this->whereNull, [$whereNull]);
195
196
        return $this;
197
    }
198
199
    public function whereNotNull($whereNotNull)
200
    {
201
        $this->whereNotNull = array_merge($this->whereNotNull, [$whereNotNull]);
202
203
        return $this;
204
    }
205
206
    public function offset($offset)
207
    {
208
        $this->offset = $offset;
209
210
        return $this;
211
    }
212
213
    public function limit($limit)
214
    {
215
        $this->limit = $limit;
216
217
        return $this;
218
    }
219
220
    public function orderBy($orderBy)
221
    {
222
        $this->orderBy = $orderBy;
223
224
        return $this;
225
    }
226
227
    public function groupBy($groupBy)
228
    {
229
        $this->groupBy = $groupBy;
230
231
        return $this;
232
    }
233
234
    public function having($having)
235
    {
236
        $this->having = $having;
237
238
        return $this;
239
    }
240
241
    protected function buildAllWhereQuery()
242
    {
243
        $wqb = new WhereQueryBuilder();
244
        return $wqb->buildAllWhereQuery($this->where, 
245
                                        $this->whereIn, 
246
                                        $this->whereNotIn, 
247
                                        $this->whereNull, 
248
                                        $this->whereNotNull
249
                                    );
250
    }
251
252
    protected function buildAllJoinQuery()
253
    {
254
        $jqb = new JoinQueryBuilder();
255
        return $jqb->buildAllJoinQuery($this->join, 
256
                                        $this->leftJoin, 
257
                                        $this->rightJoin, 
258
                                        $this->crossJoin
259
                                    );
260
    }
261
262
    /**
263
     * Builds Query added by method chaining.
264
     * It has the main logic of ORM
265
     */
266
    protected function buildQuery()
267
    {
268
        $query = array();
269
        $tblWithPrefix = $this->table();
270
        $qb     = new QueryBuilder();
271
        $prefix = $qb->getPrefix();
272
        $tbl    = str_replace($prefix, '', $tblWithPrefix);
273
274
        $query[] = 'SELECT';
275
        if (empty($this->fields)) {
276
            $query[] = $qb->quote($tbl).'.*';
277
        } else {
278
            $query[] = join(', ', $this->fields);
279
        }
280
281
        $query[] = 'FROM';
282
        $query[] = $qb->quote($tblWithPrefix).' AS '.$qb->quote($tbl);
283
284
        $allJoinQuery = $this->buildAllJoinQuery();
285
        if (count($allJoinQuery)) {
286
            $query = array_merge($query, $allJoinQuery);
287
        }
288
289
        $allWhereQuery = $this->buildAllWhereQuery();
290
        if (count($allWhereQuery)) {
291
            $query = array_merge($query, $allWhereQuery);
292
        }
293
294
        if (!empty($this->groupBy)) {
295
            $query[] = 'GROUP BY';
296
            $query[] = $this->groupBy;
297
        }
298
299
        if (!empty($this->having)) {
300
            $query[] = 'HAVING';
301
            $query[] = $this->having;
302
        }
303
304
        if (!empty($this->orderBy)) {
305
            $query[] = 'ORDER BY';
306
            $query[] = $this->orderBy;
307
        }
308
309
        if (!empty($this->limit)) {
310
            $query[] = 'LIMIT';
311
312
            if (!empty($this->offset)) {
313
                $query[] = $this->offset.',';
314
            }
315
316
            $query[] = $this->limit;
317
        }
318
319
        return join(' ', $query);
320
    }
321
322
    protected function reset()
323
    {
324
        $this->fields = array();
325
        $this->table = null;
326
        $this->tableName = null;
327
        $this->groupBy = null;
328
        $this->orderBy = null;
329
        $this->having = null;
330
        $this->join = array();
331
        $this->leftJoin = array();
332
        $this->rightJoin = array();
333
        $this->crossJoin = array();
334
        $this->where = array();
335
        $this->whereIn = array();
336
        $this->whereNotIn = array();
337
        $this->whereNull = array();
338
        $this->whereNotNull = array();
339
        $this->limit = null;
340
        $this->offset = null;
341
    }
342
343
    public function prepare($query, $fetchRows = 'all')
344
    {
345
        $qb = new QueryBuilder();
346
        $wqb = new WhereQueryBuilder();
347
        $util = new Utils();
348
        
349
        try {
350
            $ar = $wqb->parseWhereQuery($this->where);
351
            $stmt = Connection::get()->prepare($qb->queryPrefix($query));
352
            $stmt->execute($ar);
353
354
            if ($fetchRows == 'first') {
355
                $rows = $stmt->fetch(\PDO::FETCH_OBJ);
356
                $this->results = $rows;
357
                // now turn this stdClass object to the object type of calling model
358
                $rows = $util->turnObject($this->tableName, $rows);
359
            } else {
360
                // $rows = $stmt->fetchAll(\PDO::FETCH_CLASS, $this->tableName);
361
                $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
362
                $this->results = $rows;
363
                $rows = $util->turnObjects($this->tableName, $rows);
364
            }
365
366
            // Reset class variables
367
            $this->reset();
368
369
            return $rows;
370
        } catch (\PDOException $ex) {
371
            throw new \PDOException($ex->getMessage(), 1);
372
        } catch (Exception $e) {
373
            throw new Exception($e->getMessage(), 1);
374
        }
375
    }
376
377
    public function query($query, $fetchRows = 'all')
378
    {
379
        $qb = new QueryBuilder();
380
381
        try {
382
            $obj = Connection::get()->query($qb->queryPrefix($query), \PDO::FETCH_OBJ);
383
384
            if ($fetchRows == 'count') {
385
                $data = $obj->fetchColumn();
386
            }
387
388
            // Reset class variables
389
            $this->reset();
390
391
            return isset($data) ? $data : $obj;
392
        } catch (\PDOException $ex) {
393
            throw new \PDOException($ex->getMessage(), 1);
394
        } catch (Exception $e) {
395
            throw new Exception($e->getMessage(), 1);
396
        }
397
    }
398
399
    public function get()
400
    {
401
        return $this->prepare($this->buildQuery());
402
    }
403
404
    public function first()
405
    {
406
        $query = $this->buildQuery();
407
408
        if (strripos($query, 'LIMIT 1')) {
409
            // [TODO]
410
        } else {
411
            $query .= ' LIMIT 1';
412
        }
413
414
        return $this->prepare($query, 'first');
415
    }
416
417
    /**
418
     * It fetches the row by primary key
419
     * 
420
     * @author RN Kushwaha <[email protected]>
421
     * @since v0.0.5 
422
     */
423
    public function find($id)
424
    {
425
        $this->where('id = :id', $id);
426
        
427
        return $this->first();
428
    }
429
430
    /**
431
     * It fetches the row by primary key
432
     * 
433
     * @param int $id
434
     * @return object $row
435
     * @throws Exception
436
     * @author RN Kushwaha <[email protected]>
437
     * @since v0.0.5 
438
     */
439
    public function findOrFail($id)
440
    {
441
        $this->where('id = :id', $id);
442
        
443
        $row = $this->first();
444
445
        if($row == null ){
446
            throw new Exception("The record does not exists!");
447
        }
448
449
        return $row;
450
    }
451
452
    public function count()
453
    {
454
        $this->fields = null;
455
        $query = $this->buildQuery();
456
        $query = str_replace('SELECT * ', 'SELECT COUNT(*) as count ', $query);
457
458
        return $this->query($query, 'count');
459
    }
460
461
    /**
462
     * It truncates the table
463
     * 
464
     * @return boolean
465
     * @throws Exception
466
     * @author RN Kushwaha <[email protected]>
467
     * @since v0.0.5 
468
     */
469
    public function truncate()
470
    {
471
        $qb = new QueryBuilder();
472
        $query = "TRUNCATE ".$this->table();
473
        
474
        try{
475
            Connection::get()->query($qb->queryPrefix($query));
476
        } catch(Exception $e){
477
            throw new Exception($e->getMessage());
478
        }
479
480
        return true;
481
    }
482
483
    /**
484
     * It inserts the new rows
485
     * 
486
     * @param array $rows
487
     * @return integer $lastInsertedId
488
     * @throws Exception
489
     * @author RN Kushwaha <[email protected]>
490
     * @since v0.0.5 
491
     */
492
    public function insert($rows)
493
    {
494
        $iqb = new InsertQueryBuilder();
495
        return $iqb->insert($rows, $this->table());
496
    }
497
498
    /**
499
     * It updates the rows
500
     * 
501
     * @param array $row
502
     * @return boolean
503
     * @throws Exception
504
     * @author RN Kushwaha <[email protected]>
505
     * @since v0.0.5 
506
     */
507
    public function update($row)
508
    {
509
        $qb = new QueryBuilder();
510
        $query = "UPDATE ".$this->table()." SET ";
511
        $ar = array();
512
        
513
        foreach($row as $key => $val){
514
            $ar[':'.$key] = $val;
515
            $query.= $qb->quote($key)." =:".$key.",";
516
        }
517
518
        $query = rtrim($query, ",");
519
        
520
        try{
521
            $whereQuery = $this->buildAllWhereQuery();
522
            $query.= " ".join(" ", $whereQuery);
523
            $stmt = Connection::get()->prepare($qb->queryPrefix($query));
524
            $stmt->execute($ar);
525
            $this->reset();
526
        } catch(Exception $e){
527
            throw new Exception($e->getMessage());
528
        }
529
530
        return true;
531
    }
532
533
    /**
534
     * It deleted the rows matched by where clause
535
     * 
536
     * @return boolean
537
     * @throws Exception
538
     * @author RN Kushwaha <[email protected]>
539
     * @since v0.0.5 
540
     */
541
    public function delete()
542
    {
543
        $qb = new QueryBuilder();
544
        $query = "DELETE FROM ".$this->table();
545
        
546
        try{
547
            $whereQuery = $this->buildAllWhereQuery();
548
            $query.= " ".join(" ", $whereQuery);
549
            Connection::get()->query($qb->queryPrefix($query));
550
            $this->reset();
551
        } catch(Exception $e){
552
            throw new Exception($e->getMessage());
553
        }
554
555
        return true;
556
    }
557
558
}
559