Test Failed
Push — 1.0.0-dev ( 73dca1...204371 )
by nguereza
02:34
created

DatabaseQueryBuilder::whereIsNotNull()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
cc 1
eloc 1
c 1
b 1
f 1
nc 1
nop 2
dl 0
loc 2
rs 10
1
<?php
2
    defined('ROOT_PATH') || exit('Access denied');
3
    /**
4
     * TNH Framework
5
     *
6
     * A simple PHP framework using HMVC architecture
7
     *
8
     * This content is released under the GNU GPL License (GPL)
9
     *
10
     * Copyright (C) 2017 Tony NGUEREZA
11
     *
12
     * This program is free software; you can redistribute it and/or
13
     * modify it under the terms of the GNU General Public License
14
     * as published by the Free Software Foundation; either version 3
15
     * of the License, or (at your option) any later version.
16
     *
17
     * This program is distributed in the hope that it will be useful,
18
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
     * GNU General Public License for more details.
21
     *
22
     * You should have received a copy of the GNU General Public License
23
     * along with this program; if not, write to the Free Software
24
     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25
     */
26
    class DatabaseQueryBuilder {
27
        /**
28
         * The SQL SELECT statment
29
         * @var string
30
         */
31
        private $select = '*';
32
  	
33
        /**
34
         * The SQL FROM statment
35
         * @var string
36
         */
37
        private $from = null;
38
  	
39
        /**
40
         * The SQL WHERE statment
41
         * @var string
42
         */
43
        private $where = null;
44
  	
45
        /**
46
         * The SQL LIMIT statment
47
         * @var string
48
         */
49
        private $limit = null;
50
  	
51
        /**
52
         * The SQL JOIN statment
53
         * @var string
54
         */
55
        private $join = null;
56
  	
57
        /**
58
         * The SQL ORDER BY statment
59
         * @var string
60
         */
61
        private $orderBy = null;
62
  	
63
        /**
64
         * The SQL GROUP BY statment
65
         * @var string
66
         */
67
        private $groupBy = null;
68
  	
69
        /**
70
         * The SQL HAVING statment
71
         * @var string
72
         */
73
        private $having = null;
74
  	
75
        /**
76
         * The full SQL query statment after build for each command
77
         * @var string
78
         */
79
        private $query = null;
80
  	
81
        /**
82
         * The list of SQL valid operators
83
         * @var array
84
         */
85
        private $operatorList = array('=', '!=', '<', '>', '<=', '>=', '<>');
86
  	
87
        /**
88
         * The prefix used in each database table
89
         * @var string
90
         */
91
        private $prefix = null;
92
        
93
94
        /**
95
         * The PDO instance
96
         * @var object
97
         */
98
        private $pdo = null;
99
	
100
        /**
101
         * The database driver name used
102
         * @var string
103
         */
104
        private $driver = null;
105
  	
106
	
107
        /**
108
         * Construct new DatabaseQueryBuilder
109
         * @param object $pdo the PDO object
110
         */
111
        public function __construct(PDO $pdo = null) {
112
            if (is_object($pdo)) {
113
                $this->setPdo($pdo);
114
            }
115
        }
116
117
        /**
118
         * Set the SQL FROM statment
119
         * @param  string|array $table the table name or array of table list
120
         * @return object        the current DatabaseQueryBuilder instance
121
         */
122
        public function from($table) {
123
            if (is_array($table)) {
124
                $froms = '';
125
                foreach ($table as $key) {
126
                    $froms .= $this->prefix . $key . ', ';
127
                }
128
                $this->from = rtrim($froms, ', ');
129
            } else {
130
                $this->from = $this->prefix . $table;
131
            }
132
            return $this;
133
        }
134
135
        /**
136
         * Set the SQL SELECT statment
137
         * @param  string|array $fields the field name or array of field list
138
         * @return object        the current DatabaseQueryBuilder instance
139
         */
140
        public function select($fields) {
141
            $select = $fields;
142
            if (is_array($fields)) {
143
                $select = implode(', ', $fields);
144
            }
145
            return $this->setSelectStr($select);
0 ignored issues
show
Bug introduced by
It seems like $select can also be of type array; however, parameter $newSelect of DatabaseQueryBuilder::setSelectStr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

145
            return $this->setSelectStr(/** @scrutinizer ignore-type */ $select);
Loading history...
146
        }
147
148
        /**
149
         * Set the SQL SELECT DISTINCT statment
150
         * @param  string $field the field name to distinct
151
         * @return object        the current DatabaseQueryBuilder instance
152
         */
153
        public function distinct($field) {
154
            return $this->setSelectStr(' DISTINCT ' . $field);
155
        }
156
157
        /**
158
         * Set the SQL function COUNT in SELECT statment
159
         * @param  string $field the field name
160
         * @param  string $name  if is not null represent the alias used for this field in the result
161
         * @return object        the current DatabaseQueryBuilder instance
162
         */
163
        public function count($field = '*', $name = null) {
164
            return $this->select_min_max_sum_count_avg('COUNT', $field, $name);
165
        }
166
    
167
        /**
168
         * Set the SQL function MIN in SELECT statment
169
         * @param  string $field the field name
170
         * @param  string $name  if is not null represent the alias used for this field in the result
171
         * @return object        the current DatabaseQueryBuilder instance
172
         */
173
        public function min($field, $name = null) {
174
            return $this->select_min_max_sum_count_avg('MIN', $field, $name);
175
        }
176
177
        /**
178
         * Set the SQL function MAX in SELECT statment
179
         * @param  string $field the field name
180
         * @param  string $name  if is not null represent the alias used for this field in the result
181
         * @return object        the current DatabaseQueryBuilder instance
182
         */
183
        public function max($field, $name = null) {
184
            return $this->select_min_max_sum_count_avg('MAX', $field, $name);
185
        }
186
187
        /**
188
         * Set the SQL function SUM in SELECT statment
189
         * @param  string $field the field name
190
         * @param  string $name  if is not null represent the alias used for this field in the result
191
         * @return object        the current DatabaseQueryBuilder instance
192
         */
193
        public function sum($field, $name = null) {
194
            return $this->select_min_max_sum_count_avg('SUM', $field, $name);
195
        }
196
197
        /**
198
         * Set the SQL function AVG in SELECT statment
199
         * @param  string $field the field name
200
         * @param  string $name  if is not null represent the alias used for this field in the result
201
         * @return object        the current DatabaseQueryBuilder instance
202
         */
203
        public function avg($field, $name = null) {
204
            return $this->select_min_max_sum_count_avg('AVG', $field, $name);
205
        }
206
207
        /**
208
         * Set the SQL JOIN statment
209
         * @param  string $table  the join table name
210
         * @param  string $field1 the first field for join conditions	
211
         * @param  string $op     the join condition operator. If is null the default will be "="
212
         * @param  string $field2 the second field for join conditions
213
         * @param  string $type   the type of join (INNER, LEFT, RIGHT)
214
         * @return object        the current DatabaseQueryBuilder instance
215
         */
216
        public function join($table, $field1 = null, $op = null, $field2 = null, $type = '') {
217
            $on = $field1;
218
            $table = $this->prefix . $table;
219
            if (!is_null($op)) {
220
                $on = $this->prefix . $field1 . ' ' . $op . ' ' . $this->prefix . $field2;
221
                if (!in_array($op, $this->operatorList)) {
222
                    $on = $this->prefix . $field1 . ' = ' . $this->prefix . $op;
223
                }
224
            }
225
            if (empty($this->join)) {
226
                $this->join = ' ' . $type . ' JOIN' . ' ' . $table . ' ON ' . $on;
227
            } else {
228
                $this->join = $this->join . ' ' . $type . ' JOIN' . ' ' . $table . ' ON ' . $on;
229
            }
230
            return $this;
231
        }
232
233
        /**
234
         * Set the SQL INNER JOIN statment
235
         * @see  DatabaseQueryBuilder::join()
236
         * @return object        the current DatabaseQueryBuilder instance
237
         */
238
        public function innerJoin($table, $field1, $op = null, $field2 = '') {
239
            return $this->join($table, $field1, $op, $field2, 'INNER ');
240
        }
241
242
        /**
243
         * Set the SQL LEFT JOIN statment
244
         * @see  DatabaseQueryBuilder::join()
245
         * @return object        the current DatabaseQueryBuilder instance
246
         */
247
        public function leftJoin($table, $field1, $op = null, $field2 = '') {
248
            return $this->join($table, $field1, $op, $field2, 'LEFT ');
249
        }
250
251
        /**
252
         * Set the SQL RIGHT JOIN statment
253
         * @see  DatabaseQueryBuilder::join()
254
         * @return object        the current DatabaseQueryBuilder instance
255
         */
256
        public function rightJoin($table, $field1, $op = null, $field2 = '') {
257
            return $this->join($table, $field1, $op, $field2, 'RIGHT ');
258
        }
259
260
        /**
261
         * Set the SQL FULL OUTER JOIN statment
262
         * @see  DatabaseQueryBuilder::join()
263
         * @return object        the current DatabaseQueryBuilder instance
264
         */
265
        public function fullOuterJoin($table, $field1, $op = null, $field2 = '') {
266
            return $this->join($table, $field1, $op, $field2, 'FULL OUTER ');
267
        }
268
269
        /**
270
         * Set the SQL LEFT OUTER JOIN statment
271
         * @see  DatabaseQueryBuilder::join()
272
         * @return object        the current DatabaseQueryBuilder instance
273
         */
274
        public function leftOuterJoin($table, $field1, $op = null, $field2 = '') {
275
            return $this->join($table, $field1, $op, $field2, 'LEFT OUTER ');
276
        }
277
278
        /**
279
         * Set the SQL RIGHT OUTER JOIN statment
280
         * @see  DatabaseQueryBuilder::join()
281
         * @return object        the current DatabaseQueryBuilder instance
282
         */
283
        public function rightOuterJoin($table, $field1, $op = null, $field2 = '') {
284
            return $this->join($table, $field1, $op, $field2, 'RIGHT OUTER ');
285
        }
286
287
        /**
288
         * Set the SQL WHERE CLAUSE for IS NULL
289
         * @see  DatabaseQueryBuilder::whereIsNullAndNotNull
290
         */
291
        public function whereIsNull($field, $andOr = 'AND') {
292
            return $this->whereIsNullAndNotNull($field, $andOr, 'IS NULL');
293
        }
294
295
        /**
296
         * Set the SQL WHERE CLAUSE for IS NOT NULL
297
         * @see  DatabaseQueryBuilder::whereIsNullAndNotNull
298
         */
299
        public function whereIsNotNull($field, $andOr = 'AND') {
300
            return $this->whereIsNullAndNotNull($field, $andOr, 'IS NOT NULL');
301
        }
302
    
303
        /**
304
         * Set the SQL WHERE CLAUSE statment
305
         * @param  string|array  $where the where field or array of field list
306
         * @param  array|string  $op     the condition operator. If is null the default will be "="
307
         * @param  mixed  $val    the where value
308
         * @param  string  $type   the type used for this where clause (NOT, etc.)
309
         * @param  string  $andOr the separator type used 'AND', 'OR', etc.
310
         * @param  boolean $escape whether to escape or not the $val
311
         * @return object        the current DatabaseQueryBuilder instance
312
         */
313
        public function where($where, $op = null, $val = null, $type = '', $andOr = 'AND', $escape = true) {
314
            $whereStr = '';
315
            if (is_array($where)) {
316
                $whereStr = $this->getWhereStrIfIsArray($where, $type, $andOr, $escape);
317
            } else {
318
                if (is_array($op)) {
319
                    $whereStr = $this->getWhereStrIfOperatorIsArray($where, $op, $type, $escape);
320
                } else {
321
                    $whereStr = $this->getWhereStrForOperator($where, $op, $val, $type, $escape);
322
                }
323
            }
324
            $this->setWhereStr($whereStr, $andOr);
325
            return $this;
326
        }
327
328
        /**
329
         * Set the SQL WHERE CLAUSE statment using OR
330
         * @see  DatabaseQueryBuilder::where()
331
         * @return object        the current DatabaseQueryBuilder instance
332
         */
333
        public function orWhere($where, $op = null, $val = null, $escape = true) {
334
            return $this->where($where, $op, $val, '', 'OR', $escape);
335
        }
336
337
        /**
338
         * Set the SQL WHERE CLAUSE statment using AND and NOT
339
         * @see  DatabaseQueryBuilder::where()
340
         * @return object        the current DatabaseQueryBuilder instance
341
         */
342
        public function notWhere($where, $op = null, $val = null, $escape = true) {
343
            return $this->where($where, $op, $val, 'NOT ', 'AND', $escape);
344
        }
345
346
        /**
347
         * Set the SQL WHERE CLAUSE statment using OR and NOT
348
         * @see  DatabaseQueryBuilder::where()
349
         * @return object        the current DatabaseQueryBuilder instance
350
         */
351
        public function orNotWhere($where, $op = null, $val = null, $escape = true) {
352
            return $this->where($where, $op, $val, 'NOT ', 'OR', $escape);
353
        }
354
355
        /**
356
         * Set the opened parenthesis for the complex SQL query
357
         * @param  string $type   the type of this grouped (NOT, etc.)
358
         * @param  string $andOr the multiple conditions separator (AND, OR, etc.)
359
         * @return object        the current DatabaseQueryBuilder instance
360
         */
361
        public function groupStart($type = '', $andOr = ' AND') {
362
            if (empty($this->where)) {
363
                $this->where = $type . ' (';
364
            } else {
365
                if (substr(trim($this->where), -1) == '(') {
366
                    $this->where .= $type . ' (';
367
                } else {
368
                    $this->where .= $andOr . ' ' . $type . ' (';
369
                }
370
            }
371
            return $this;
372
        }
373
374
        /**
375
         * Set the opened parenthesis for the complex SQL query using NOT type
376
         * @see  DatabaseQueryBuilder::groupStart()
377
         * @return object        the current DatabaseQueryBuilder instance
378
         */
379
        public function notGroupStart() {
380
            return $this->groupStart('NOT');
381
        }
382
383
        /**
384
         * Set the opened parenthesis for the complex SQL query using OR for separator
385
         * @see  DatabaseQueryBuilder::groupStart()
386
         * @return object        the current DatabaseQueryBuilder instance
387
         */
388
        public function orGroupStart() {
389
            return $this->groupStart('', ' OR');
390
        }
391
392
        /**
393
         * Set the opened parenthesis for the complex SQL query using OR for separator and NOT for type
394
         * @see  DatabaseQueryBuilder::groupStart()
395
         * @return object        the current DatabaseQueryBuilder instance
396
         */
397
        public function orNotGroupStart() {
398
            return $this->groupStart('NOT', ' OR');
399
        }
400
401
        /**
402
         * Close the parenthesis for the grouped SQL
403
         * @return object        the current DatabaseQueryBuilder instance
404
         */
405
        public function groupEnd() {
406
            $this->where .= ')';
407
            return $this;
408
        }
409
410
        /**
411
         * Set the SQL WHERE CLAUSE statment for IN
412
         * @param  string  $field  the field name for IN statment
413
         * @param  array   $keys   the list of values used
414
         * @param  string  $type   the condition separator type (NOT)
415
         * @param  string  $andOr the multiple conditions separator (OR, AND)
416
         * @param  boolean $escape whether to escape or not the values
417
         * @return object        the current DatabaseQueryBuilder instance
418
         */
419
        public function in($field, array $keys, $type = '', $andOr = 'AND', $escape = true) {
420
            $_keys = array();
421
            foreach ($keys as $k => $v) {
422
                $v = $this->checkForNullValue($v);
423
                if (! is_numeric($v)) {
424
                    $v = $this->escape($v, $escape);
425
                }
426
                $_keys[] = $v;
427
            }
428
            $keys = implode(', ', $_keys);
429
            $whereStr = $field . ' ' . $type . ' IN (' . $keys . ')';
430
            $this->setWhereStr($whereStr, $andOr);
431
            return $this;
432
        }
433
434
        /**
435
         * Set the SQL WHERE CLAUSE statment for NOT IN with AND separator
436
         * @see  DatabaseQueryBuilder::in()
437
         * @return object        the current DatabaseQueryBuilder instance
438
         */
439
        public function notIn($field, array $keys, $escape = true) {
440
            return $this->in($field, $keys, 'NOT ', 'AND', $escape);
441
        }
442
443
        /**
444
         * Set the SQL WHERE CLAUSE statment for IN with OR separator
445
         * @see  DatabaseQueryBuilder::in()
446
         * @return object        the current DatabaseQueryBuilder instance
447
         */
448
        public function orIn($field, array $keys, $escape = true) {
449
            return $this->in($field, $keys, '', 'OR', $escape);
450
        }
451
452
        /**
453
         * Set the SQL WHERE CLAUSE statment for NOT IN with OR separator
454
         * @see  DatabaseQueryBuilder::in()
455
         * @return object        the current DatabaseQueryBuilder instance
456
         */
457
        public function orNotIn($field, array $keys, $escape = true) {
458
            return $this->in($field, $keys, 'NOT ', 'OR', $escape);
459
        }
460
461
        /**
462
         * Set the SQL WHERE CLAUSE statment for BETWEEN
463
         * @param  string  $field  the field used for the BETWEEN statment
464
         * @param  mixed  $value1 the BETWEEN begin value
465
         * @param  mixed  $value2 the BETWEEN end value
466
         * @param  string  $type   the condition separator type (NOT)
467
         * @param  string  $andOr the multiple conditions separator (OR, AND)
468
         * @param  boolean $escape whether to escape or not the values
469
         * @return object        the current DatabaseQueryBuilder instance
470
         */
471
        public function between($field, $value1, $value2, $type = '', $andOr = 'AND', $escape = true) {
472
            $value1 = $this->checkForNullValue($value1);
473
            $value2 = $this->checkForNullValue($value2);
474
            $whereStr = $field . ' ' . $type . ' BETWEEN ' . $this->escape($value1, $escape) . ' AND ' . $this->escape($value2, $escape);
475
            $this->setWhereStr($whereStr, $andOr);
476
            return $this;
477
        }
478
479
        /**
480
         * Set the SQL WHERE CLAUSE statment for BETWEEN with NOT type and AND separator
481
         * @see  DatabaseQueryBuilder::between()
482
         * @return object        the current DatabaseQueryBuilder instance
483
         */
484
        public function notBetween($field, $value1, $value2, $escape = true) {
485
            return $this->between($field, $value1, $value2, 'NOT ', 'AND', $escape);
486
        }
487
488
        /**
489
         * Set the SQL WHERE CLAUSE statment for BETWEEN with OR separator
490
         * @see  DatabaseQueryBuilder::between()
491
         * @return object        the current DatabaseQueryBuilder instance
492
         */
493
        public function orBetween($field, $value1, $value2, $escape = true) {
494
            return $this->between($field, $value1, $value2, '', 'OR', $escape);
495
        }
496
497
        /**
498
         * Set the SQL WHERE CLAUSE statment for BETWEEN with NOT type and OR separator
499
         * @see  DatabaseQueryBuilder::between()
500
         * @return object        the current DatabaseQueryBuilder instance
501
         */
502
        public function orNotBetween($field, $value1, $value2, $escape = true) {
503
            return $this->between($field, $value1, $value2, 'NOT ', 'OR', $escape);
504
        }
505
506
        /**
507
         * Set the SQL WHERE CLAUSE statment for LIKE
508
         * @param  string  $field  the field name used in LIKE statment
509
         * @param  string  $data   the LIKE value for this field including the '%', and '_' part
510
         * @param  string  $type   the condition separator type (NOT)
511
         * @param  string  $andOr the multiple conditions separator (OR, AND)
512
         * @param  boolean $escape whether to escape or not the values
513
         * @return object        the current DatabaseQueryBuilder instance
514
         */
515
        public function like($field, $data, $type = '', $andOr = 'AND', $escape = true) {
516
            $data = $this->checkForNullValue($data);
517
            $this->setWhereStr($field . ' ' . $type . ' LIKE ' . ($this->escape($data, $escape)), $andOr);
518
            return $this;
519
        }
520
521
        /**
522
         * Set the SQL WHERE CLAUSE statment for LIKE with OR separator
523
         * @see  DatabaseQueryBuilder::like()
524
         * @return object        the current DatabaseQueryBuilder instance
525
         */
526
        public function orLike($field, $data, $escape = true) {
527
            return $this->like($field, $data, '', 'OR', $escape);
528
        }
529
530
        /**
531
         * Set the SQL WHERE CLAUSE statment for LIKE with NOT type and AND separator
532
         * @see  DatabaseQueryBuilder::like()
533
         * @return object        the current DatabaseQueryBuilder instance
534
         */
535
        public function notLike($field, $data, $escape = true) {
536
            return $this->like($field, $data, 'NOT ', 'AND', $escape);
537
        }
538
539
        /**
540
         * Set the SQL WHERE CLAUSE statment for LIKE with NOT type and OR separator
541
         * @see  DatabaseQueryBuilder::like()
542
         * @return object        the current DatabaseQueryBuilder instance
543
         */
544
        public function orNotLike($field, $data, $escape = true) {
545
            return $this->like($field, $data, 'NOT ', 'OR', $escape);
546
        }
547
548
        /**
549
         * Set the SQL LIMIT statment
550
         * @param  int $limit    the limit offset. If $limitEnd is null this will be the limit count
551
         * like LIMIT n;
552
         * @param  int $limitEnd the limit count
553
         * @return object        the current DatabaseQueryBuilder instance
554
         */
555
        public function limit($limit, $limitEnd = null) {
556
            if (empty($limit)) {
557
                $limit = 0;
558
            }
559
            if (!is_null($limitEnd)) {
560
                $this->limit = $limit . ', ' . $limitEnd;
561
            } else {
562
                $this->limit = $limit;
563
            }
564
            return $this;
565
        }
566
567
        /**
568
         * Set the SQL ORDER BY CLAUSE statment
569
         * @param  string $orderBy   the field name used for order
570
         * @param  string $orderDir the order direction (ASC or DESC)
571
         * @return object        the current DatabaseQueryBuilder instance
572
         */
573
        public function orderBy($orderBy, $orderDir = ' ASC') {
574
            if (stristr($orderBy, ' ') || $orderBy == 'rand()') {
575
                $this->orderBy = empty($this->orderBy) ? $orderBy : $this->orderBy . ', ' . $orderBy;
576
            } else {
577
                $this->orderBy = empty($this->orderBy) 
578
                            ? ($orderBy . ' ' . strtoupper($orderDir)) 
579
                            : $this->orderBy . ', ' . $orderBy . ' ' . strtoupper($orderDir);
580
            }
581
            return $this;
582
        }
583
584
        /**
585
         * Set the SQL GROUP BY CLAUSE statment
586
         * @param  string|array $field the field name used or array of field list
587
         * @return object        the current DatabaseQueryBuilder instance
588
         */
589
        public function groupBy($field) {
590
            $groupBy = $field;
591
            if (is_array($field)) {
592
                $groupBy = implode(', ', $field);
593
            } 
594
            $this->groupBy = $groupBy;
0 ignored issues
show
Documentation Bug introduced by
It seems like $groupBy can also be of type array. However, the property $groupBy is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
595
            return $this;
596
        }
597
598
        /**
599
         * Set the SQL HAVING CLAUSE statment
600
         * @param  string  $field  the field name used for HAVING statment
601
         * @param  string|array  $op     the operator used or array
602
         * @param  mixed  $val    the value for HAVING comparaison
603
         * @param  boolean $escape whether to escape or not the values
604
         * @return object        the current DatabaseQueryBuilder instance
605
         */
606
        public function having($field, $op = null, $val = null, $escape = true) {
607
            if (is_array($op)) {
608
                $this->having = $this->getHavingStrIfOperatorIsArray($field, $op, $escape);
609
            } else if (!in_array($op, $this->operatorList)) {
610
                $op = $this->checkForNullValue($op);
611
                $this->having = $field . ' > ' . ($this->escape($op, $escape));
612
            } else {
613
                $val = $this->checkForNullValue($val);
614
                $this->having = $field . ' ' . $op . ' ' . ($this->escape($val, $escape));
615
            }
616
            return $this;
617
        }
618
619
        /**
620
         * Insert new record in the database
621
         * @param  array   $data   the record data
622
         * @param  boolean $escape  whether to escape or not the values
623
         * @return object  the current DatabaseQueryBuilder instance        
624
         */
625
        public function insert($data = array(), $escape = true) {
626
            $columns = array_keys($data);
627
            $column = implode(', ', $columns);
628
            $values = implode(', ', ($escape ? array_map(array($this, 'escape'), $data) : $data));
629
630
            $this->query = 'INSERT INTO ' . $this->from . ' (' . $column . ') VALUES (' . $values . ')';
631
            return $this;
632
        }
633
634
        /**
635
         * Update record in the database
636
         * @param  array   $data   the record data if is empty will use the $this->data array.
637
         * @param  boolean $escape  whether to escape or not the values
638
         * @return object  the current DatabaseQueryBuilder instance 
639
         */
640
        public function update($data = array(), $escape = true) {
641
            $query = 'UPDATE ' . $this->from . ' SET ';
642
            $values = array();
643
            foreach ($data as $column => $val) {
644
                $values[] = $column . ' = ' . ($this->escape($val, $escape));
645
            }
646
            $query .= implode(', ', $values);
647
            $query .= $this->buildQueryPart('where', ' WHERE ');
648
            $query .= $this->buildQueryPart('orderBy', ' ORDER BY ');
649
            $query .= $this->buildQueryPart('limit', ' LIMIT ');
650
651
            $this->query = $query;
652
            return $this;
653
        }
654
655
        /**
656
         * Delete the record in database
657
         * @return object  the current DatabaseQueryBuilder instance 
658
         */
659
        public function delete() {
660
            $query = 'DELETE FROM ' . $this->from;
661
            $isTruncate = $query;
662
            $query .= $this->buildQueryPart('where', ' WHERE ');
663
            $query .= $this->buildQueryPart('orderBy', ' ORDER BY ');
664
            $query .= $this->buildQueryPart('limit', ' LIMIT ');
665
666
            if ($isTruncate == $query && $this->driver != 'sqlite') {  
667
                $query = 'TRUNCATE TABLE ' . $this->from;
668
            }
669
            $this->query = $query;
670
            return $this;
671
        }
672
673
        /**
674
         * Escape the data before execute query useful for security.
675
         * @param  mixed $data the data to be escaped
676
         * @param boolean $escaped whether we can do escape of not 
677
         * @return mixed       the data after escaped or the same data if not
678
         */
679
        public function escape($data, $escaped = true) {
680
            $data = trim($data);
681
            if ($escaped) {
682
                return $this->pdo->quote($data);
683
            }
684
            return $data;  
685
        }
686
687
        /**
688
         * Return the current SQL query string
689
         * @return string
690
         */
691
        public function getQuery() {
692
            //INSERT, UPDATE, DELETE already set it, if is SELECT we need set it now
693
            if (empty($this->query)) {
694
                $query = 'SELECT ' . $this->select . ' FROM ' . $this->from;
695
                $query .= $this->buildQueryPart('join', '');
696
                $query .= $this->buildQueryPart('where', ' WHERE ');
697
                $query .= $this->buildQueryPart('groupBy', ' GROUP BY ');
698
                $query .= $this->buildQueryPart('having', ' HAVING ');
699
                $query .= $this->buildQueryPart('orderBy', ' ORDER BY ');
700
                $query .= $this->buildQueryPart('limit', ' LIMIT ');
701
                $this->query = $query;
702
            }
703
            return $this->query;
704
        }
705
706
        /**
707
         * Build the part of SQL query
708
         * @param  string $property the name of this class attribute, use after $this->
709
         * @param  string $command  the SQL command like WHERE, HAVING, etc.
710
         * 
711
         * @return string|null
712
         */
713
         protected function buildQueryPart($property, $command = ''){
714
            if (!empty($this->{$property})) {
715
                return $command . ' ' . $this->{$property};
716
            }
717
            return null;
718
         }
719
720
	
721
        /**
722
         * Return the PDO instance
723
         * @return object
724
         */
725
        public function getPdo() {
726
            return $this->pdo;
727
        }
728
729
        /**
730
         * Set the PDO instance
731
         * @param PDO $pdo the pdo object
732
         * @return object DatabaseQueryBuilder
733
         */
734
        public function setPdo(PDO $pdo = null) {
735
            $this->pdo = $pdo;
736
            return $this;
737
        }
738
    	
739
        /**
740
         * Return the database table prefix
741
         * @return string
742
         */
743
        public function getPrefix() {
744
            return $this->prefix;
745
        }
746
747
        /**
748
         * Set the database table prefix
749
         * @param string $prefix the new prefix
750
         * @return object DatabaseQueryBuilder
751
         */
752
        public function setPrefix($prefix) {
753
            $this->prefix = $prefix;
754
            return $this;
755
        }
756
    	
757
        /**
758
         * Return the database driver
759
         * @return string
760
         */
761
        public function getDriver() {
762
            return $this->driver;
763
        }
764
765
        /**
766
         * Set the database driver
767
         * @param string $driver the new driver
768
         * @return object DatabaseQueryBuilder
769
         */
770
        public function setDriver($driver) {
771
            $this->driver = $driver;
772
            return $this;
773
        }
774
	
775
        /**
776
         * Reset the DatabaseQueryBuilder class attributs to the initial values before each query.
777
         * @return object  the current DatabaseQueryBuilder instance 
778
         */
779
        public function reset() {
780
            $this->select   = '*';
781
            $this->from     = null;
782
            $this->where    = null;
783
            $this->limit    = null;
784
            $this->orderBy  = null;
785
            $this->groupBy  = null;
786
            $this->having   = null;
787
            $this->join     = null;
788
            $this->query    = null;
789
            return $this;
790
        }
791
792
        /**
793
         * Set the SQL WHERE CLAUSE for IS NULL ad IS NOT NULL
794
         * @param  string|array $field  the field name or array of field list
795
         * @param  string $andOr the separator type used 'AND', 'OR', etc.
796
         * @param string $clause the clause type "IS NULL", "IS NOT NULLs"
797
         * @return object        the current DatabaseQueryBuilder instance
798
         */
799
        protected function whereIsNullAndNotNull($field, $andOr = 'AND', $clause = 'IS NULL'){
800
            if (is_array($field)) {
801
                foreach ($field as $f) {
802
                    $this->whereIsNullAndNotNull($f, $andOr, $clause);
803
                }
804
            } else {
805
                $this->setWhereStr($field . ' ' . $clause, $andOr);
806
            }
807
            return $this;
808
        }
809
810
811
        /**
812
         * Set the value for SELECT command and update it if already exists
813
         * @param string $newSelect the new value to set
814
         *
815
         * @return object the current instance
816
         */
817
        protected function setSelectStr($newSelect){
818
            $this->select = (($this->select == '*' || empty($this->select)) 
819
                                    ? $newSelect 
820
                                    : $this->select . ', ' . $newSelect);
821
            return $this;
822
        }
823
824
        /**
825
         * Check if the value is null will return an empty string
826
         * to prevent have error like field1 =  ANd field2 = 'foo'
827
         * @param  string|null $value the value to check
828
         * @return string        the empty string if the value is null
829
         * otherwise the same value will be returned
830
         */
831
        protected function checkForNullValue($value){
832
            if(is_null($value)){
833
                return '';
834
            }
835
            return $value;
836
        }
837
838
        /**
839
         * Get the SQL HAVING clause when operator argument is an array
840
         * @see DatabaseQueryBuilder::having
841
         *
842
         * @return string
843
         */
844
        protected function getHavingStrIfOperatorIsArray($field, $op = null, $escape = true) {
845
            $x = explode('?', $field);
846
            $w = '';
847
            foreach ($x as $k => $v) {
848
                if (!empty($v)) {
849
                    if (!isset($op[$k])) {
850
                        $op[$k] = '';
851
                    }
852
                    $value = '';
853
                    if (isset($op[$k])) {
854
                        $value = $this->escape($op[$k], $escape);
855
                    }
856
                    $w .= $v . $value;
857
                }
858
            }
859
            return $w;
860
        }
861
862
        /**
863
         * Get the SQL WHERE clause using array column => value
864
         * @see DatabaseQueryBuilder::where
865
         *
866
         * @return string
867
         */
868
        protected function getWhereStrIfIsArray(array $where, $type = '', $andOr = 'AND', $escape = true) {
869
            $_where = array();
870
            foreach ($where as $column => $data) {
871
                $data = $this->checkForNullValue($data);
872
                $_where[] = $type . $column . ' = ' . ($this->escape($data, $escape));
873
            }
874
            $where = implode(' ' . $andOr . ' ', $_where);
875
            return $where;
876
        }
877
878
        /**
879
         * Get the SQL WHERE clause when operator argument is an array
880
         * @see DatabaseQueryBuilder::where
881
         *
882
         * @return string
883
         */
884
        protected function getWhereStrIfOperatorIsArray($where, array $op, $type = '', $escape = true) {
885
            $x = explode('?', $where);
886
            $w = '';
887
            foreach ($x as $k => $v) {
888
                if (!empty($v)) {
889
                    $value = '';
890
                    if (isset($op[$k])) {
891
                        $value = $this->escape($op[$k], $escape);
892
                    }
893
                    $w .= $type . $v . $value;
894
                }
895
            }
896
            return $w;
897
        }
898
899
        /**
900
         * Get the default SQL WHERE clause using operator = or the operator argument
901
         * @see DatabaseQueryBuilder::where
902
         *
903
         * @return string
904
         */
905
        protected function getWhereStrForOperator($where, $op = null, $val = null, $type = '', $escape = true) {
906
            $w = '';
907
            if (!in_array((string) $op, $this->operatorList)) {
908
                $op = $this->checkForNullValue($op);
909
                $w = $type . $where . ' = ' . ($this->escape($op, $escape));
910
            } else {
911
                $val = $this->checkForNullValue($val);
912
                $w = $type . $where . ' ' . $op . ' ' . ($this->escape($val, $escape));
913
            }
914
            return $w;
915
        }
916
917
        /**
918
         * Set the $this->where property 
919
         * @param string $whereStr the WHERE clause string
920
         * @param  string  $andOr the separator type used 'AND', 'OR', etc.
921
         */
922
        protected function setWhereStr($whereStr, $andOr = 'AND') {
923
            if (empty($this->where)) {
924
                $this->where = $whereStr;
925
            } else {
926
                if (substr(trim($this->where), -1) == '(') {
927
                    $this->where = $this->where . ' ' . $whereStr;
928
                } else {
929
                    $this->where = $this->where . ' ' . $andOr . ' ' . $whereStr;
930
                }
931
            }
932
        }
933
934
        /**
935
         * Set the SQL SELECT for function MIN, MAX, SUM, AVG, COUNT, AVG
936
         * @param  string $clause the clause type like MIN, MAX, etc.
937
         * @see  DatabaseQueryBuilder::min
938
         * @see  DatabaseQueryBuilder::max
939
         * @see  DatabaseQueryBuilder::sum
940
         * @see  DatabaseQueryBuilder::count
941
         * @see  DatabaseQueryBuilder::avg
942
         * @return object
943
         */
944
        protected function select_min_max_sum_count_avg($clause, $field, $name = null) {
945
            $clause = strtoupper($clause);
946
            $func = $clause . '(' . $field . ')' . (!is_null($name) ? ' AS ' . $name : '');
947
            return $this->setSelectStr($func);
948
        }
949
}
950