Completed
Pull Request — 3.x (#112)
by
unknown
01:39
created

Select::resetWhere()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 0
crap 1
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
     * Tracks which JOIN clauses are attached to which FROM tables.
71
     *
72
     * @var array
73
     *
74
     */
75
    protected $join = array();
76
77
    /**
78
     *
79
     * GROUP BY these columns.
80
     *
81
     * @var array
82
     *
83
     */
84
    protected $group_by = array();
85
86
    /**
87
     *
88
     * The list of HAVING conditions.
89
     *
90
     * @var array
91
     *
92
     */
93
    protected $having = array();
94
95
    /**
96
     *
97
     * The page number to select.
98
     *
99
     * @var int
100
     *
101
     */
102
    protected $page = 0;
103
104
    /**
105
     *
106
     * The number of rows per page.
107
     *
108
     * @var int
109
     *
110
     */
111
    protected $paging = 10;
112
113
    /**
114
     *
115
     * Tracks table references to avoid duplicate identifiers.
116
     *
117
     * @var array
118
     *
119
     */
120
    protected $table_refs = array();
121
122
    /**
123
     *
124
     * Returns this query object as an SQL statement string.
125
     *
126
     * @return string An SQL statement string.
127
     *
128
     */
129 184
    public function getStatement()
130
    {
131 184
        $union = '';
132 184
        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...
133 15
            $union = implode(PHP_EOL, $this->union) . PHP_EOL;
134 15
        }
135 184
        return $union . $this->build();
136
    }
137
138
    /**
139
     *
140
     * Sets the number of rows per page.
141
     *
142
     * @param int $paging The number of rows to page at.
143
     *
144
     * @return $this
145
     *
146
     */
147 10
    public function setPaging($paging)
148
    {
149 10
        $this->paging = (int) $paging;
150 10
        if ($this->page) {
151 5
            $this->setPagingLimitOffset();
152 5
        }
153 10
        return $this;
154
    }
155
156
    /**
157
     *
158
     * Gets the number of rows per page.
159
     *
160
     * @return int The number of rows per page.
161
     *
162
     */
163 10
    public function getPaging()
164
    {
165 10
        return $this->paging;
166
    }
167
168
    /**
169
     *
170
     * Makes the select FOR UPDATE (or not).
171
     *
172
     * @param bool $enable Whether or not the SELECT is FOR UPDATE (default
173
     * true).
174
     *
175
     * @return $this
176
     *
177
     */
178 20
    public function forUpdate($enable = true)
179
    {
180 20
        $this->for_update = (bool) $enable;
181 20
        return $this;
182
    }
183
184
    /**
185
     *
186
     * Makes the select DISTINCT (or not).
187
     *
188
     * @param bool $enable Whether or not the SELECT is DISTINCT (default
189
     * true).
190
     *
191
     * @return $this
192
     *
193
     */
194 16
    public function distinct($enable = true)
195
    {
196 16
        $this->setFlag('DISTINCT', $enable);
197 16
        return $this;
198
    }
199
200
    /**
201
     *
202
     * Is the select DISTINCT?
203
     *
204
     * @return bool
205
     *
206
     */
207 10
    public function isDistinct()
208
    {
209 10
        return $this->hasFlag('DISTINCT');
210
    }
211
212
    /**
213
     *
214
     * Adds columns to the query.
215
     *
216
     * Multiple calls to cols() will append to the list of columns, not
217
     * overwrite the previous columns.
218
     *
219
     * @param array $cols The column(s) to add to the query. The elements can be
220
     * any mix of these: `array("col", "col AS alias", "col" => "alias")`
221
     *
222
     * @return $this
223
     *
224
     */
225 224
    public function cols(array $cols)
226
    {
227 224
        foreach ($cols as $key => $val) {
228 224
            $this->addCol($key, $val);
229 224
        }
230 224
        return $this;
231
    }
232
233
    /**
234
     *
235
     * Adds a column and alias to the columns to be selected.
236
     *
237
     * @param mixed $key If an integer, ignored. Otherwise, the column to be
238
     * added.
239
     *
240
     * @param mixed $val If $key was an integer, the column to be added;
241
     * otherwise, the column alias.
242
     *
243
     * @return null
244
     *
245
     */
246 224
    protected function addCol($key, $val)
247
    {
248 224
        if (is_string($key)) {
249
            // [col => alias]
250 25
            $this->cols[$val] = $key;
251 25
        } else {
252 214
            $this->addColWithAlias($val);
253
        }
254 224
    }
255
256
    /**
257
     *
258
     * Adds a column with an alias to the columns to be selected.
259
     *
260
     * @param string $spec The column specification: "col alias",
261
     * "col AS alias", or something else entirely.
262
     *
263
     * @return null
264
     *
265
     */
266 214
    protected function addColWithAlias($spec)
267
    {
268 214
        $parts = explode(' ', $spec);
269 214
        $count = count($parts);
270 214
        if ($count == 2) {
271
            // "col alias"
272 5
            $this->cols[$parts[1]] = $parts[0];
273 214
        } elseif ($count == 3 && strtoupper($parts[1]) == 'AS') {
274
            // "col AS alias"
275 5
            $this->cols[$parts[2]] = $parts[0];
276 5
        } else {
277
            // no recognized alias
278 214
            $this->cols[] = $spec;
279
        }
280 214
    }
281
282
    /**
283
     *
284
     * Remove a column via its alias.
285
     *
286
     * @param string $alias The column to remove
287
     *
288
     * @return null
289
     *
290
     */
291 15
    public function removeCol($alias)
292
    {
293 15
        if (isset($this->cols[$alias])) {
294 5
            unset($this->cols[$alias]);
295
296 5
            return true;
297
        }
298
299 10
        $index = array_search($alias, $this->cols);
300 10
        if ($index !== false) {
301 5
            unset($this->cols[$index]);
302 5
            return true;
303
        }
304
305 5
        return false;
306
    }
307
308
    /**
309
     *
310
     * Does the query have any columns in it?
311
     *
312
     * @return bool
313
     *
314
     */
315 5
    public function hasCols()
316
    {
317 5
        return (bool) $this->cols;
318
    }
319
320
    /**
321
     *
322
     * Returns a list of columns.
323
     *
324
     * @return array
325
     *
326
     */
327 15
    public function getCols()
328
    {
329 15
        return $this->cols;
330
    }
331
332
    /**
333
     *
334
     * Tracks table references.
335
     *
336
     * @param string $type FROM, JOIN, etc.
337
     *
338
     * @param string $spec The table and alias name.
339
     *
340
     * @return null
341
     *
342
     * @throws Exception when the reference has already been used.
343
     *
344
     */
345 149
    protected function addTableRef($type, $spec)
346
    {
347 149
        $name = $spec;
348
349 149
        $pos = strripos($name, ' AS ');
350 149
        if ($pos !== false) {
351 35
            $name = trim(substr($name, $pos + 4));
352 35
        }
353
354 149
        if (isset($this->table_refs[$name])) {
355 25
            $used = $this->table_refs[$name];
356 25
            throw new Exception("Cannot reference '$type $spec' after '$used'");
357
        }
358
359 149
        $this->table_refs[$name] = "$type $spec";
360 149
    }
361
362
    /**
363
     *
364
     * Adds a FROM element to the query; quotes the table name automatically.
365
     *
366
     * @param string $spec The table specification; "foo" or "foo AS bar".
367
     *
368
     * @return $this
369
     *
370
     */
371 139
    public function from($spec)
372
    {
373 139
        $this->addTableRef('FROM', $spec);
374 139
        return $this->addFrom($this->quoter->quoteName($spec));
0 ignored issues
show
Bug introduced by
It seems like $this->quoter->quoteName($spec) targeting Aura\SqlQuery\Quoter::quoteName() can also be of type array; however, Aura\SqlQuery\Common\Select::addFrom() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
375
    }
376
377
    /**
378
     *
379
     * Adds a raw unquoted FROM element to the query; useful for adding FROM
380
     * elements that are functions.
381
     *
382
     * @param string $spec The table specification, e.g. "function_name()".
383
     *
384
     * @return $this
385
     *
386
     */
387 5
    public function fromRaw($spec)
388
    {
389 5
        $this->addTableRef('FROM', $spec);
390 5
        return $this->addFrom($spec);
391
    }
392
393
    /**
394
     *
395
     * Adds to the $from property and increments the key count.
396
     *
397
     * @param string $spec The table specification.
398
     *
399
     * @return $this
400
     *
401
     */
402 149
    protected function addFrom($spec)
403
    {
404 149
        $this->from[] = array($spec);
405 149
        $this->from_key ++;
406 149
        return $this;
407
    }
408
409
    /**
410
     *
411
     * Adds an aliased sub-select to the query.
412
     *
413
     * @param string|Select $spec If a Select object, use as the sub-select;
414
     * if a string, the sub-select string.
415
     *
416
     * @param string $name The alias name for the sub-select.
417
     *
418
     * @return $this
419
     *
420
     */
421 15
    public function fromSubSelect($spec, $name)
422
    {
423 15
        $this->addTableRef('FROM (SELECT ...) AS', $name);
424 10
        $spec = $this->subSelect($spec, '        ');
425 10
        $name = $this->quoter->quoteName($name);
426 10
        return $this->addFrom("({$spec}    ) AS $name");
427
    }
428
429
    /**
430
     *
431
     * Formats a sub-SELECT statement, binding values from a Select object as
432
     * needed.
433
     *
434
     * @param string|SelectInterface $spec A sub-SELECT specification.
435
     *
436
     * @param string $indent Indent each line with this string.
437
     *
438
     * @return string The sub-SELECT string.
439
     *
440
     */
441 25
    protected function subSelect($spec, $indent)
442
    {
443 25
        if ($spec instanceof SelectInterface) {
444 10
            $this->bindValues($spec->getBindValues());
445 10
        }
446
447 25
        return PHP_EOL . $indent
448 25
            . ltrim(preg_replace('/^/m', $indent, (string) $spec))
449 25
            . PHP_EOL;
450
    }
451
452
    /**
453
     *
454
     * Adds a JOIN table and columns to the query.
455
     *
456
     * @param string $join The join type: inner, left, natural, etc.
457
     *
458
     * @param string $spec The table specification; "foo" or "foo AS bar".
459
     *
460
     * @param string $cond Join on this condition.
461
     *
462
     * @param array $bind Values to bind to ?-placeholders in the condition.
463
     *
464
     * @return $this
465
     *
466
     * @throws Exception
467
     *
468
     */
469 45
    public function join($join, $spec, $cond = null, array $bind = array())
470
    {
471 45
        $join = strtoupper(ltrim("$join JOIN"));
472 45
        $this->addTableRef($join, $spec);
473
474 40
        $spec = $this->quoter->quoteName($spec);
475 40
        $cond = $this->fixJoinCondition($cond, $bind);
476 40
        return $this->addJoin(rtrim("$join $spec $cond"));
477
    }
478
479
    /**
480
     *
481
     * Fixes a JOIN condition to quote names in the condition and prefix it
482
     * with a condition type ('ON' is the default and 'USING' is recognized).
483
     *
484
     * @param string $cond Join on this condition.
485
     *
486
     * @param array $bind Values to bind to ?-placeholders in the condition.
487
     *
488
     * @return string
489
     *
490
     */
491 55
    protected function fixJoinCondition($cond, array $bind)
492
    {
493 55
        if (! $cond) {
494 25
            return;
495
        }
496
497 55
        $cond = $this->quoter->quoteNamesIn($cond);
498 55
        $cond = $this->rebuildCondAndBindValues($cond, $bind);
499
500 55
        if (strtoupper(substr(ltrim($cond), 0, 3)) == 'ON ') {
501 5
            return $cond;
502
        }
503
504 55
        if (strtoupper(substr(ltrim($cond), 0, 6)) == 'USING ') {
505 5
            return $cond;
506
        }
507
508 50
        return 'ON ' . $cond;
509
    }
510
511
    /**
512
     *
513
     * Adds a INNER JOIN table and columns to the query.
514
     *
515
     * @param string $spec The table specification; "foo" or "foo AS bar".
516
     *
517
     * @param string $cond Join on this condition.
518
     *
519
     * @param array $bind Values to bind to ?-placeholders in the condition.
520
     *
521
     * @return $this
522
     *
523
     * @throws Exception
524
     *
525
     */
526 10
    public function innerJoin($spec, $cond = null, array $bind = array())
527
    {
528 10
        return $this->join('INNER', $spec, $cond, $bind);
529
    }
530
531
    /**
532
     *
533
     * Adds a LEFT JOIN table and columns to the query.
534
     *
535
     * @param string $spec The table specification; "foo" or "foo AS bar".
536
     *
537
     * @param string $cond Join on this condition.
538
     *
539
     * @param array $bind Values to bind to ?-placeholders in the condition.
540
     *
541
     * @return $this
542
     *
543
     * @throws Exception
544
     *
545
     */
546 10
    public function leftJoin($spec, $cond = null, array $bind = array())
547
    {
548 10
        return $this->join('LEFT', $spec, $cond, $bind);
549
    }
550
551
    /**
552
     *
553
     * Adds a JOIN to an aliased subselect and columns to the query.
554
     *
555
     * @param string $join The join type: inner, left, natural, etc.
556
     *
557
     * @param string|Select $spec If a Select
558
     * object, use as the sub-select; if a string, the sub-select
559
     * command string.
560
     *
561
     * @param string $name The alias name for the sub-select.
562
     *
563
     * @param string $cond Join on this condition.
564
     *
565
     * @param array $bind Values to bind to ?-placeholders in the condition.
566
     *
567
     * @return $this
568
     *
569
     * @throws Exception
570
     *
571
     */
572 20
    public function joinSubSelect($join, $spec, $name, $cond = null, array $bind = array())
573
    {
574 20
        $join = strtoupper(ltrim("$join JOIN"));
575 20
        $this->addTableRef("$join (SELECT ...) AS", $name);
576
577 15
        $spec = $this->subSelect($spec, '            ');
578 15
        $name = $this->quoter->quoteName($name);
579 15
        $cond = $this->fixJoinCondition($cond, $bind);
580
581 15
        $text = rtrim("$join ($spec        ) AS $name $cond");
582 15
        return $this->addJoin('        ' . $text);
583
    }
584
585
    /**
586
     *
587
     * Adds the JOIN to the right place, given whether or not a FROM has been
588
     * specified yet.
589
     *
590
     * @param string $spec The JOIN clause.
591
     *
592
     * @return $this
593
     *
594
     */
595 55
    protected function addJoin($spec)
596
    {
597 55
        $from_key = ($this->from_key == -1) ? 0 : $this->from_key;
598 55
        $this->join[$from_key][] = $spec;
599 55
        return $this;
600
    }
601
602
    /**
603
     *
604
     * Adds grouping to the query.
605
     *
606
     * @param array $spec The column(s) to group by.
607
     *
608
     * @return $this
609
     *
610
     */
611 5
    public function groupBy(array $spec)
612
    {
613 5
        foreach ($spec as $col) {
614 5
            $this->group_by[] = $this->quoter->quoteNamesIn($col);
615 5
        }
616 5
        return $this;
617
    }
618
619
    /**
620
     *
621
     * Adds a HAVING condition to the query by AND. If the condition has
622
     * ?-placeholders, additional arguments to the method will be bound to
623
     * those placeholders sequentially.
624
     *
625
     * @param string $cond The HAVING condition.
626
     *
627
     * @return $this
628
     *
629
     */
630 10
    public function having($cond)
631
    {
632 10
        $this->addClauseCondWithBind('having', 'AND', func_get_args());
633 10
        return $this;
634
    }
635
636
    /**
637
     *
638
     * Adds a HAVING condition to the query by AND. If the condition has
639
     * ?-placeholders, additional arguments to the method will be bound to
640
     * those placeholders sequentially.
641
     *
642
     * @param string $cond The HAVING condition.
643
     *
644
     * @return $this
645
     *
646
     * @see having()
647
     *
648
     */
649 5
    public function orHaving($cond)
650
    {
651 5
        $this->addClauseCondWithBind('having', 'OR', func_get_args());
652 5
        return $this;
653
    }
654
655
    /**
656
     *
657
     * Sets the limit and count by page number.
658
     *
659
     * @param int $page Limit results to this page number.
660
     *
661
     * @return $this
662
     *
663
     */
664 25
    public function page($page)
665
    {
666 25
        $this->page = (int) $page;
667 25
        $this->setPagingLimitOffset();
668 25
        return $this;
669
    }
670
671
    /**
672
     *
673
     * Updates the limit and offset values when changing pagination.
674
     *
675
     * @return null
676
     *
677
     */
678 25
    protected function setPagingLimitOffset()
679
    {
680 25
        $this->limit  = 0;
681 25
        $this->offset = 0;
682 25
        if ($this->page) {
683 10
            $this->limit  = $this->paging;
684 10
            $this->offset = $this->paging * ($this->page - 1);
685 10
        }
686 25
    }
687
688
    /**
689
     *
690
     * Returns the page number being selected.
691
     *
692
     * @return int
693
     *
694
     */
695 5
    public function getPage()
696
    {
697 5
        return $this->page;
698
    }
699
700
    /**
701
     *
702
     * Takes the current select properties and retains them, then sets
703
     * UNION for the next set of properties.
704
     *
705
     * @return $this
706
     *
707
     */
708 10
    public function union()
709
    {
710 10
        $this->union[] = $this->build() . PHP_EOL . 'UNION';
711 10
        $this->reset();
712 10
        return $this;
713
    }
714
715
    /**
716
     *
717
     * Takes the current select properties and retains them, then sets
718
     * UNION ALL for the next set of properties.
719
     *
720
     * @return $this
721
     *
722
     */
723 5
    public function unionAll()
724
    {
725 5
        $this->union[] = $this->build() . PHP_EOL . 'UNION ALL';
726 5
        $this->reset();
727 5
        return $this;
728
    }
729
730
    /**
731
     *
732
     * Returns the LIMIT value.
733
     *
734
     * @return int
735
     *
736
     */
737 10
    public function getLimit()
738
    {
739 10
        return $this->limit;
740
    }
741
742
    /**
743
     *
744
     * Returns the OFFSET value.
745
     *
746
     * @return int
747
     *
748
     */
749 10
    public function getOffset()
750
    {
751 10
        return $this->offset;
752
    }
753
754
    /**
755
     *
756
     * Clears the current select properties; generally used after adding a
757
     * union.
758
     *
759
     * @return null
760
     *
761
     */
762 15
    public function reset()
763
    {
764 15
        $this->resetFlags();
765 15
        $this->resetCols();
766 15
        $this->resetTables();
767 15
        $this->resetWhere();
768 15
        $this->resetGroupBy();
769 15
        $this->resetHaving();
770 15
        $this->resetOrderBy();
771 15
        $this->limit(0);
772 15
        $this->offset(0);
773 15
        $this->page(0);
774 15
        $this->forUpdate(false);
775 15
    }
776
777
    /**
778
     *
779
     * Resets the columns on the SELECT.
780
     *
781
     * @return $this
782
     *
783
     */
784 15
    public function resetCols()
785
    {
786 15
        $this->cols = array();
787 15
        return $this;
788
    }
789
790
    /**
791
     *
792
     * Resets the FROM and JOIN clauses on the SELECT.
793
     *
794
     * @return $this
795
     *
796
     */
797 15
    public function resetTables()
798
    {
799 15
        $this->from = array();
800 15
        $this->from_key = -1;
801 15
        $this->join = array();
802 15
        $this->table_refs = array();
803 15
        return $this;
804
    }
805
806
    /**
807
     *
808
     * Resets the WHERE clause on the SELECT.
809
     *
810
     * @return $this
811
     *
812
     */
813 15
    public function resetWhere()
814
    {
815 15
        $this->where = array();
816 15
        return $this;
817
    }
818
819
    /**
820
     *
821
     * Resets the GROUP BY clause on the SELECT.
822
     *
823
     * @return $this
824
     *
825
     */
826 15
    public function resetGroupBy()
827
    {
828 15
        $this->group_by = array();
829 15
        return $this;
830
    }
831
832
    /**
833
     *
834
     * Resets the HAVING clause on the SELECT.
835
     *
836
     * @return $this
837
     *
838
     */
839 15
    public function resetHaving()
840
    {
841 15
        $this->having = array();
842 15
        return $this;
843
    }
844
845
    /**
846
     *
847
     * Resets the ORDER BY clause on the SELECT.
848
     *
849
     * @return $this
850
     *
851
     */
852 15
    public function resetOrderBy()
853
    {
854 15
        $this->order_by = array();
855 15
        return $this;
856
    }
857
858
    /**
859
     *
860
     * Resets the UNION and UNION ALL clauses on the SELECT.
861
     *
862
     * @return $this
863
     *
864
     */
865
    public function resetUnions()
866
    {
867
        $this->union = array();
868
        return $this;
869
    }
870
871
    /**
872
     *
873
     * Builds this query object into a string.
874
     *
875
     * @return string
876
     *
877
     */
878 184
    protected function build()
879
    {
880
        return 'SELECT'
881 184
            . $this->buildFlags()
882 184
            . $this->buildCols()
883 179
            . $this->buildFrom() // includes JOIN
884 179
            . $this->buildWhere()
885 179
            . $this->buildGroupBy()
886 179
            . $this->buildHaving()
887 179
            . $this->buildOrderBy()
888 179
            . $this->buildLimit()
889 179
            . $this->buildForUpdate();
890
    }
891
892
    /**
893
     *
894
     * Builds the columns clause.
895
     *
896
     * @return string
897
     *
898
     * @throws Exception when there are no columns in the SELECT.
899
     *
900
     */
901 184
    protected function buildCols()
902
    {
903 184
        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...
904 5
            throw new Exception('No columns in the SELECT.');
905
        }
906
907 179
        $cols = array();
908 179
        foreach ($this->cols as $key => $val) {
909 179
            if (is_int($key)) {
910 179
                $cols[] = $this->quoter->quoteNamesIn($val);
911 179
            } else {
912 10
                $cols[] = $this->quoter->quoteNamesIn("$val AS $key");
913
            }
914 179
        }
915
916 179
        return $this->indentCsv($cols);
917
    }
918
919
    /**
920
     *
921
     * Builds the FROM clause.
922
     *
923
     * @return string
924
     *
925
     */
926 179
    protected function buildFrom()
927
    {
928 179
        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...
929 60
            return ''; // not applicable
930
        }
931
932 119
        $refs = array();
933 119
        foreach ($this->from as $from_key => $from) {
934 119
            if (isset($this->join[$from_key])) {
935 55
                $from = array_merge($from, $this->join[$from_key]);
936 55
            }
937 119
            $refs[] = implode(PHP_EOL, $from);
938 119
        }
939 119
        return PHP_EOL . 'FROM' . $this->indentCsv($refs);
940
    }
941
942
    /**
943
     *
944
     * Builds the GROUP BY clause.
945
     *
946
     * @return string
947
     *
948
     */
949 179
    protected function buildGroupBy()
950
    {
951 179
        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...
952 174
            return ''; // not applicable
953
        }
954
955 5
        return PHP_EOL . 'GROUP BY' . $this->indentCsv($this->group_by);
956
    }
957
958
    /**
959
     *
960
     * Builds the HAVING clause.
961
     *
962
     * @return string
963
     *
964
     */
965 179
    protected function buildHaving()
966
    {
967 179
        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...
968 164
            return ''; // not applicable
969
        }
970
971 15
        return PHP_EOL . 'HAVING' . $this->indent($this->having);
972
    }
973
974
    /**
975
     *
976
     * Builds the FOR UPDATE clause.
977
     *
978
     * @return string
979
     *
980
     */
981 179
    protected function buildForUpdate()
982
    {
983 179
        if (! $this->for_update) {
984 174
            return ''; // not applicable
985
        }
986
987 5
        return PHP_EOL . 'FOR UPDATE';
988
    }
989
990
    /**
991
     *
992
     * Adds a WHERE condition to the query by AND. If the condition has
993
     * ?-placeholders, additional arguments to the method will be bound to
994
     * those placeholders sequentially.
995
     *
996
     * @param string $cond The WHERE condition.
997
     * @param mixed ...$bind arguments to bind to placeholders
998
     *
999
     * @return $this
1000
     *
1001
     */
1002 30
    public function where($cond)
1003
    {
1004 30
        $this->addWhere('AND', func_get_args());
1005 30
        return $this;
1006
    }
1007
1008
    /**
1009
     *
1010
     * Adds a WHERE condition to the query by OR. If the condition has
1011
     * ?-placeholders, additional arguments to the method will be bound to
1012
     * those placeholders sequentially.
1013
     *
1014
     * @param string $cond The WHERE condition.
1015
     * @param mixed ...$bind arguments to bind to placeholders
1016
     *
1017
     * @return $this
1018
     *
1019
     * @see where()
1020
     *
1021
     */
1022 5
    public function orWhere($cond)
1023
    {
1024 5
        $this->addWhere('OR', func_get_args());
1025 5
        return $this;
1026
    }
1027
1028
    /**
1029
     *
1030
     * Sets a limit count on the query.
1031
     *
1032
     * @param int $limit The number of rows to select.
1033
     *
1034
     * @return $this
1035
     *
1036
     */
1037 30
    public function limit($limit)
1038
    {
1039 30
        $this->limit = (int) $limit;
1040 30
        if ($this->page) {
1041 5
            $this->page = 0;
1042 5
            $this->offset = 0;
1043 5
        }
1044 30
        return $this;
1045
    }
1046
1047
    /**
1048
     *
1049
     * Sets a limit offset on the query.
1050
     *
1051
     * @param int $offset Start returning after this many rows.
1052
     *
1053
     * @return $this
1054
     *
1055
     */
1056 30
    public function offset($offset)
1057
    {
1058 30
        $this->offset = (int) $offset;
1059 30
        if ($this->page) {
1060 5
            $this->page = 0;
1061 5
            $this->limit = 0;
1062 5
        }
1063 30
        return $this;
1064
    }
1065
1066
    /**
1067
     *
1068
     * Adds a column order to the query.
1069
     *
1070
     * @param array $spec The columns and direction to order by.
1071
     *
1072
     * @return $this
1073
     *
1074
     */
1075 5
    public function orderBy(array $spec)
1076
    {
1077 5
        return $this->addOrderBy($spec);
1078
    }
1079
}
1080