Completed
Push — master ( e47c19...3aaaf2 )
by Anton
15s queued 13s
created

Select::addSelect()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Bluz Framework Component
5
 *
6
 * @copyright Bluz PHP Team
7
 * @link      https://github.com/bluzphp/framework
8
 */
9
10
declare(strict_types=1);
11
12
namespace Bluz\Db\Query;
13
14
use Bluz\Db\Exception\DbException;
15
use Bluz\Proxy\Db;
16
17
/**
18
 * Builder of SELECT queries
19
 *
20
 * @package Bluz\Db\Query
21
 */
22
class Select extends AbstractBuilder
23
{
24
    use Traits\From;
25
    use Traits\Where;
26
    use Traits\Order;
27
    use Traits\Limit;
28
29
    /**
30
     * <code>
31
     * [
32
     *     'u.id', 'u.name',
33
     *     'p.id', 'p.title'
34
     * ]
35
     * </code>
36
     *
37
     * @var array[]
38
     */
39
    protected $select = [];
40
    protected $groupBy = [];
41
    protected $having = null;
42
43
    /**
44
     * @var mixed PDO fetch types or object class
45
     */
46
    protected $fetchType = \PDO::FETCH_ASSOC;
47
48
    /**
49
     * {@inheritdoc}
50
     *
51
     * @param  integer|string|object $fetchType
52
     *
53
     * @return integer|string|array
54
     */
55 3
    public function execute($fetchType = null)
56
    {
57 3
        if (!$fetchType) {
58 3
            $fetchType = $this->fetchType;
59
        }
60
61
        switch ($fetchType) {
62 3
            case (!is_int($fetchType)):
63 2
                return Db::fetchObjects($this->getSql(), $this->params, $fetchType);
64 1
            case \PDO::FETCH_CLASS:
65
                return Db::fetchObjects($this->getSql(), $this->params);
66 1
            case \PDO::FETCH_ASSOC:
67
            default:
68 1
                return Db::fetchAll($this->getSql(), $this->params);
69
        }
70
    }
71
72
    /**
73
     * Setup fetch type, any of PDO, or any Class
74
     *
75
     * @param  string $fetchType
76
     *
77
     * @return Select instance
78
     */
79 2
    public function setFetchType($fetchType): Select
80
    {
81 2
        $this->fetchType = $fetchType;
82 2
        return $this;
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88 8
    public function getSql(): string
89
    {
90 8
        return $this->prepareSelect()
91 8
            . $this->prepareFrom()
92 8
            . $this->prepareWhere()
93 8
            . $this->prepareGroupBy()
94 8
            . $this->prepareHaving()
95 8
            . $this->prepareOrderBy()
96 8
            . $this->prepareLimit();
97
    }
98
99
    /**
100
     * Specifies an item that is to be returned in the query result
101
     * Replaces any previously specified selections, if any
102
     *
103
     * Example
104
     * <code>
105
     *     $sb = new Select();
106
     *     $sb
107
     *         ->select('u.id', 'p.id')
108
     *         ->from('users', 'u')
109
     *         ->leftJoin('u', 'phone', 'p', 'u.id = p.user_id');
110
     * </code>
111
     *
112
     * @param  string[] $select the selection expressions
113
     *
114
     * @return Select instance
115
     */
116 9
    public function select(...$select): Select
117
    {
118 9
        $this->select = $select;
0 ignored issues
show
Documentation Bug introduced by
It seems like $select of type array<integer,string> is incompatible with the declared type array<mixed,array> of property $select.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
119 9
        return $this;
120
    }
121
122
    /**
123
     * Adds an item that is to be returned in the query result.
124
     *
125
     * Example
126
     * <code>
127
     *     $sb = new Select();
128
     *     $sb
129
     *         ->select('u.id')
130
     *         ->addSelect('p.id')
131
     *         ->from('users', 'u')
132
     *         ->leftJoin('u', 'phone', 'u.id = p.user_id');
133
     * </code>
134
     *
135
     * @param  string[] $select the selection expression
136
     *
137
     * @return Select instance
138
     */
139 1
    public function addSelect(string ...$select): Select
140
    {
141 1
        $this->select = array_merge($this->select, $select);
142 1
        return $this;
143
    }
144
145
    /**
146
     * Get current select query part
147
     *
148
     * @return array
149
     */
150 3
    public function getSelect(): array
151
    {
152 3
        return $this->select;
153
    }
154
155
    /**
156
     * Specifies a grouping over the results of the query.
157
     * Replaces any previously specified groupings, if any.
158
     *
159
     * Example
160
     * <code>
161
     *     $sb = new Select();
162
     *     $sb
163
     *         ->select('u.name')
164
     *         ->from('users', 'u')
165
     *         ->groupBy('u.id');
166
     * </code>
167
     *
168
     * @param  string[] $groupBy the grouping expression
169
     *
170
     * @return Select instance
171
     */
172 1
    public function groupBy(string ...$groupBy): Select
173
    {
174 1
        $this->groupBy = $groupBy;
175 1
        return $this;
176
    }
177
178
    /**
179
     * Adds a grouping expression to the query.
180
     *
181
     * Example
182
     * <code>
183
     *     $sb = new Select();
184
     *     $sb
185
     *         ->select('u.name')
186
     *         ->from('users', 'u')
187
     *         ->groupBy('u.lastLogin');
188
     *         ->addGroupBy('u.createdAt')
189
     * </code>
190
     *
191
     * @param  string[] $groupBy the grouping expression
192
     *
193
     * @return Select instance
194
     */
195 1
    public function addGroupBy(string ...$groupBy): Select
196
    {
197 1
        $this->groupBy = array_merge($this->groupBy, $groupBy);
198 1
        return $this;
199
    }
200
201
    /**
202
     * Specifies a restriction over the groups of the query.
203
     * Replaces any previous having restrictions, if any
204
     *
205
     * @param  string[] $conditions the query restriction predicates
206
     *
207
     * @return Select
208
     */
209 1
    public function having(...$conditions): Select
210
    {
211 1
        $this->having = $this->prepareCondition($conditions);
212 1
        return $this;
213
    }
214
215
    /**
216
     * Adds a restriction over the groups of the query, forming a logical
217
     * conjunction with any existing having restrictions
218
     *
219
     * @param  string[] $conditions the query restriction predicates
220
     *
221
     * @return Select
222
     */
223 1
    public function andHaving(...$conditions): Select
224
    {
225 1
        $condition = $this->prepareCondition($conditions);
226
227
        if (
228 1
            $this->having instanceof CompositeBuilder
229 1
            && $this->having->getType() === 'AND'
230
        ) {
231
            $this->having->addPart($condition);
232
        } else {
233 1
            $this->having = new CompositeBuilder([$this->having, $condition]);
234
        }
235 1
        return $this;
236
    }
237
238
    /**
239
     * Adds a restriction over the groups of the query, forming a logical
240
     * disjunction with any existing having restrictions
241
     *
242
     * @param  string[] $conditions the query restriction predicates
243
     *
244
     * @return Select
245
     */
246 1
    public function orHaving(...$conditions): Select
247
    {
248 1
        $condition = $this->prepareCondition($conditions);
249
250
        if (
251 1
            $this->having instanceof CompositeBuilder
252 1
            && $this->having->getType() === 'OR'
253
        ) {
254
            $this->having->addPart($condition);
255
        } else {
256 1
            $this->having = new CompositeBuilder([$this->having, $condition], 'OR');
257
        }
258 1
        return $this;
259
    }
260
261
    /**
262
     * Setup offset like a page number, start from 1
263
     *
264
     * @param  integer $page
265
     *
266
     * @return Select
267
     * @throws DbException
268
     */
269 1
    public function setPage(int $page = 1): Select
270
    {
271 1
        if (!$this->limit) {
272
            throw new DbException('Please setup limit for use method `setPage`');
273
        }
274 1
        $this->offset = $this->limit * ($page - 1);
275 1
        return $this;
276
    }
277
278
    /**
279
     * Prepare Select query part
280
     *
281
     * @return string
282
     */
283 8
    protected function prepareSelect(): string
284
    {
285 8
        return 'SELECT ' . implode(', ', $this->select);
286
    }
287
288
    /**
289
     * prepareWhere
290
     *
291
     * @return string
292
     */
293 8
    protected function prepareGroupBy(): string
294
    {
295 8
        return !empty($this->groupBy) ? ' GROUP BY ' . implode(', ', $this->groupBy) : '';
296
    }
297
298
    /**
299
     * prepareWhere
300
     *
301
     * @return string
302
     */
303 8
    protected function prepareHaving(): string
304
    {
305 8
        return $this->having ? ' HAVING ' . $this->having : '';
306
    }
307
}
308