Completed
Push — master ( a4c193...4ecd26 )
by Anton
10s
created

Select::setPage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 8
ccs 4
cts 5
cp 0.8
crap 2.032
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Bluz Framework Component
4
 *
5
 * @copyright Bluz PHP Team
6
 * @link https://github.com/bluzphp/framework
7
 */
8
9
declare(strict_types=1);
10
11
namespace Bluz\Db\Query;
12
13
use Bluz\Db\Exception\DbException;
14
use Bluz\Proxy\Db;
15
16
/**
17
 * Builder of SELECT queries
18
 *
19
 * @package Bluz\Db\Query
20
 */
21
class Select extends AbstractBuilder
22
{
23
    use Traits\From;
24
    use Traits\Where;
25
    use Traits\Order;
26
    use Traits\Limit;
27
28
    /**
29
     * @var mixed PDO fetch types or object class
30
     */
31
    protected $fetchType = \PDO::FETCH_ASSOC;
32
33
    /**
34
     * {@inheritdoc}
35
     *
36
     * @param  integer|string|object $fetchType
37
     * @return integer|string|array
38
     */
39 2
    public function execute($fetchType = null)
40
    {
41 2
        if (!$fetchType) {
42 2
            $fetchType = $this->fetchType;
43
        }
44
45
        switch ($fetchType) {
46 2
            case (!is_int($fetchType)):
47 1
                return Db::fetchObjects($this->getSql(), $this->params, $fetchType);
48 1
            case \PDO::FETCH_CLASS:
49
                return Db::fetchObjects($this->getSql(), $this->params);
50 1
            case \PDO::FETCH_ASSOC:
51
            default:
52 1
                return Db::fetchAll($this->getSql(), $this->params);
53
        }
54
    }
55
56
    /**
57
     * Setup fetch type, any of PDO, or any Class
58
     *
59
     * @param  string $fetchType
60
     * @return Select instance
61
     */
62 1
    public function setFetchType($fetchType)
63
    {
64 1
        $this->fetchType = $fetchType;
65 1
        return $this;
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     *
71
     * @return string
72
     */
73 7
    public function getSql()
74
    {
75 7
        $query = "SELECT " . implode(', ', $this->sqlParts['select']) . " FROM ";
76
77 7
        $fromClauses = [];
78
79
        // Loop through all FROM clauses
80 7
        foreach ($this->sqlParts['from'] as $from) {
81 7
            $fromClause = $from['table'] . ' ' . $from['alias']
82 7
                . $this->getSQLForJoins($from['alias']);
83
84 7
            $fromClauses[$from['alias']] = $fromClause;
85
        }
86
87 7
        $query .= join(', ', $fromClauses)
88 7
            . ($this->sqlParts['where'] !== null ? " WHERE " . ((string) $this->sqlParts['where']) : "")
89 7
            . ($this->sqlParts['groupBy'] ? " GROUP BY " . join(", ", $this->sqlParts['groupBy']) : "")
90 7
            . ($this->sqlParts['having'] !== null ? " HAVING " . ((string) $this->sqlParts['having']) : "")
91 7
            . ($this->sqlParts['orderBy'] ? " ORDER BY " . join(", ", $this->sqlParts['orderBy']) : "")
92 7
            . ($this->limit ? " LIMIT ". $this->limit ." OFFSET ". $this->offset : "")
93
        ;
94
95 7
        return $query;
96
    }
97
98
    /**
99
     * Specifies an item that is to be returned in the query result
100
     * Replaces any previously specified selections, if any
101
     *
102
     * Example
103
     * <code>
104
     *     $sb = new Select();
105
     *     $sb
106
     *         ->select('u.id', 'p.id')
107
     *         ->from('users', 'u')
108
     *         ->leftJoin('u', 'phone', 'p', 'u.id = p.user_id');
109
     * </code>
110
     *
111
     * @param  string[] $select the selection expressions
112
     * @return Select instance
113
     */
114 8
    public function select(...$select)
115
    {
116 8
        return $this->addQueryPart('select', $select, false);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addQueryPart('select', $select, false); of type Bluz\Db\Query\Select|Bluz\Db\Query\Delete adds the type Bluz\Db\Query\Delete to the return on line 116 which is incompatible with the return type documented by Bluz\Db\Query\Select::select of type Bluz\Db\Query\Select.
Loading history...
117
    }
118
119
    /**
120
     * Adds an item that is to be returned in the query result.
121
     *
122
     * Example
123
     * <code>
124
     *     $sb = new Select();
125
     *     $sb
126
     *         ->select('u.id')
127
     *         ->addSelect('p.id')
128
     *         ->from('users', 'u')
129
     *         ->leftJoin('u', 'phone', 'u.id = p.user_id');
130
     * </code>
131
     *
132
     * @param  string $select the selection expression
133
     * @return Select instance
134
     */
135 1
    public function addSelect($select)
136
    {
137 1
        return $this->addQueryPart('select', $select, true);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addQueryPart('select', $select, true); of type Bluz\Db\Query\Select|Bluz\Db\Query\Delete adds the type Bluz\Db\Query\Delete to the return on line 137 which is incompatible with the return type documented by Bluz\Db\Query\Select::addSelect of type Bluz\Db\Query\Select.
Loading history...
138
    }
139
140
    /**
141
     * Creates and adds a join to the query
142
     *
143
     * Example
144
     * <code>
145
     *     $sb = new Select();
146
     *     $sb
147
     *         ->select('u.name')
148
     *         ->from('users', 'u')
149
     *         ->join('u', 'phone', 'p', 'p.is_primary = 1');
150
     * </code>
151
     *
152
     * @param  string $fromAlias the alias that points to a from clause
153
     * @param  string $join      the table name to join
154
     * @param  string $alias     the alias of the join table
155
     * @param  string $condition the condition for the join
156
     * @return Select instance
157
     */
158 2
    public function join($fromAlias, $join, $alias, $condition = null)
159
    {
160 2
        return $this->innerJoin($fromAlias, $join, $alias, $condition);
161
    }
162
163
    /**
164
     * Creates and adds a join to the query
165
     *
166
     * Example
167
     * <code>
168
     *     $sb = new Select();
169
     *     $sb
170
     *         ->select('u.name')
171
     *         ->from('users', 'u')
172
     *         ->innerJoin('u', 'phone', 'p', 'p.is_primary = 1');
173
     * </code>
174
     *
175
     * @param  string $fromAlias the alias that points to a from clause
176
     * @param  string $join      the table name to join
177
     * @param  string $alias     the alias of the join table
178
     * @param  string $condition the condition for the join
179
     * @return Select instance
180
     */
181 2
    public function innerJoin($fromAlias, $join, $alias, $condition = null)
182
    {
183 2
        $this->aliases[] = $alias;
184
185 2
        return $this->addQueryPart(
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addQueryPart('joi...=> $condition)), true); of type Bluz\Db\Query\Select|Bluz\Db\Query\Delete adds the type Bluz\Db\Query\Delete to the return on line 185 which is incompatible with the return type documented by Bluz\Db\Query\Select::innerJoin of type Bluz\Db\Query\Select.
Loading history...
186 2
            'join',
187
            [
188
                $fromAlias => [
189 2
                    'joinType'      => 'inner',
190 2
                    'joinTable'     => $join,
191 2
                    'joinAlias'     => $alias,
192 2
                    'joinCondition' => $condition
193
                ]
194
            ],
195 2
            true
196
        );
197
    }
198
199
    /**
200
     * Creates and adds a left join to the query.
201
     *
202
     * Example
203
     * <code>
204
     *     $sb = new Select();
205
     *     $sb
206
     *         ->select('u.name')
207
     *         ->from('users', 'u')
208
     *         ->leftJoin('u', 'phone', 'p', 'p.is_primary = 1');
209
     * </code>
210
     *
211
     * @param  string $fromAlias the alias that points to a from clause
212
     * @param  string $join      the table name to join
213
     * @param  string $alias     the alias of the join table
214
     * @param  string $condition the condition for the join
215
     * @return Select instance
216
     */
217 1
    public function leftJoin($fromAlias, $join, $alias, $condition = null)
218
    {
219 1
        $this->aliases[] = $alias;
220
221 1
        return $this->addQueryPart(
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addQueryPart('joi...=> $condition)), true); of type Bluz\Db\Query\Select|Bluz\Db\Query\Delete adds the type Bluz\Db\Query\Delete to the return on line 221 which is incompatible with the return type documented by Bluz\Db\Query\Select::leftJoin of type Bluz\Db\Query\Select.
Loading history...
222 1
            'join',
223
            [
224
                $fromAlias => [
225 1
                    'joinType'      => 'left',
226 1
                    'joinTable'     => $join,
227 1
                    'joinAlias'     => $alias,
228 1
                    'joinCondition' => $condition
229
                ]
230
            ],
231 1
            true
232
        );
233
    }
234
235
    /**
236
     * Creates and adds a right join to the query.
237
     *
238
     * Example
239
     * <code>
240
     *     $sb = new Select();
241
     *     $sb
242
     *         ->select('u.name')
243
     *         ->from('users', 'u')
244
     *         ->rightJoin('u', 'phone', 'p', 'p.is_primary = 1');
245
     * </code>
246
     *
247
     * @param  string $fromAlias the alias that points to a from clause
248
     * @param  string $join      the table name to join
249
     * @param  string $alias     the alias of the join table
250
     * @param  string $condition the condition for the join
251
     * @return Select instance
252
     */
253 1
    public function rightJoin($fromAlias, $join, $alias, $condition = null)
254
    {
255 1
        $this->aliases[] = $alias;
256
257 1
        return $this->addQueryPart(
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addQueryPart('joi...=> $condition)), true); of type Bluz\Db\Query\Select|Bluz\Db\Query\Delete adds the type Bluz\Db\Query\Delete to the return on line 257 which is incompatible with the return type documented by Bluz\Db\Query\Select::rightJoin of type Bluz\Db\Query\Select.
Loading history...
258 1
            'join',
259
            [
260
                $fromAlias => [
261 1
                    'joinType'      => 'right',
262 1
                    'joinTable'     => $join,
263 1
                    'joinAlias'     => $alias,
264 1
                    'joinCondition' => $condition
265
                ]
266
            ],
267 1
            true
268
        );
269
    }
270
271
    /**
272
     * Specifies a grouping over the results of the query.
273
     * Replaces any previously specified groupings, if any.
274
     *
275
     * Example
276
     * <code>
277
     *     $sb = new Select();
278
     *     $sb
279
     *         ->select('u.name')
280
     *         ->from('users', 'u')
281
     *         ->groupBy('u.id');
282
     * </code>
283
     *
284
     * @param  string[] $groupBy the grouping expression
285
     * @return Select instance
286
     */
287 1
    public function groupBy(...$groupBy)
288
    {
289 1
        if (empty($groupBy)) {
290
            return $this;
291
        }
292
293 1
        return $this->addQueryPart('groupBy', $groupBy, false);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addQueryPart('groupBy', $groupBy, false); of type Bluz\Db\Query\Select|Bluz\Db\Query\Delete adds the type Bluz\Db\Query\Delete to the return on line 293 which is incompatible with the return type documented by Bluz\Db\Query\Select::groupBy of type Bluz\Db\Query\Select.
Loading history...
294
    }
295
296
    /**
297
     * Adds a grouping expression to the query.
298
     *
299
     * Example
300
     * <code>
301
     *     $sb = new Select();
302
     *     $sb
303
     *         ->select('u.name')
304
     *         ->from('users', 'u')
305
     *         ->groupBy('u.lastLogin');
306
     *         ->addGroupBy('u.createdAt')
307
     * </code>
308
     *
309
     * @param  string[] $groupBy the grouping expression
310
     * @return Select instance
311
     */
312 1
    public function addGroupBy(...$groupBy)
313
    {
314 1
        if (empty($groupBy)) {
315
            return $this;
316
        }
317
318 1
        return $this->addQueryPart('groupBy', $groupBy, true);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addQueryPart('groupBy', $groupBy, true); of type Bluz\Db\Query\Select|Bluz\Db\Query\Delete adds the type Bluz\Db\Query\Delete to the return on line 318 which is incompatible with the return type documented by Bluz\Db\Query\Select::addGroupBy of type Bluz\Db\Query\Select.
Loading history...
319
    }
320
321
    /**
322
     * Specifies a restriction over the groups of the query.
323
     * Replaces any previous having restrictions, if any
324
     *
325
     * @param  string[] $condition the query restriction predicates
326
     * @return Select
327
     */
328 1
    public function having(...$condition)
329
    {
330 1
        $condition = $this->prepareCondition($condition);
331 1
        return $this->addQueryPart('having', $condition, false);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addQueryPart('having', $condition, false); of type Bluz\Db\Query\Select|Bluz\Db\Query\Delete adds the type Bluz\Db\Query\Delete to the return on line 331 which is incompatible with the return type documented by Bluz\Db\Query\Select::having of type Bluz\Db\Query\Select.
Loading history...
332
    }
333
334
    /**
335
     * Adds a restriction over the groups of the query, forming a logical
336
     * conjunction with any existing having restrictions
337
     *
338
     * @param  string[] $condition the query restriction predicates
339
     * @return Select
340
     */
341 1
    public function andHaving(...$condition)
342
    {
343 1
        $condition = $this->prepareCondition($condition);
344 1
        $having = $this->getQueryPart('having');
345
346 1
        if ($having instanceof CompositeBuilder && $having->getType() == 'AND') {
347
            $having->add($condition);
348
        } else {
349 1
            $having = new CompositeBuilder([$having, $condition]);
350
        }
351
352 1
        return $this->addQueryPart('having', $having, false);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addQueryPart('having', $having, false); of type Bluz\Db\Query\Select|Bluz\Db\Query\Delete adds the type Bluz\Db\Query\Delete to the return on line 352 which is incompatible with the return type documented by Bluz\Db\Query\Select::andHaving of type Bluz\Db\Query\Select.
Loading history...
353
    }
354
355
    /**
356
     * Adds a restriction over the groups of the query, forming a logical
357
     * disjunction with any existing having restrictions
358
     *
359
     * @param  string[] $condition the query restriction predicates
360
     * @return Select
361
     */
362 1
    public function orHaving(...$condition)
363
    {
364 1
        $condition = $this->prepareCondition($condition);
365 1
        $having = $this->getQueryPart('having');
366
367 1
        if ($having instanceof CompositeBuilder && $having->getType() == 'OR') {
368
            $having->add($condition);
369
        } else {
370 1
            $having = new CompositeBuilder([$having, $condition], 'OR');
371
        }
372
373 1
        return $this->addQueryPart('having', $having, false);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->addQueryPart('having', $having, false); of type Bluz\Db\Query\Select|Bluz\Db\Query\Delete adds the type Bluz\Db\Query\Delete to the return on line 373 which is incompatible with the return type documented by Bluz\Db\Query\Select::orHaving of type Bluz\Db\Query\Select.
Loading history...
374
    }
375
376
    /**
377
     * Setup offset like a page number, start from 1
378
     *
379
     * @param  integer $page
380
     * @return Select
381
     * @throws DbException
382
     */
383 1
    public function setPage($page = 1)
384
    {
385 1
        if (!$this->limit) {
386
            throw new DbException("Please setup limit for use method `setPage`");
387
        }
388 1
        $this->offset = $this->limit * ($page - 1);
389 1
        return $this;
390
    }
391
392
    /**
393
     * Generate SQL string for JOINs
394
     *
395
     * @internal
396
     * @param  string $fromAlias alias of table
397
     * @return string
398
     */
399 7
    protected function getSQLForJoins($fromAlias)
400
    {
401 7
        $sql = '';
402
403 7
        if (isset($this->sqlParts['join'][$fromAlias])) {
404 4
            foreach ($this->sqlParts['join'][$fromAlias] as $join) {
405 4
                $sql .= ' ' . strtoupper($join['joinType'])
406 4
                    . " JOIN " . $join['joinTable'] . ' ' . $join['joinAlias']
407 4
                    . " ON " . ((string) $join['joinCondition']);
408 4
                $sql .= $this->getSQLForJoins($join['joinAlias']);
409
            }
410
        }
411
412 7
        return $sql;
413
    }
414
}
415