DatabaseQueryBuilder::groupEnd()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
cc 1
eloc 2
c 1
b 1
f 1
nc 1
nop 0
dl 0
loc 3
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 MIT License (MIT)
9
     *
10
     * Copyright (c) 2017 TNH Framework
11
     *
12
     * Permission is hereby granted, free of charge, to any person obtaining a copy
13
     * of this software and associated documentation files (the "Software"), to deal
14
     * in the Software without restriction, including without limitation the rights
15
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
     * copies of the Software, and to permit persons to whom the Software is
17
     * furnished to do so, subject to the following conditions:
18
     *
19
     * The above copyright notice and this permission notice shall be included in all
20
     * copies or substantial portions of the Software.
21
     *
22
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
     * SOFTWARE.
29
     */
30
    
31
    class DatabaseQueryBuilder {
32
33
         /**
34
         * The DatabaseConnection instance
35
         * @var object
36
         */
37
        private $connection = null;
38
39
        /**
40
         * The SQL SELECT statment
41
         * @var string
42
         */
43
        private $select = '*';
44
  	
45
        /**
46
         * The SQL FROM statment
47
         * @var string
48
         */
49
        private $from = null;
50
  	
51
        /**
52
         * The SQL WHERE statment
53
         * @var string
54
         */
55
        private $where = null;
56
  	
57
        /**
58
         * The SQL LIMIT statment
59
         * @var string
60
         */
61
        private $limit = null;
62
  	
63
        /**
64
         * The SQL JOIN statment
65
         * @var string
66
         */
67
        private $join = null;
68
  	
69
        /**
70
         * The SQL ORDER BY statment
71
         * @var string
72
         */
73
        private $orderBy = null;
74
  	
75
        /**
76
         * The SQL GROUP BY statment
77
         * @var string
78
         */
79
        private $groupBy = null;
80
  	
81
        /**
82
         * The SQL HAVING statment
83
         * @var string
84
         */
85
        private $having = null;
86
  	
87
        /**
88
         * The full SQL query statment after build for each command
89
         * @var string
90
         */
91
        private $query = null;
92
  	
93
        /**
94
         * The list of SQL valid operators
95
         * @var array
96
         */
97
        private $operatorList = array('=', '!=', '<', '>', '<=', '>=', '<>');
98
  	
99
        /**
100
         * Construct new DatabaseQueryBuilder
101
         * @param object $connection the DatabaseConnection object
102
         */
103
        public function __construct(DatabaseConnection $connection = null) {
104
            if ($connection !== null) {
105
                $this->connection = $connection;
106
            }
107
        }
108
109
        /**
110
         * Set the SQL FROM statment
111
         * @param  string|array $table the table name or array of table list
112
         * @return object        the current DatabaseQueryBuilder instance
113
         */
114
        public function from($table) {
115
            $prefix = $this->connection->getPrefix();
116
            if (is_array($table)) {
117
                $froms = '';
118
                foreach ($table as $key) {
119
                    $froms .= $prefix . $key . ', ';
120
                }
121
                $this->from = rtrim($froms, ', ');
122
            } else {
123
                $this->from = $prefix . $table;
124
            }
125
            return $this;
126
        }
127
128
        /**
129
         * Set the SQL SELECT statment
130
         * @param  string|array $fields the field name or array of field list
131
         * @return object        the current DatabaseQueryBuilder instance
132
         */
133
        public function select($fields) {
134
            $select = $fields;
135
            if (is_array($fields)) {
136
                $select = implode(', ', $fields);
137
            }
138
            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

138
            return $this->setSelectStr(/** @scrutinizer ignore-type */ $select);
Loading history...
139
        }
140
141
        /**
142
         * Set the SQL SELECT DISTINCT statment
143
         * @param  string $field the field name to distinct
144
         * @return object        the current DatabaseQueryBuilder instance
145
         */
146
        public function distinct($field) {
147
            return $this->setSelectStr('DISTINCT ' . $field);
148
        }
149
150
        /**
151
         * Set the SQL function COUNT in SELECT statment
152
         * @param  string $field the field name
153
         * @param  string $name  if is not null represent the alias used for this field in the result
154
         * @return object        the current DatabaseQueryBuilder instance
155
         */
156
        public function count($field = '*', $name = null) {
157
            return $this->selectMinMaxSumCountAvg('COUNT', $field, $name);
158
        }
159
    
160
        /**
161
         * Set the SQL function MIN in SELECT statment
162
         * @param  string $field the field name
163
         * @param  string $name  if is not null represent the alias used for this field in the result
164
         * @return object        the current DatabaseQueryBuilder instance
165
         */
166
        public function min($field, $name = null) {
167
            return $this->selectMinMaxSumCountAvg('MIN', $field, $name);
168
        }
169
170
        /**
171
         * Set the SQL function MAX in SELECT statment
172
         * @param  string $field the field name
173
         * @param  string $name  if is not null represent the alias used for this field in the result
174
         * @return object        the current DatabaseQueryBuilder instance
175
         */
176
        public function max($field, $name = null) {
177
            return $this->selectMinMaxSumCountAvg('MAX', $field, $name);
178
        }
179
180
        /**
181
         * Set the SQL function SUM in SELECT statment
182
         * @param  string $field the field name
183
         * @param  string $name  if is not null represent the alias used for this field in the result
184
         * @return object        the current DatabaseQueryBuilder instance
185
         */
186
        public function sum($field, $name = null) {
187
            return $this->selectMinMaxSumCountAvg('SUM', $field, $name);
188
        }
189
190
        /**
191
         * Set the SQL function AVG in SELECT statment
192
         * @param  string $field the field name
193
         * @param  string $name  if is not null represent the alias used for this field in the result
194
         * @return object        the current DatabaseQueryBuilder instance
195
         */
196
        public function avg($field, $name = null) {
197
            return $this->selectMinMaxSumCountAvg('AVG', $field, $name);
198
        }
199
200
        /**
201
         * Set the SQL JOIN statment
202
         * @param  string $table  the join table name
203
         * @param  string $field1 the first field for join conditions	
204
         * @param  string $op     the join condition operator. If is null the default will be "="
205
         * @param  string $field2 the second field for join conditions
206
         * @param  string $type   the type of join (INNER, LEFT, RIGHT)
207
         * @return object        the current DatabaseQueryBuilder instance
208
         */
209
        public function join($table, $field1 = null, $op = null, $field2 = null, $type = '') {
210
            $on = $field1;
211
            $prefix = $this->connection->getPrefix();
212
            $table = $prefix . $table;
213
            if (!is_null($op)) {
214
                $on = $prefix . $field1 . ' ' . $op . ' ' . $prefix . $field2;
215
                if (!in_array($op, $this->operatorList)) {
216
                    $on = $prefix . $field1 . ' = ' . $prefix . $op;
217
                }
218
            }
219
            if (empty($this->join)) {
220
                $this->join = $type . 'JOIN' . ' ' . $table . ' ON ' . $on;
221
            } else {
222
                $this->join = $this->join . ' ' . $type . 'JOIN' . ' ' . $table . ' ON ' . $on;
223
            }
224
            return $this;
225
        }
226
227
        /**
228
         * Set the SQL INNER JOIN statment
229
         * @see  DatabaseQueryBuilder::join()
230
         * @return object        the current DatabaseQueryBuilder instance
231
         */
232
        public function innerJoin($table, $field1, $op = null, $field2 = '') {
233
            return $this->join($table, $field1, $op, $field2, 'INNER ');
234
        }
235
236
        /**
237
         * Set the SQL LEFT JOIN statment
238
         * @see  DatabaseQueryBuilder::join()
239
         * @return object        the current DatabaseQueryBuilder instance
240
         */
241
        public function leftJoin($table, $field1, $op = null, $field2 = '') {
242
            return $this->join($table, $field1, $op, $field2, 'LEFT ');
243
        }
244
245
        /**
246
         * Set the SQL RIGHT JOIN statment
247
         * @see  DatabaseQueryBuilder::join()
248
         * @return object        the current DatabaseQueryBuilder instance
249
         */
250
        public function rightJoin($table, $field1, $op = null, $field2 = '') {
251
            return $this->join($table, $field1, $op, $field2, 'RIGHT ');
252
        }
253
254
        /**
255
         * Set the SQL FULL OUTER JOIN statment
256
         * @see  DatabaseQueryBuilder::join()
257
         * @return object        the current DatabaseQueryBuilder instance
258
         */
259
        public function fullOuterJoin($table, $field1, $op = null, $field2 = '') {
260
            return $this->join($table, $field1, $op, $field2, 'FULL OUTER ');
261
        }
262
263
        /**
264
         * Set the SQL LEFT OUTER JOIN statment
265
         * @see  DatabaseQueryBuilder::join()
266
         * @return object        the current DatabaseQueryBuilder instance
267
         */
268
        public function leftOuterJoin($table, $field1, $op = null, $field2 = '') {
269
            return $this->join($table, $field1, $op, $field2, 'LEFT OUTER ');
270
        }
271
272
        /**
273
         * Set the SQL RIGHT OUTER JOIN statment
274
         * @see  DatabaseQueryBuilder::join()
275
         * @return object        the current DatabaseQueryBuilder instance
276
         */
277
        public function rightOuterJoin($table, $field1, $op = null, $field2 = '') {
278
            return $this->join($table, $field1, $op, $field2, 'RIGHT OUTER ');
279
        }
280
281
        /**
282
         * Set the SQL WHERE CLAUSE for IS NULL
283
         * @see  DatabaseQueryBuilder::whereIsNullAndNotNull
284
         */
285
        public function whereIsNull($field, $andOr = 'AND') {
286
            return $this->whereIsNullAndNotNull($field, $andOr, 'IS NULL');
287
        }
288
289
        /**
290
         * Set the SQL WHERE CLAUSE for IS NOT NULL
291
         * @see  DatabaseQueryBuilder::whereIsNullAndNotNull
292
         */
293
        public function whereIsNotNull($field, $andOr = 'AND') {
294
            return $this->whereIsNullAndNotNull($field, $andOr, 'IS NOT NULL');
295
        }
296
    
297
        /**
298
         * Set the SQL WHERE CLAUSE statment
299
         * @param  string|array  $where the where field or array of field list
300
         * @param  null|string  $op the condition operator. If is null the default will be "="
301
         * @param  mixed  $value the where value
302
         * @param  string  $type the type used for this where clause (NOT, etc.)
303
         * @param  string  $andOr the separator type used 'AND', 'OR', etc.
304
         * @param  boolean $escape whether to escape or not the $val
305
         * @return object the current instance
306
         */
307
        public function where($where, $op = null, $value = null, $type = '', $andOr = 'AND', $escape = true) {
308
            if (is_array($where)) {
309
                $whereStr = $this->getWhereStrArray($where, $type, $andOr, $escape);
310
                $this->setWhereStr($whereStr, $andOr);
311
                return $this;
312
            } 
313
            $whereStr = $this->getWhereStrForOperator($where, $op, $value, $type, $escape);
314
            $this->setWhereStr($whereStr, $andOr);
315
            return $this;
316
        }
317
318
        /**
319
         * Set the SQL WHERE CLAUSE statment using OR
320
         * @see  DatabaseQueryBuilder::where()
321
         * @return object        the current DatabaseQueryBuilder instance
322
         */
323
        public function orWhere($where, $op = null, $value = null, $escape = true) {
324
            return $this->where($where, $op, $value, '', 'OR', $escape);
325
        }
326
327
        /**
328
         * Set the SQL WHERE CLAUSE statment using AND and NOT
329
         * @see  DatabaseQueryBuilder::where()
330
         * @return object        the current DatabaseQueryBuilder instance
331
         */
332
        public function notWhere($where, $op = null, $value = null, $escape = true) {
333
            return $this->where($where, $op, $value, 'NOT ', 'AND', $escape);
334
        }
335
336
        /**
337
         * Set the SQL WHERE CLAUSE statment using OR and NOT
338
         * @see  DatabaseQueryBuilder::where()
339
         * @return object        the current DatabaseQueryBuilder instance
340
         */
341
        public function orNotWhere($where, $op = null, $value = null, $escape = true) {
342
            return $this->where($where, $op, $value, 'NOT ', 'OR', $escape);
343
        }
344
345
        /**
346
         * Set the opened parenthesis for the complex SQL query
347
         * @param  string $type   the type of this grouped (NOT, etc.)
348
         * @param  string $andOr the multiple conditions separator (AND, OR, etc.)
349
         * @return object        the current DatabaseQueryBuilder instance
350
         */
351
        public function groupStart($type = '', $andOr = ' AND') {
352
            if (empty($this->where)) {
353
                $this->where = $type . '(';
354
            } else {
355
                if (substr(trim($this->where), -1) == '(') {
356
                    $this->where .= $type . '(';
357
                } else {
358
                    $this->where .= $andOr . $type . ' (';
359
                }
360
            }
361
            return $this;
362
        }
363
364
        /**
365
         * Set the opened parenthesis for the complex SQL query using NOT type
366
         * @see  DatabaseQueryBuilder::groupStart()
367
         * @return object        the current DatabaseQueryBuilder instance
368
         */
369
        public function notGroupStart() {
370
            return $this->groupStart(' NOT');
371
        }
372
373
        /**
374
         * Set the opened parenthesis for the complex SQL query using OR for separator
375
         * @see  DatabaseQueryBuilder::groupStart()
376
         * @return object        the current DatabaseQueryBuilder instance
377
         */
378
        public function orGroupStart() {
379
            return $this->groupStart('', ' OR');
380
        }
381
382
        /**
383
         * Set the opened parenthesis for the complex SQL query using OR for separator and NOT for type
384
         * @see  DatabaseQueryBuilder::groupStart()
385
         * @return object        the current DatabaseQueryBuilder instance
386
         */
387
        public function orNotGroupStart() {
388
            return $this->groupStart('NOT', ' OR');
389
        }
390
391
        /**
392
         * Close the parenthesis for the grouped SQL
393
         * @return object        the current DatabaseQueryBuilder instance
394
         */
395
        public function groupEnd() {
396
            $this->where .= ')';
397
            return $this;
398
        }
399
400
        /**
401
         * Set the SQL WHERE CLAUSE statment for IN
402
         * @param  string  $field  the field name for IN statment
403
         * @param  array   $keys   the list of values used
404
         * @param  string  $type   the condition separator type (NOT)
405
         * @param  string  $andOr the multiple conditions separator (OR, AND)
406
         * @param  boolean $escape whether to escape or not the values
407
         * @return object        the current DatabaseQueryBuilder instance
408
         */
409
        public function in($field, array $keys, $type = '', $andOr = 'AND', $escape = true) {
410
            $keysList = array();
411
            foreach ($keys as $k => $v) {
412
                $v = $this->checkForNullValue($v);
413
                if (! is_numeric($v)) {
414
                    $v = $this->connection->escape($v, $escape);
415
                }
416
                $keysList[] = $v;
417
            }
418
            $keys = implode(', ', $keysList);
419
            $whereStr = $field . $type . ' IN (' . $keys . ')';
420
            $this->setWhereStr($whereStr, $andOr);
421
            return $this;
422
        }
423
424
        /**
425
         * Set the SQL WHERE CLAUSE statment for NOT IN with AND separator
426
         * @see  DatabaseQueryBuilder::in()
427
         * @return object        the current DatabaseQueryBuilder instance
428
         */
429
        public function notIn($field, array $keys, $escape = true) {
430
            return $this->in($field, $keys, ' NOT', 'AND', $escape);
431
        }
432
433
        /**
434
         * Set the SQL WHERE CLAUSE statment for IN with OR separator
435
         * @see  DatabaseQueryBuilder::in()
436
         * @return object        the current DatabaseQueryBuilder instance
437
         */
438
        public function orIn($field, array $keys, $escape = true) {
439
            return $this->in($field, $keys, '', 'OR', $escape);
440
        }
441
442
        /**
443
         * Set the SQL WHERE CLAUSE statment for NOT IN with OR separator
444
         * @see  DatabaseQueryBuilder::in()
445
         * @return object        the current DatabaseQueryBuilder instance
446
         */
447
        public function orNotIn($field, array $keys, $escape = true) {
448
            return $this->in($field, $keys, ' NOT', 'OR', $escape);
449
        }
450
451
        /**
452
         * Set the SQL WHERE CLAUSE statment for BETWEEN
453
         * @param  string  $field  the field used for the BETWEEN statment
454
         * @param  mixed  $value1 the BETWEEN begin value
455
         * @param  mixed  $value2 the BETWEEN end value
456
         * @param  string  $type   the condition separator type (NOT)
457
         * @param  string  $andOr the multiple conditions separator (OR, AND)
458
         * @param  boolean $escape whether to escape or not the values
459
         * @return object        the current DatabaseQueryBuilder instance
460
         */
461
        public function between($field, $value1, $value2, $type = '', $andOr = 'AND', $escape = true) {
462
            $value1 = $this->checkForNullValue($value1);
463
            $value2 = $this->checkForNullValue($value2);
464
            $whereStr = $field . $type . ' BETWEEN ' . $this->connection->escape($value1, $escape) . ' AND ' . $this->connection->escape($value2, $escape);
465
            $this->setWhereStr($whereStr, $andOr);
466
            return $this;
467
        }
468
469
        /**
470
         * Set the SQL WHERE CLAUSE statment for BETWEEN with NOT type and AND separator
471
         * @see  DatabaseQueryBuilder::between()
472
         * @return object        the current DatabaseQueryBuilder instance
473
         */
474
        public function notBetween($field, $value1, $value2, $escape = true) {
475
            return $this->between($field, $value1, $value2, ' NOT', 'AND', $escape);
476
        }
477
478
        /**
479
         * Set the SQL WHERE CLAUSE statment for BETWEEN with OR separator
480
         * @see  DatabaseQueryBuilder::between()
481
         * @return object        the current DatabaseQueryBuilder instance
482
         */
483
        public function orBetween($field, $value1, $value2, $escape = true) {
484
            return $this->between($field, $value1, $value2, '', 'OR', $escape);
485
        }
486
487
        /**
488
         * Set the SQL WHERE CLAUSE statment for BETWEEN with NOT type and OR separator
489
         * @see  DatabaseQueryBuilder::between()
490
         * @return object        the current DatabaseQueryBuilder instance
491
         */
492
        public function orNotBetween($field, $value1, $value2, $escape = true) {
493
            return $this->between($field, $value1, $value2, ' NOT', 'OR', $escape);
494
        }
495
496
        /**
497
         * Set the SQL WHERE CLAUSE statment for LIKE
498
         * @param  string  $field  the field name used in LIKE statment
499
         * @param  string  $value   the LIKE value for this field including the '%', and '_' part
500
         * @param  string  $type   the condition separator type (NOT)
501
         * @param  string  $andOr the multiple conditions separator (OR, AND)
502
         * @param  boolean $escape whether to escape or not the values
503
         * @return object        the current DatabaseQueryBuilder instance
504
         */
505
        public function like($field, $value, $type = '', $andOr = 'AND', $escape = true) {
506
            $value = $this->checkForNullValue($value);
507
            $this->setWhereStr($field . $type . ' LIKE ' . ($this->connection->escape($value, $escape)), $andOr);
508
            return $this;
509
        }
510
511
        /**
512
         * Set the SQL WHERE CLAUSE statment for LIKE with OR separator
513
         * @see  DatabaseQueryBuilder::like()
514
         * @return object        the current DatabaseQueryBuilder instance
515
         */
516
        public function orLike($field, $value, $escape = true) {
517
            return $this->like($field, $value, '', 'OR', $escape);
518
        }
519
520
        /**
521
         * Set the SQL WHERE CLAUSE statment for LIKE with NOT type and AND separator
522
         * @see  DatabaseQueryBuilder::like()
523
         * @return object        the current DatabaseQueryBuilder instance
524
         */
525
        public function notLike($field, $value, $escape = true) {
526
            return $this->like($field, $value, ' NOT', 'AND', $escape);
527
        }
528
529
        /**
530
         * Set the SQL WHERE CLAUSE statment for LIKE with NOT type and OR separator
531
         * @see  DatabaseQueryBuilder::like()
532
         * @return object        the current DatabaseQueryBuilder instance
533
         */
534
        public function orNotLike($field, $value, $escape = true) {
535
            return $this->like($field, $value, ' NOT', 'OR', $escape);
536
        }
537
538
        /**
539
         * Set the SQL LIMIT statment
540
         * @param  int $offset    the limit offset. If $limitEnd is null this will be the limit count
541
         * like LIMIT n;
542
         * @param  int $count the limit count
543
         * @return object        the current DatabaseQueryBuilder instance
544
         */
545
        public function limit($offset, $count = null) {
546
            if (empty($offset)) {
547
                $offset = 0;
548
            }
549
            if (!is_null($count)) {
550
                $this->limit = $offset . ', ' . $count;
551
            } else {
552
                $this->limit = $offset;
553
            }
554
            return $this;
555
        }
556
557
        /**
558
         * Set the SQL ORDER BY CLAUSE statment
559
         * @param  string $field   the field name used for order
560
         * @param  string $orderDir the order direction (ASC or DESC)
561
         * @return object        the current DatabaseQueryBuilder instance
562
         */
563
        public function orderBy($field, $orderDir = 'ASC') {
564
            if (stristr($field, ' ') || $field == 'rand()') {
565
                $this->orderBy = empty($this->orderBy) ? $field : $this->orderBy . ', ' . $field;
566
            } else {
567
                $this->orderBy = empty($this->orderBy) 
568
                            ? ($field . ' ' . strtoupper($orderDir)) 
569
                            : $this->orderBy . ', ' . $field . ' ' . strtoupper($orderDir);
570
            }
571
            return $this;
572
        }
573
574
        /**
575
         * Set the SQL GROUP BY CLAUSE statment
576
         * @param  string|array $field the field name used or array of field list
577
         * @return object        the current DatabaseQueryBuilder instance
578
         */
579
        public function groupBy($field) {
580
            $groupBy = $field;
581
            if (is_array($field)) {
582
                $groupBy = implode(', ', $field);
583
            } 
584
            $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...
585
            return $this;
586
        }
587
588
        /**
589
         * Set the SQL HAVING CLAUSE statment
590
         * @param  string  $field  the field name used for HAVING statment
591
         * @param  string|null $op the operator used or array
592
         * @param  mixed  $value the value for HAVING comparaison
593
         * @param  boolean $escape whether to escape or not the values
594
         * @return object the current instance
595
         */
596
        public function having($field, $op = null, $value = null, $escape = true) {
597
            if (!in_array($op, $this->operatorList)) {
598
                $op = $this->checkForNullValue($op);
599
                $this->having = $field . ' > ' . ($this->connection->escape($op, $escape));
600
                return $this;
601
            } 
602
            $value = $this->checkForNullValue($value);
603
            $this->having = $field . ' ' . $op . ' ' . ($this->connection->escape($value, $escape));
604
            return $this;
605
        }
606
607
        /**
608
         * Insert new record in the database
609
         * @param  array   $data   the record data
610
         * @param  boolean $escape  whether to escape or not the values
611
         * @return object  the current DatabaseQueryBuilder instance        
612
         */
613
        public function insert($data = array(), $escape = true) {
614
            $columns = array_keys($data);
615
            $column = implode(', ', $columns);
616
            $values = implode(', ', ($escape ? array_map(array($this->connection, 'escape'), $data) : $data));
617
618
            $this->query = 'INSERT INTO ' . $this->from . '(' . $column . ') VALUES (' . $values . ')';
619
            return $this;
620
        }
621
622
        /**
623
         * Update record in the database
624
         * @param  array   $data   the record data if is empty will use the $this->data array.
625
         * @param  boolean $escape  whether to escape or not the values
626
         * @return object  the current DatabaseQueryBuilder instance 
627
         */
628
        public function update($data = array(), $escape = true) {
629
            $query = 'UPDATE ' . $this->from . ' SET ';
630
            $values = array();
631
            foreach ($data as $column => $val) {
632
                $values[] = $column . ' = ' . ($this->connection->escape($val, $escape));
633
            }
634
            $query .= implode(', ', $values);
635
            $query .= $this->buildQueryPart('where', ' WHERE ');
636
            $query .= $this->buildQueryPart('orderBy', ' ORDER BY ');
637
            $query .= $this->buildQueryPart('limit', ' LIMIT ');
638
639
            $this->query = $query;
640
            return $this;
641
        }
642
643
        /**
644
         * Delete the record in database
645
         * @return object  the current DatabaseQueryBuilder instance 
646
         */
647
        public function delete() {
648
            $query = 'DELETE FROM ' . $this->from;
649
            $isTruncate = $query;
650
            $query .= $this->buildQueryPart('where', ' WHERE ');
651
            $query .= $this->buildQueryPart('orderBy', ' ORDER BY ');
652
            $query .= $this->buildQueryPart('limit', ' LIMIT ');
653
654
            if ($isTruncate == $query && $this->connection->getDriver() != 'sqlite') {  
655
                $query = 'TRUNCATE TABLE ' . $this->from;
656
            }
657
            $this->query = $query;
658
            return $this;
659
        }
660
661
        /**
662
         * Return the current SQL query string
663
         * @return string
664
         */
665
        public function getQuery() {
666
            //INSERT, UPDATE, DELETE already set it, if is SELECT we need set it now
667
            if (empty($this->query)) {
668
                $query = 'SELECT ' . $this->select . ' FROM ' . $this->from;
669
                $query .= $this->buildQueryPart('join', ' ');
670
                $query .= $this->buildQueryPart('where', ' WHERE ');
671
                $query .= $this->buildQueryPart('groupBy', ' GROUP BY ');
672
                $query .= $this->buildQueryPart('having', ' HAVING ');
673
                $query .= $this->buildQueryPart('orderBy', ' ORDER BY ');
674
                $query .= $this->buildQueryPart('limit', ' LIMIT ');
675
                $this->query = trim($query);
676
            }
677
            return $this->query;
678
        }
679
	
680
        /**
681
         * Reset the DatabaseQueryBuilder class attributs to the initial values before each query.
682
         * @return object  the current DatabaseQueryBuilder instance 
683
         */
684
        public function reset() {
685
            $this->select   = '*';
686
            $this->from     = null;
687
            $this->where    = null;
688
            $this->limit    = null;
689
            $this->orderBy  = null;
690
            $this->groupBy  = null;
691
            $this->having   = null;
692
            $this->join     = null;
693
            $this->query    = null;
694
            return $this;
695
        }
696
697
        /**
698
         * Return the DatabaseConnection instance
699
         * @return object DatabaseConnection
700
         */
701
        public function getConnection() {
702
            return $this->connection;
703
        }
704
705
        /**
706
         * Set the DatabaseConnection instance
707
         * @param object DatabaseConnection $connection the DatabaseConnection object
708
         *
709
         * @return object the current instance
710
         */
711
        public function setConnection(DatabaseConnection $connection) {
712
            $this->connection = $connection;
713
            return $this;
714
        }
715
716
717
        /**
718
         * Build the part of SQL query
719
         * @param  string $property the name of this class attribute, use after $this->
720
         * @param  string $command  the SQL command like WHERE, HAVING, etc.
721
         * 
722
         * @return string|null
723
         */
724
         protected function buildQueryPart($property, $command = ''){
725
            if (!empty($this->{$property})) {
726
                return $command . $this->{$property};
727
            }
728
            return null;
729
         }
730
731
732
        /**
733
         * Set the SQL WHERE CLAUSE for IS NULL ad IS NOT NULL
734
         * @param  string|array $field  the field name or array of field list
735
         * @param  string $andOr the separator type used 'AND', 'OR', etc.
736
         * @param string $clause the clause type "IS NULL", "IS NOT NULLs"
737
         * @return object        the current DatabaseQueryBuilder instance
738
         */
739
        protected function whereIsNullAndNotNull($field, $andOr = 'AND', $clause = 'IS NULL'){
740
            if (is_array($field)) {
741
                foreach ($field as $f) {
742
                    $this->whereIsNullAndNotNull($f, $andOr, $clause);
743
                }
744
            } else {
745
                $this->setWhereStr($field . ' ' . $clause, $andOr);
746
            }
747
            return $this;
748
        }
749
750
751
        /**
752
         * Set the value for SELECT command and update it if already exists
753
         * @param string $newSelect the new value to set
754
         *
755
         * @return object the current instance
756
         */
757
        protected function setSelectStr($newSelect){
758
            $this->select = (($this->select == '*' || empty($this->select)) 
759
                                    ? $newSelect 
760
                                    : $this->select . ', ' . $newSelect);
761
            return $this;
762
        }
763
764
        /**
765
         * Check if the value is null will return an empty string
766
         * to prevent have error like field1 =  ANd field2 = 'foo'
767
         * @param  string|null $value the value to check
768
         * @return string        the empty string if the value is null
769
         * otherwise the same value will be returned
770
         */
771
        protected function checkForNullValue($value){
772
            if(is_null($value)){
773
                return '';
774
            }
775
            return $value;
776
        }
777
778
        /**
779
         * Get the SQL WHERE clause using array column => value
780
         * @see DatabaseQueryBuilder::where
781
         *
782
         * @return string
783
         */
784
        protected function getWhereStrArray(array $where, $type = '', $andOr = 'AND', $escape = true) {
785
            $wheres = array();
786
            foreach ($where as $column => $data) {
787
                $data = $this->checkForNullValue($data);
788
                $wheres[] = $type . $column . ' = ' . ($this->connection->escape($data, $escape));
789
            }
790
            return implode(' ' . $andOr . ' ', $wheres);
791
        }
792
793
        /**
794
         * Get the default SQL WHERE clause using operator = or the operator argument
795
         * @see DatabaseQueryBuilder::where
796
         *
797
         * @return string
798
         */
799
        protected function getWhereStrForOperator($where, $op = null, $value= null, $type = '', $escape = true) {
800
            $w = '';
801
            if (!in_array((string) $op, $this->operatorList)) {
802
                $op = $this->checkForNullValue($op);
803
                $w = $type . $where . ' = ' . ($this->connection->escape($op, $escape));
804
            } else {
805
                $value = $this->checkForNullValue($value);
806
                $w = $type . $where . ' ' . $op . ' ' . ($this->connection->escape($value, $escape));
807
            }
808
            return $w;
809
        }
810
811
        /**
812
         * Set the $this->where property 
813
         * @param string $whereStr the WHERE clause string
814
         * @param  string  $andOr the separator type used 'AND', 'OR', etc.
815
         */
816
        protected function setWhereStr($whereStr, $andOr = 'AND') {
817
            if (empty($this->where)) {
818
                $this->where = $whereStr;
819
            } else {
820
                if (substr(trim($this->where), -1) == '(') {
821
                    $this->where = $this->where . $whereStr;
822
                } else {
823
                    $this->where = $this->where . ' ' . $andOr . ' ' . $whereStr;
824
                }
825
            }
826
        }
827
828
        /**
829
         * Set the SQL SELECT for function MIN, MAX, SUM, AVG, COUNT, AVG
830
         * @param  string $clause the clause type like MIN, MAX, etc.
831
         * @see  DatabaseQueryBuilder::min
832
         * @see  DatabaseQueryBuilder::max
833
         * @see  DatabaseQueryBuilder::sum
834
         * @see  DatabaseQueryBuilder::count
835
         * @see  DatabaseQueryBuilder::avg
836
         * @return object
837
         */
838
        protected function selectMinMaxSumCountAvg($clause, $field, $name = null) {
839
            $clause = strtoupper($clause);
840
            $func = $clause . '(' . $field . ')' . (!is_null($name) ? ' AS ' . $name : '');
841
            return $this->setSelectStr($func);
842
        }
843
}
844