Completed
Push — resets ( d2f77b )
by Paul
02:06
created

Select::buildFrom()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3
Metric Value
dl 0
loc 12
ccs 8
cts 8
cp 1
rs 9.4285
cc 3
eloc 7
nc 3
nop 0
crap 3
1
<?php
2
/**
3
 *
4
 * This file is part of Aura for PHP.
5
 *
6
 * @license http://opensource.org/licenses/bsd-license.php BSD
7
 *
8
 */
9
namespace Aura\SqlQuery\Common;
10
11
use Aura\SqlQuery\AbstractQuery;
12
use Aura\SqlQuery\Exception;
13
14
/**
15
 *
16
 * An object for SELECT queries.
17
 *
18
 * @package Aura.SqlQuery
19
 *
20
 */
21
class Select extends AbstractQuery implements SelectInterface, SubselectInterface
22
{
23
    /**
24
     *
25
     * An array of union SELECT statements.
26
     *
27
     * @var array
28
     *
29
     */
30
    protected $union = array();
31
32
    /**
33
     *
34
     * Is this a SELECT FOR UPDATE?
35
     *
36
     * @var
37
     *
38
     */
39
    protected $for_update = false;
40
41
    /**
42
     *
43
     * The columns to be selected.
44
     *
45
     * @var array
46
     *
47
     */
48
    protected $cols = array();
49
50
    /**
51
     *
52
     * Select from these tables; includes JOIN clauses.
53
     *
54
     * @var array
55
     *
56
     */
57
    protected $from = array();
58
59
    /**
60
     *
61
     * The current key in the `$from` array.
62
     *
63
     * @var int
64
     *
65
     */
66
    protected $from_key = -1;
67
68
    /**
69
     *
70
     * GROUP BY these columns.
71
     *
72
     * @var array
73
     *
74
     */
75
    protected $group_by = array();
76
77
    /**
78
     *
79
     * The list of HAVING conditions.
80
     *
81
     * @var array
82
     *
83
     */
84
    protected $having = array();
85
86
    /**
87
     *
88
     * The page number to select.
89
     *
90
     * @var int
91
     *
92
     */
93
    protected $page = 0;
94
95
    /**
96
     *
97
     * The number of rows per page.
98
     *
99
     * @var int
100
     *
101
     */
102
    protected $paging = 10;
103
104
    /**
105
     *
106
     * Tracks table references to avoid duplicate identifiers.
107
     *
108
     * @var array
109
     *
110
     */
111
    protected $table_refs = array();
112
113
    /**
114
     *
115
     * Returns this query object as an SQL statement string.
116
     *
117
     * @return string An SQL statement string.
118
     *
119
     */
120 174
    public function getStatement()
121
    {
122 174
        $union = '';
123 174
        if ($this->union) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->union of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
124 15
            $union = implode(PHP_EOL, $this->union) . PHP_EOL;
125 15
        }
126 174
        return $union . $this->build();
127
    }
128
129
    /**
130
     *
131
     * Sets the number of rows per page.
132
     *
133
     * @param int $paging The number of rows to page at.
134
     *
135
     * @return $this
136
     *
137
     */
138 10
    public function setPaging($paging)
139
    {
140 10
        $this->paging = (int) $paging;
141 10
        if ($this->page) {
142 5
            $this->setPagingLimitOffset();
143 5
        }
144 10
        return $this;
145
    }
146
147
    /**
148
     *
149
     * Gets the number of rows per page.
150
     *
151
     * @return int The number of rows per page.
152
     *
153
     */
154 10
    public function getPaging()
155
    {
156 10
        return $this->paging;
157
    }
158
159
    /**
160
     *
161
     * Makes the select FOR UPDATE (or not).
162
     *
163
     * @param bool $enable Whether or not the SELECT is FOR UPDATE (default
164
     * true).
165
     *
166
     * @return $this
167
     *
168
     */
169 20
    public function forUpdate($enable = true)
170
    {
171 20
        $this->for_update = (bool) $enable;
172 20
        return $this;
173
    }
174
175
    /**
176
     *
177
     * Makes the select DISTINCT (or not).
178
     *
179
     * @param bool $enable Whether or not the SELECT is DISTINCT (default
180
     * true).
181
     *
182
     * @return $this
183
     *
184
     */
185 16
    public function distinct($enable = true)
186
    {
187 16
        $this->setFlag('DISTINCT', $enable);
188 16
        return $this;
189
    }
190
191
    /**
192
     *
193
     * Adds columns to the query.
194
     *
195
     * Multiple calls to cols() will append to the list of columns, not
196
     * overwrite the previous columns.
197
     *
198
     * @param array $cols The column(s) to add to the query. The elements can be
199
     * any mix of these: `array("col", "col AS alias", "col" => "alias")`
200
     *
201
     * @return $this
202
     *
203
     */
204 214
    public function cols(array $cols)
205
    {
206 214
        foreach ($cols as $key => $val) {
207 214
            $this->addCol($key, $val);
208 214
        }
209 214
        return $this;
210
    }
211
212
    /**
213
     *
214
     * Adds a column and alias to the columns to be selected.
215
     *
216
     * @param mixed $key If an integer, ignored. Otherwise, the column to be
217
     * added.
218
     *
219
     * @param mixed $val If $key was an integer, the column to be added;
220
     * otherwise, the column alias.
221
     *
222
     * @return null
223
     *
224
     */
225 214
    protected function addCol($key, $val)
226
    {
227 214
        if (is_string($key)) {
228
            // [col => alias]
229 25
            $this->cols[$val] = $key;
230 25
        } else {
231 204
            $this->addColWithAlias($val);
232
        }
233 214
    }
234
235
    /**
236
     *
237
     * Adds a column with an alias to the columns to be selected.
238
     *
239
     * @param string $spec The column specification: "col alias",
240
     * "col AS alias", or something else entirely.
241
     *
242
     * @return null
243
     *
244
     */
245 204
    protected function addColWithAlias($spec)
246
    {
247 204
        $parts = explode(' ', $spec);
248 204
        $count = count($parts);
249 204
        if ($count == 2) {
250
            // "col alias"
251 5
            $this->cols[$parts[1]] = $parts[0];
252 204
        } elseif ($count == 3 && strtoupper($parts[1]) == 'AS') {
253
            // "col AS alias"
254 5
            $this->cols[$parts[2]] = $parts[0];
255 5
        } else {
256
            // no recognized alias
257 204
            $this->cols[] = $spec;
258
        }
259 204
    }
260
261
    /**
262
     *
263
     * Remove a column via its alias.
264
     *
265
     * @param string $alias The column to remove
266
     *
267
     * @return null
268
     *
269
     */
270 15
    public function removeCol($alias)
271
    {
272 15
        if (isset($this->cols[$alias])) {
273 5
            unset($this->cols[$alias]);
274
275 5
            return true;
276
        }
277
278 10
        $index = array_search($alias, $this->cols);
279 10
        if ($index !== false) {
280 5
            unset($this->cols[$index]);
281 5
            return true;
282
        }
283
284 5
        return false;
285
    }
286
287
    /**
288
     *
289
     * Does the query have any columns in it?
290
     *
291
     * @return bool
292
     *
293
     */
294 5
    public function hasCols()
295
    {
296 5
        return (bool) $this->cols;
297
    }
298
299
    /**
300
     *
301
     * Returns a list of columns.
302
     *
303
     * @return array
304
     *
305
     */
306 15
    public function getCols()
307
    {
308 15
        return $this->cols;
309
    }
310
311
    /**
312
     *
313
     * Tracks table references.
314
     *
315
     * @param string $type FROM, JOIN, etc.
316
     *
317
     * @param string $spec The table and alias name.
318
     *
319
     * @return null
320
     *
321
     * @throws Exception when the reference has already been used.
322
     *
323
     */
324 139
    protected function addTableRef($type, $spec)
325
    {
326 139
        $name = $spec;
327
328 139
        $pos = strripos($name, ' AS ');
329 139
        if ($pos !== false) {
330 30
            $name = trim(substr($name, $pos + 4));
331 30
        }
332
333 139
        if (isset($this->table_refs[$name])) {
334 25
            $used = $this->table_refs[$name];
335 25
            throw new Exception("Cannot reference '$type $spec' after '$used'");
336
        }
337
338 139
        $this->table_refs[$name] = "$type $spec";
339 139
    }
340
341
    /**
342
     *
343
     * Adds a FROM element to the query; quotes the table name automatically.
344
     *
345
     * @param string $spec The table specification; "foo" or "foo AS bar".
346
     *
347
     * @return $this
348
     *
349
     */
350 129
    public function from($spec)
351
    {
352 129
        $this->addTableRef('FROM', $spec);
353 129
        return $this->addFrom($this->quoter->quoteName($spec));
354
    }
355
356
    /**
357
     *
358
     * Adds a raw unquoted FROM element to the query; useful for adding FROM
359
     * elements that are functions.
360
     *
361
     * @param string $spec The table specification, e.g. "function_name()".
362
     *
363
     * @return $this
364
     *
365
     */
366 5
    public function fromRaw($spec)
367
    {
368 5
        $this->addTableRef('FROM', $spec);
369 5
        return $this->addFrom($spec);
370
    }
371
372
    /**
373
     *
374
     * Adds to the $from property and increments the key count.
375
     *
376
     * @param string $spec The table specification.
377
     *
378
     * @return $this
379
     *
380
     */
381 134
    protected function addFrom($spec)
382
    {
383 134
        $this->from[] = array($spec);
384 134
        $this->from_key ++;
385 134
        return $this;
386
    }
387
388
    /**
389
     *
390
     * Adds an aliased sub-select to the query.
391
     *
392
     * @param string|Select $spec If a Select object, use as the sub-select;
393
     * if a string, the sub-select string.
394
     *
395
     * @param string $name The alias name for the sub-select.
396
     *
397
     * @return $this
398
     *
399
     */
400 15
    public function fromSubSelect($spec, $name)
401
    {
402 15
        $this->addTableRef('FROM (SELECT ...) AS', $name);
403 10
        $spec = $this->subSelect($spec, '        ');
404 10
        $name = $this->quoter->quoteName($name);
405 10
        $this->from[] = array("({$spec}    ) AS $name");
406 10
        $this->from_key ++;
407 10
        return $this;
408
    }
409
410
    /**
411
     *
412
     * Formats a sub-SELECT statement, binding values from a Select object as
413
     * needed.
414
     *
415
     * @param string|SelectInterface $spec A sub-SELECT specification.
416
     *
417
     * @param string $indent Indent each line with this string.
418
     *
419
     * @return string The sub-SELECT string.
420
     *
421
     */
422 20
    protected function subSelect($spec, $indent)
423
    {
424 20
        if ($spec instanceof SelectInterface) {
425 10
            $this->bindValues($spec->getBindValues());
426 10
        }
427
428 20
        return PHP_EOL . $indent
429 20
            . ltrim(preg_replace('/^/m', $indent, (string) $spec))
430 20
            . PHP_EOL;
431
    }
432
433
    /**
434
     *
435
     * Adds a JOIN table and columns to the query.
436
     *
437
     * @param string $join The join type: inner, left, natural, etc.
438
     *
439
     * @param string $spec The table specification; "foo" or "foo AS bar".
440
     *
441
     * @param string $cond Join on this condition.
442
     *
443
     * @param array $bind Values to bind to ?-placeholders in the condition.
444
     *
445
     * @return $this
446
     *
447
     * @throws Exception
448
     *
449
     */
450 40
    public function join($join, $spec, $cond = null, array $bind = array())
451
    {
452 40
        if (! $this->from) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->from of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
453 10
            throw new Exception('Cannot join() without from() first.');
454
        }
455
456 40
        $join = strtoupper(ltrim("$join JOIN"));
457 40
        $this->addTableRef($join, $spec);
458
459 35
        $spec = $this->quoter->quoteName($spec);
460 35
        $cond = $this->fixJoinCondition($cond, $bind);
461 35
        $this->from[$this->from_key][] = rtrim("$join $spec $cond");
462 35
        return $this;
463
    }
464
465
    /**
466
     *
467
     * Fixes a JOIN condition to quote names in the condition and prefix it
468
     * with a condition type ('ON' is the default and 'USING' is recognized).
469
     *
470
     * @param string $cond Join on this condition.
471
     *
472
     * @param array $bind Values to bind to ?-placeholders in the condition.
473
     *
474
     * @return string
475
     *
476
     */
477 45
    protected function fixJoinCondition($cond, array $bind)
478
    {
479 45
        if (! $cond) {
480 15
            return;
481
        }
482
483 45
        $cond = $this->quoter->quoteNamesIn($cond);
484 45
        $cond = $this->rebuildCondAndBindValues($cond, $bind);
485
486 45
        if (strtoupper(substr(ltrim($cond), 0, 3)) == 'ON ') {
487 5
            return $cond;
488
        }
489
490 45
        if (strtoupper(substr(ltrim($cond), 0, 6)) == 'USING ') {
491 5
            return $cond;
492
        }
493
494 40
        return 'ON ' . $cond;
495
    }
496
497
    /**
498
     *
499
     * Adds a INNER JOIN table and columns to the query.
500
     *
501
     * @param string $spec The table specification; "foo" or "foo AS bar".
502
     *
503
     * @param string $cond Join on this condition.
504
     *
505
     * @param array $bind Values to bind to ?-placeholders in the condition.
506
     *
507
     * @return $this
508
     *
509
     * @throws Exception
510
     *
511
     */
512 10
    public function innerJoin($spec, $cond = null, array $bind = array())
513
    {
514 10
        return $this->join('INNER', $spec, $cond, $bind);
515
    }
516
517
    /**
518
     *
519
     * Adds a LEFT JOIN table and columns to the query.
520
     *
521
     * @param string $spec The table specification; "foo" or "foo AS bar".
522
     *
523
     * @param string $cond Join on this condition.
524
     *
525
     * @param array $bind Values to bind to ?-placeholders in the condition.
526
     *
527
     * @return $this
528
     *
529
     * @throws Exception
530
     *
531
     */
532 10
    public function leftJoin($spec, $cond = null, array $bind = array())
533
    {
534 10
        return $this->join('LEFT', $spec, $cond, $bind);
535
    }
536
537
    /**
538
     *
539
     * Adds a JOIN to an aliased subselect and columns to the query.
540
     *
541
     * @param string $join The join type: inner, left, natural, etc.
542
     *
543
     * @param string|Select $spec If a Select
544
     * object, use as the sub-select; if a string, the sub-select
545
     * command string.
546
     *
547
     * @param string $name The alias name for the sub-select.
548
     *
549
     * @param string $cond Join on this condition.
550
     *
551
     * @param array $bind Values to bind to ?-placeholders in the condition.
552
     *
553
     * @return $this
554
     *
555
     * @throws Exception
556
     *
557
     */
558 15
    public function joinSubSelect($join, $spec, $name, $cond = null, array $bind = array())
559
    {
560 15
        if (! $this->from) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->from of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
561 5
            throw new Exception('Cannot join() without from() first.');
562
        }
563
564 15
        $join = strtoupper(ltrim("$join JOIN"));
565 15
        $this->addTableRef("$join (SELECT ...) AS", $name);
566
567 10
        $spec = $this->subSelect($spec, '            ');
568 10
        $name = $this->quoter->quoteName($name);
569 10
        $cond = $this->fixJoinCondition($cond, $bind);
570
571 10
        $text = rtrim("$join ($spec        ) AS $name $cond");
572 10
        $this->from[$this->from_key][] = '        ' . $text ;
573 10
        return $this;
574
    }
575
576
    /**
577
     *
578
     * Adds grouping to the query.
579
     *
580
     * @param array $spec The column(s) to group by.
581
     *
582
     * @return $this
583
     *
584
     */
585 5
    public function groupBy(array $spec)
586
    {
587 5
        foreach ($spec as $col) {
588 5
            $this->group_by[] = $this->quoter->quoteNamesIn($col);
589 5
        }
590 5
        return $this;
591
    }
592
593
    /**
594
     *
595
     * Adds a HAVING condition to the query by AND. If the condition has
596
     * ?-placeholders, additional arguments to the method will be bound to
597
     * those placeholders sequentially.
598
     *
599
     * @param string $cond The HAVING condition.
600
     *
601
     * @return $this
602
     *
603
     */
604 10
    public function having($cond)
605
    {
606 10
        $this->addClauseCondWithBind('having', 'AND', func_get_args());
607 10
        return $this;
608
    }
609
610
    /**
611
     *
612
     * Adds a HAVING condition to the query by AND. If the condition has
613
     * ?-placeholders, additional arguments to the method will be bound to
614
     * those placeholders sequentially.
615
     *
616
     * @param string $cond The HAVING condition.
617
     *
618
     * @return $this
619
     *
620
     * @see having()
621
     *
622
     */
623 5
    public function orHaving($cond)
624
    {
625 5
        $this->addClauseCondWithBind('having', 'OR', func_get_args());
626 5
        return $this;
627
    }
628
629
    /**
630
     *
631
     * Sets the limit and count by page number.
632
     *
633
     * @param int $page Limit results to this page number.
634
     *
635
     * @return $this
636
     *
637
     */
638 25
    public function page($page)
639
    {
640 25
        $this->page = (int) $page;
641 25
        $this->setPagingLimitOffset();
642 25
        return $this;
643
    }
644
645
    /**
646
     *
647
     * Updates the limit and offset values when changing pagination.
648
     *
649
     * @return null
650
     *
651
     */
652 25
    protected function setPagingLimitOffset()
653
    {
654 25
        $this->limit  = 0;
655 25
        $this->offset = 0;
656 25
        if ($this->page) {
657 10
            $this->limit  = $this->paging;
658 10
            $this->offset = $this->paging * ($this->page - 1);
659 10
        }
660 25
    }
661
662
    /**
663
     *
664
     * Returns the page number being selected.
665
     *
666
     * @return int
667
     *
668
     */
669 5
    public function getPage()
670
    {
671 5
        return $this->page;
672
    }
673
674
    /**
675
     *
676
     * Takes the current select properties and retains them, then sets
677
     * UNION for the next set of properties.
678
     *
679
     * @return $this
680
     *
681
     */
682 10
    public function union()
683
    {
684 10
        $this->union[] = $this->build() . PHP_EOL . 'UNION';
685 10
        $this->reset();
686 10
        return $this;
687
    }
688
689
    /**
690
     *
691
     * Takes the current select properties and retains them, then sets
692
     * UNION ALL for the next set of properties.
693
     *
694
     * @return $this
695
     *
696
     */
697 5
    public function unionAll()
698
    {
699 5
        $this->union[] = $this->build() . PHP_EOL . 'UNION ALL';
700 5
        $this->reset();
701 5
        return $this;
702
    }
703
704
    /**
705
     *
706
     * Returns the LIMIT value.
707
     *
708
     * @return int
709
     *
710
     */
711 10
    public function getLimit()
712
    {
713 10
        return $this->limit;
714
    }
715
716
    /**
717
     *
718
     * Returns the OFFSET value.
719
     *
720
     * @return int
721
     *
722
     */
723 10
    public function getOffset()
724
    {
725 10
        return $this->offset;
726
    }
727
728
    /**
729
     *
730
     * Clears the current select properties; generally used after adding a
731
     * union.
732
     *
733
     * @return null
734
     *
735
     */
736 15
    protected function reset()
737
    {
738 15
        $this->resetFlags();
739 15
        $this->resetCols();
740 15
        $this->resetTables();
741 15
        $this->resetWhere();
742 15
        $this->resetGroupBy();
743 15
        $this->resetHaving();
744 15
        $this->resetOrderBy();
745 15
        $this->limit(0);
746 15
        $this->offset(0);
747 15
        $this->page(0);
748 15
        $this->forUpdate(false);
749 15
    }
750
751 15
    public function resetCols()
752
    {
753 15
        $this->cols = array();
754 15
        return $this;
755
    }
756
757 15
    public function resetTables()
758
    {
759 15
        $this->from = array();
760 15
        $this->from_key = -1;
761 15
        $this->table_refs = array();
762 15
        return $this;
763
    }
764
765 15
    public function resetWhere()
766
    {
767 15
        $this->where = array();
768 15
        return $this;
769
    }
770
771 15
    public function resetGroupBy()
772
    {
773 15
        $this->group_by = array();
774 15
        return $this;
775
    }
776
777 15
    public function resetHaving()
778
    {
779 15
        $this->having = array();
780 15
        return $this;
781
    }
782
783 15
    public function resetOrderBy()
784
    {
785 15
        $this->order_by = array();
786 15
        return $this;
787
    }
788
789
    public function resetUnions()
790
    {
791
        $this->union = array();
792
        return $this;
793
    }
794
795
    /**
796
     *
797
     * Builds this query object into a string.
798
     *
799
     * @return string
800
     *
801
     */
802 174
    protected function build()
803
    {
804
        return 'SELECT'
805 174
            . $this->buildFlags()
806 174
            . $this->buildCols()
807 169
            . $this->buildFrom() // includes JOIN
808 169
            . $this->buildWhere()
809 169
            . $this->buildGroupBy()
810 169
            . $this->buildHaving()
811 169
            . $this->buildOrderBy()
812 169
            . $this->buildLimit()
813 169
            . $this->buildForUpdate();
814
    }
815
816
    /**
817
     *
818
     * Builds the columns clause.
819
     *
820
     * @return string
821
     *
822
     * @throws Exception when there are no columns in the SELECT.
823
     *
824
     */
825 174
    protected function buildCols()
826
    {
827 174
        if (! $this->cols) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cols of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
828 5
            throw new Exception('No columns in the SELECT.');
829
        }
830
831 169
        $cols = array();
832 169
        foreach ($this->cols as $key => $val) {
833 169
            if (is_int($key)) {
834 169
                $cols[] = $this->quoter->quoteNamesIn($val);
835 169
            } else {
836 10
                $cols[] = $this->quoter->quoteNamesIn("$val AS $key");
837
            }
838 169
        }
839
840 169
        return $this->indentCsv($cols);
841
    }
842
843
    /**
844
     *
845
     * Builds the FROM clause.
846
     *
847
     * @return string
848
     *
849
     */
850 169
    protected function buildFrom()
851
    {
852 169
        if (! $this->from) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->from of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
853 60
            return ''; // not applicable
854
        }
855
856 109
        $refs = array();
857 109
        foreach ($this->from as $from) {
858 109
            $refs[] = implode(PHP_EOL, $from);
859 109
        }
860 109
        return PHP_EOL . 'FROM' . $this->indentCsv($refs);
861
    }
862
863
    /**
864
     *
865
     * Builds the GROUP BY clause.
866
     *
867
     * @return string
868
     *
869
     */
870 169
    protected function buildGroupBy()
871
    {
872 169
        if (! $this->group_by) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->group_by of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
873 164
            return ''; // not applicable
874
        }
875
876 5
        return PHP_EOL . 'GROUP BY' . $this->indentCsv($this->group_by);
877
    }
878
879
    /**
880
     *
881
     * Builds the HAVING clause.
882
     *
883
     * @return string
884
     *
885
     */
886 169
    protected function buildHaving()
887
    {
888 169
        if (! $this->having) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->having of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
889 154
            return ''; // not applicable
890
        }
891
892 15
        return PHP_EOL . 'HAVING' . $this->indent($this->having);
893
    }
894
895
    /**
896
     *
897
     * Builds the FOR UPDATE clause.
898
     *
899
     * @return string
900
     *
901
     */
902 169
    protected function buildForUpdate()
903
    {
904 169
        if (! $this->for_update) {
905 164
            return ''; // not applicable
906
        }
907
908 5
        return PHP_EOL . 'FOR UPDATE';
909
    }
910
911
    /**
912
     *
913
     * Adds a WHERE condition to the query by AND. If the condition has
914
     * ?-placeholders, additional arguments to the method will be bound to
915
     * those placeholders sequentially.
916
     *
917
     * @param string $cond The WHERE condition.
918
     * @param mixed ...$bind arguments to bind to placeholders
919
     *
920
     * @return $this
921
     *
922
     */
923 30
    public function where($cond)
924
    {
925 30
        $this->addWhere('AND', func_get_args());
926 30
        return $this;
927
    }
928
929
    /**
930
     *
931
     * Adds a WHERE condition to the query by OR. If the condition has
932
     * ?-placeholders, additional arguments to the method will be bound to
933
     * those placeholders sequentially.
934
     *
935
     * @param string $cond The WHERE condition.
936
     * @param mixed ...$bind arguments to bind to placeholders
937
     *
938
     * @return $this
939
     *
940
     * @see where()
941
     *
942
     */
943 5
    public function orWhere($cond)
944
    {
945 5
        $this->addWhere('OR', func_get_args());
946 5
        return $this;
947
    }
948
949
    /**
950
     *
951
     * Sets a limit count on the query.
952
     *
953
     * @param int $limit The number of rows to select.
954
     *
955
     * @return $this
956
     *
957
     */
958 30
    public function limit($limit)
959
    {
960 30
        $this->limit = (int) $limit;
961 30
        if ($this->page) {
962 5
            $this->page = 0;
963 5
            $this->offset = 0;
964 5
        }
965 30
        return $this;
966
    }
967
968
    /**
969
     *
970
     * Sets a limit offset on the query.
971
     *
972
     * @param int $offset Start returning after this many rows.
973
     *
974
     * @return $this
975
     *
976
     */
977 30
    public function offset($offset)
978
    {
979 30
        $this->offset = (int) $offset;
980 30
        if ($this->page) {
981 5
            $this->page = 0;
982 5
            $this->limit = 0;
983 5
        }
984 30
        return $this;
985
    }
986
987
    /**
988
     *
989
     * Adds a column order to the query.
990
     *
991
     * @param array $spec The columns and direction to order by.
992
     *
993
     * @return $this
994
     *
995
     */
996 5
    public function orderBy(array $spec)
997
    {
998 5
        return $this->addOrderBy($spec);
999
    }
1000
}
1001