Completed
Push — master ( 467d47...6f2bb4 )
by Anton
14s
created

Select::getSql()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 0
Metric Value
nc 1
dl 0
loc 10
ccs 8
cts 8
cp 1
c 0
b 0
f 0
cc 1
eloc 8
nop 0
crap 1
rs 9.4285
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
     * <code>
30
     * [
31
     *     'u.id', 'u.name',
32
     *     'p.id', 'p.title'
33
     * ]
34
     * </code>
35
     *
36
     * @var array[]
37
     */
38
    protected $select = [];
39
    protected $groupBy = [];
40
    protected $having = null;
41
42
    /**
43
     * @var mixed PDO fetch types or object class
44
     */
45
    protected $fetchType = \PDO::FETCH_ASSOC;
46
47
    /**
48
     * {@inheritdoc}
49
     *
50
     * @param  integer|string|object $fetchType
51
     *
52
     * @return integer|string|array
53
     */
54 3
    public function execute($fetchType = null)
55
    {
56 3
        if (!$fetchType) {
57 3
            $fetchType = $this->fetchType;
58
        }
59
60
        switch ($fetchType) {
61 3
            case (!is_int($fetchType)):
62 2
                return Db::fetchObjects($this->getSql(), $this->params, $fetchType);
63 1
            case \PDO::FETCH_CLASS:
64
                return Db::fetchObjects($this->getSql(), $this->params);
65 1
            case \PDO::FETCH_ASSOC:
66
            default:
67 1
                return Db::fetchAll($this->getSql(), $this->params);
68
        }
69
    }
70
71
    /**
72
     * Setup fetch type, any of PDO, or any Class
73
     *
74
     * @param  string $fetchType
75
     *
76
     * @return Select instance
77
     */
78 2
    public function setFetchType($fetchType)
79
    {
80 2
        $this->fetchType = $fetchType;
81 2
        return $this;
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87 8
    public function getSql() : string
88
    {
89 8
        return $this->prepareSelect()
90 8
            . $this->prepareFrom()
91 8
            . $this->prepareWhere()
92 8
            . $this->prepareGroupBy()
93 8
            . $this->prepareHaving()
94 8
            . $this->prepareOrderBy()
95 8
            . $this->prepareLimit();
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
     *
113
     * @return Select instance
114
     */
115 9
    public function select(...$select) : Select
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
116
    {
117 9
        $this->select = $select;
118 9
        return $this;
119
    }
120
121
    /**
122
     * Adds an item that is to be returned in the query result.
123
     *
124
     * Example
125
     * <code>
126
     *     $sb = new Select();
127
     *     $sb
128
     *         ->select('u.id')
129
     *         ->addSelect('p.id')
130
     *         ->from('users', 'u')
131
     *         ->leftJoin('u', 'phone', 'u.id = p.user_id');
132
     * </code>
133
     *
134
     * @param  string[] $select the selection expression
135
     *
136
     * @return Select instance
137
     */
138 1
    public function addSelect(string ...$select) : Select
139
    {
140 1
        $this->select = array_merge($this->select, $select);
141 1
        return $this;
142
    }
143
144
    /**
145
     * Get current select query part
146
     *
147
     * @return array
148
     */
149 3
    public function getSelect() : array
150
    {
151 3
        return $this->select;
152
    }
153
154
    /**
155
     * Specifies a grouping over the results of the query.
156
     * Replaces any previously specified groupings, if any.
157
     *
158
     * Example
159
     * <code>
160
     *     $sb = new Select();
161
     *     $sb
162
     *         ->select('u.name')
163
     *         ->from('users', 'u')
164
     *         ->groupBy('u.id');
165
     * </code>
166
     *
167
     * @param  string[] $groupBy the grouping expression
168
     *
169
     * @return Select instance
170
     */
171 1
    public function groupBy(string ...$groupBy) : Select
172
    {
173 1
        $this->groupBy = $groupBy;
174 1
        return $this;
175
    }
176
177
    /**
178
     * Adds a grouping expression to the query.
179
     *
180
     * Example
181
     * <code>
182
     *     $sb = new Select();
183
     *     $sb
184
     *         ->select('u.name')
185
     *         ->from('users', 'u')
186
     *         ->groupBy('u.lastLogin');
187
     *         ->addGroupBy('u.createdAt')
188
     * </code>
189
     *
190
     * @param  string[] $groupBy the grouping expression
191
     *
192
     * @return Select instance
193
     */
194 1
    public function addGroupBy(string ...$groupBy) : Select
195
    {
196 1
        $this->groupBy = array_merge($this->groupBy, $groupBy);
197 1
        return $this;
198
    }
199
200
    /**
201
     * Specifies a restriction over the groups of the query.
202
     * Replaces any previous having restrictions, if any
203
     *
204
     * @param  string[] $conditions the query restriction predicates
205
     *
206
     * @return Select
207
     */
208 1
    public function having(...$conditions) : Select
209
    {
210 1
        $this->having = $this->prepareCondition($conditions);
211 1
        return $this;
212
    }
213
214
    /**
215
     * Adds a restriction over the groups of the query, forming a logical
216
     * conjunction with any existing having restrictions
217
     *
218
     * @param  string[] $conditions the query restriction predicates
219
     *
220
     * @return Select
221
     */
222 1
    public function andHaving(...$conditions) : Select
223
    {
224 1
        $condition = $this->prepareCondition($conditions);
225
226 1
        if ($this->having instanceof CompositeBuilder
227 1
            && $this->having->getType() === 'AND') {
228
            $this->having->addPart($condition);
229
        } else {
230 1
            $this->having = new CompositeBuilder([$this->having, $condition]);
231
        }
232 1
        return $this;
233
    }
234
235
    /**
236
     * Adds a restriction over the groups of the query, forming a logical
237
     * disjunction with any existing having restrictions
238
     *
239
     * @param  string[] $conditions the query restriction predicates
240
     *
241
     * @return Select
242
     */
243 1
    public function orHaving(...$conditions) : Select
244
    {
245 1
        $condition = $this->prepareCondition($conditions);
246
247 1
        if ($this->having instanceof CompositeBuilder
248 1
            && $this->having->getType() === 'OR') {
249
            $this->having->addPart($condition);
250
        } else {
251 1
            $this->having = new CompositeBuilder([$this->having, $condition], 'OR');
252
        }
253 1
        return $this;
254
    }
255
256
    /**
257
     * Setup offset like a page number, start from 1
258
     *
259
     * @param  integer $page
260
     *
261
     * @return Select
262
     * @throws DbException
263
     */
264 1
    public function setPage(int $page = 1) : Select
265
    {
266 1
        if (!$this->limit) {
267
            throw new DbException('Please setup limit for use method `setPage`');
268
        }
269 1
        $this->offset = $this->limit * ($page - 1);
270 1
        return $this;
271
    }
272
273
    /**
274
     * Prepare Select query part
275
     *
276
     * @return string
277
     */
278 8
    protected function prepareSelect() : string
279
    {
280 8
        return 'SELECT ' . implode(', ', $this->select);
281
    }
282
283
    /**
284
     * prepareWhere
285
     *
286
     * @return string
287
     */
288 8
    protected function prepareGroupBy() : string
289
    {
290 8
        return !empty($this->groupBy) ? ' GROUP BY ' . implode(', ', $this->groupBy) : '';
291
    }
292
293
    /**
294
     * prepareWhere
295
     *
296
     * @return string
297
     */
298 8
    protected function prepareHaving() : string
299
    {
300 8
        return $this->having ? ' HAVING ' . $this->having : '';
301
    }
302
}
303