Passed
Push — master ( 4bcd21...b44f1e )
by RN
07:16
created

Dolphin   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 455
Duplicated Lines 0 %

Importance

Changes 8
Bugs 2 Features 4
Metric Value
eloc 209
dl 0
loc 455
rs 7.44
c 8
b 2
f 4
wmc 52

32 Methods

Rating   Name   Duplication   Size   Complexity  
A whereNotNull() 0 5 1
A leftJoin() 0 5 1
A selectRaw() 0 7 1
A rightJoin() 0 5 1
A getFields() 0 11 4
A whereIn() 0 5 1
A whereNull() 0 5 1
A select() 0 7 1
A whereNotIn() 0 5 1
A join() 0 5 1
A where() 0 12 3
A crossJoin() 0 5 1
A having() 0 5 1
A limit() 0 5 1
A offset() 0 5 1
A orderBy() 0 5 1
A groupBy() 0 5 1
A whereRaw() 0 5 1
A buildQuery() 0 25 1
A query() 0 19 5
A insert() 0 4 1
A delete() 0 23 2
B prepare() 0 37 6
A get() 0 3 1
A count() 0 7 1
A update() 0 32 3
A all() 0 5 1
A find() 0 5 1
A reset() 0 20 1
A truncate() 0 12 2
A first() 0 9 2
A findOrFail() 0 11 2

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
 * @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\InsertQueryBuilder;
15
use Dolphin\Parsers\WhereQueryParser;
16
use Dolphin\Utils\Utils;
17
use \Exception;
18
19
/**
20
 * This class provides some nice features to interact with the Database
21
 * Elegant Query builder
22
 * Method Chaining
23
 * Prepared Statement using named parameter like status = :status
24
 * Raw Query Option
25
 * Join Clause
26
 * Where Clause
27
 * WhereRaw Clause
28
 * orWhere Clause [TODO]
29
 * WhereIn Clause
30
 * WhereNotIn Clause
31
 * WhereNull Clause
32
 * WhereNotNull Clause
33
 * GroupBy Clause
34
 * Having Clause
35
 * OrderBy Clause.
36
 *
37
 * Aggregations like
38
 * Count()
39
 * Max() [TODO]
40
 * Min() [TODO]
41
 * First()
42
 * Last() [TODO]
43
 * Avg() [TODO]
44
 * fetchColumn [TODO]
45
 * union() [TODO]
46
 * delete()
47
 * update()
48
 * insert()
49
 * truncate()
50
 * havingRaw() [TODO]
51
 * exists() [TODO]
52
 */
53
class Dolphin
54
{
55
    protected $fields = array();
56
    public $table;
57
    public $className;
58
    protected $groupBy;
59
    protected $orderBy;
60
    protected $having;
61
    protected $join = array();
62
    protected $leftJoin = array();
63
    protected $rightJoin = array();
64
    protected $crossJoin = array();
65
    protected $where = array();
66
    protected $whereRaw = 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 = $this->getFields($args, false);
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 whereRaw($whereConditions)
180
    {
181
        $this->whereRaw = array_merge($this->whereRaw, [$whereConditions]);
182
183
        return $this;
184
    }
185
186
    public function offset($offset)
187
    {
188
        $this->offset = $offset;
189
190
        return $this;
191
    }
192
193
    public function limit($limit)
194
    {
195
        $this->limit = $limit;
196
197
        return $this;
198
    }
199
200
    public function orderBy($orderBy)
201
    {
202
        $this->orderBy = $orderBy;
203
204
        return $this;
205
    }
206
207
    public function groupBy($groupBy)
208
    {
209
        $this->groupBy = $groupBy;
210
211
        return $this;
212
    }
213
214
    public function having($having)
215
    {
216
        $this->having = $having;
217
218
        return $this;
219
    }
220
221
    /**
222
     * Builds Query added by method chaining.
223
     * It has the main logic of ORM
224
     */
225
    protected function buildQuery()
226
    {
227
        $qb     = new QueryBuilder();
228
229
        $query  = $qb->buildQuery([
230
            'table' => $this->table,
231
            'fields' => $this->fields,
232
            'join' => $this->join,
233
            'leftJoin' => $this->leftJoin,
234
            'rightJoin' => $this->rightJoin,
235
            'crossJoin' => $this->crossJoin,
236
            'where' => $this->where,
237
            'whereRaw' => $this->whereRaw,
238
            'whereIn' => $this->whereIn,
239
            'whereNotIn' => $this->whereNotIn,
240
            'whereNull' => $this->whereNull,
241
            'whereNotNull' => $this->whereNotNull,
242
            'groupBy' => $this->groupBy,
243
            'having' => $this->having,
244
            'orderBy' => $this->orderBy,
245
            'limit' => $this->limit,
246
            'offset' => $this->offset
247
        ]);
248
249
        return join(' ', $query);
250
    }
251
252
    protected function reset()
253
    {
254
        $this->fields = array();
255
        $this->table = null;
256
        $this->className = null;
257
        $this->groupBy = null;
258
        $this->orderBy = null;
259
        $this->having = null;
260
        $this->join = array();
261
        $this->leftJoin = array();
262
        $this->rightJoin = array();
263
        $this->crossJoin = array();
264
        $this->where = array();
265
        $this->whereRaw = array();
266
        $this->whereIn = array();
267
        $this->whereNotIn = array();
268
        $this->whereNull = array();
269
        $this->whereNotNull = array();
270
        $this->limit = null;
271
        $this->offset = null;
272
    }
273
274
    public function prepare($query, $fetchRows = 'all')
275
    {
276
        $qb   = new QueryBuilder();
277
        $wqp  = new WhereQueryParser();
278
        $util = new Utils();
279
        $rows = null;
280
281
        try {
282
            $ar = $wqp->parseWhereQuery($this->where);
283
            $stmt = Connection::get()->prepare($qb->queryPrefix($query));
284
            $stmt->execute($ar);
285
286
            if ($fetchRows == 'first') {
287
                $this->results = $stmt->fetch(\PDO::FETCH_OBJ);
288
289
                if(count($this->results) ){
290
                  // now turn this stdClass object to the object type of calling model
291
                  $rows = $util->turnObject($this->className, $this->results);
292
                }
293
                // Reset class variables
294
                $this->reset();
295
296
                return $rows;
297
            }
298
299
            $this->results = $stmt->fetchAll(\PDO::FETCH_ASSOC);
300
            if(count($this->results) ){
301
              $rows = $util->turnObjects($this->className, $this->results);
302
            }
303
            // Reset class variables
304
            $this->reset();
305
306
            return $rows;
307
        } catch (\PDOException $ex) {
308
            throw new \PDOException($ex->getMessage(), 1);
309
        } catch (Exception $e) {
310
            throw new Exception($e->getMessage(), 1);
311
        }
312
    }
313
314
    public function query($query, $fetchRows = 'all')
315
    {
316
        $qb = new QueryBuilder();
317
318
        try {
319
            $obj = Connection::get()->query($qb->queryPrefix($query), \PDO::FETCH_OBJ);
320
321
            if ($fetchRows == 'count') {
322
                $data = $obj->fetchColumn();
323
            }
324
325
            // Reset class variables
326
            $this->reset();
327
328
            return isset($data) ? $data : $obj;
329
        } catch (\PDOException $ex) {
330
            throw new \PDOException($ex->getMessage(), 1);
331
        } catch (Exception $e) {
332
            throw new Exception($e->getMessage(), 1);
333
        }
334
    }
335
336
    public function get()
337
    {
338
        return $this->prepare($this->buildQuery());
339
    }
340
341
    public function first()
342
    {
343
        $query = $this->buildQuery();
344
345
        if (!strripos($query, 'LIMIT 1')) {
346
            $query .= ' LIMIT 1';
347
        }
348
349
        return $this->prepare($query, 'first');
350
    }
351
352
    public function all()
353
    {
354
        $query = $this->buildQuery();
355
356
        return $this->prepare($query);
357
    }
358
359
    /**
360
     * It fetches the row by primary key
361
     *
362
     * @since v0.0.5
363
     */
364
    public function find($id)
365
    {
366
        $this->where('id', $id);
367
368
        return $this->first();
369
    }
370
371
    /**
372
     * It fetches the row by primary key
373
     *
374
     * @param int $id
375
     * @return object $row
376
     * @throws Exception
377
     * @since v0.0.5
378
     */
379
    public function findOrFail($id)
380
    {
381
        $this->where('id', $id);
382
383
        $row = $this->first();
384
385
        if($row == null ){
386
            throw new Exception("The record does not exists!");
387
        }
388
389
        return $row;
390
    }
391
392
    public function count()
393
    {
394
        $this->fields = null;
395
        $query = $this->buildQuery();
396
        $query = str_replace('SELECT * ', 'SELECT COUNT(*) as count ', $query);
397
398
        return $this->query($query, 'count');
399
    }
400
401
    /**
402
     * It truncates the table
403
     *
404
     * @return boolean
405
     * @throws Exception
406
     * @since v0.0.5
407
     */
408
    public function truncate()
409
    {
410
        $qb = new QueryBuilder();
411
        $query = "TRUNCATE ".$this->table;
412
413
        try{
414
            Connection::get()->query($qb->queryPrefix($query));
415
        } catch(Exception $e){
416
            throw new Exception($e->getMessage());
417
        }
418
419
        return true;
420
    }
421
422
    /**
423
     * It inserts the new rows
424
     *
425
     * @param array $rows
426
     * @return integer $lastInsertedId
427
     * @throws Exception
428
     * @since v0.0.5
429
     */
430
    public function insert($rows)
431
    {
432
        $iqb = new InsertQueryBuilder();
433
        return $iqb->insert($rows, $this->table);
434
    }
435
436
    /**
437
     * It updates the rows
438
     *
439
     * @param array $row
440
     * @return boolean
441
     * @throws Exception
442
     * @since v0.0.5
443
     */
444
    public function update($row)
445
    {
446
        $qb    = new QueryBuilder();
447
        $wqb   = new WhereQueryBuilder();
448
        $query = "UPDATE ".$this->table." SET ";
449
        $ar    = array();
450
451
        foreach($row as $key => $val){
452
            $ar[':'.$key] = $val;
453
            $query.= $qb->quote($key)." =:".$key.",";
454
        }
455
456
        $query = rtrim($query, ",");
457
458
        try{
459
            $whereQuery = $wqb->buildAllWhereQuery(
460
                                $this->where,
461
                                $this->whereRaw,
462
                                $this->whereIn,
463
                                $this->whereNotIn,
464
                                $this->whereNull,
465
                                $this->whereNotNull
466
                            );
467
            $query.= " ".join(" ", $whereQuery);
468
            $stmt = Connection::get()->prepare($qb->queryPrefix($query));
469
            $stmt->execute($ar);
470
            $this->reset();
471
        } catch(Exception $e){
472
            throw new Exception($e->getMessage());
473
        }
474
475
        return true;
476
    }
477
478
    /**
479
     * It deleted the rows matched by where clause
480
     *
481
     * @return boolean
482
     * @throws Exception
483
     * @since v0.0.5
484
     */
485
    public function delete()
486
    {
487
        $qb = new QueryBuilder();
488
        $wqb = new WhereQueryBuilder();
489
        $query = "DELETE FROM ".$this->table;
490
491
        try{
492
            $whereQuery = $wqb->buildAllWhereQuery(
493
                                    $this->where,
494
                                    $this->whereRaw,
495
                                    $this->whereIn,
496
                                    $this->whereNotIn,
497
                                    $this->whereNull,
498
                                    $this->whereNotNull
499
                                );
500
            $query.= " ".join(" ", $whereQuery);
501
            Connection::get()->query($qb->queryPrefix($query));
502
            $this->reset();
503
        } catch(Exception $e){
504
            throw new Exception($e->getMessage());
505
        }
506
507
        return true;
508
    }
509
510
}
511