Completed
Pull Request — master (#451)
by Anton
13:12
created

Select::execute()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 11
nc 8
nop 1
dl 0
loc 16
rs 8.8571
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 5
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 3
    protected $having = null;
41
42 3
    /**
43 3
     * @var mixed PDO fetch types or object class
44
     */
45
    protected $fetchType = \PDO::FETCH_ASSOC;
46
47 3
    /**
48 2
     * {@inheritdoc}
49 1
     *
50
     * @param  integer|string|object $fetchType
51 1
     *
52
     * @return integer|string|array
53 1
     */
54
    public function execute($fetchType = null)
55
    {
56
        if (!$fetchType) {
57
            $fetchType = $this->fetchType;
58
        }
59
60
        switch ($fetchType) {
61
            case (!is_int($fetchType)):
62
                return Db::fetchObjects($this->getSql(), $this->params, $fetchType);
63
            case \PDO::FETCH_CLASS:
64 2
                return Db::fetchObjects($this->getSql(), $this->params);
65
            case \PDO::FETCH_ASSOC:
66 2
            default:
67 2
                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 8
     *
76
     * @return Select instance
77 8
     */
78
    public function setFetchType($fetchType)
79 8
    {
80
        $this->fetchType = $fetchType;
81
        return $this;
82 8
    }
83 8
84 8
    /**
85
     * {@inheritdoc}
86 8
     */
87
    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
            . $this->prepareLimit();
96 8
    }
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
    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 9
    {
117
        $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
        return $this;
142
    }
143
144
    /**
145
     * Get current select query part
146
     *
147
     * @return array
148
     */
149
    public function getSelect() : array
150
    {
151
        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 2
     *         ->select('u.name')
163
     *         ->from('users', 'u')
164 2
     *         ->groupBy('u.id');
165
     * </code>
166
     *
167
     * @param  string[] $groupBy the grouping expression
168
     *
169
     * @return Select instance
170
     */
171
    public function groupBy(string ...$groupBy) : Select
172
    {
173
        $this->groupBy = $groupBy;
174
        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 2
     *         ->groupBy('u.lastLogin');
187
     *         ->addGroupBy('u.createdAt')
188 2
     * </code>
189
     *
190 2
     * @param  string[] $groupBy the grouping expression
191 2
     *
192
     * @return Select instance
193
     */
194 2
    public function addGroupBy(string ...$groupBy) : Select
195 2
    {
196 2
        $this->groupBy = array_merge($this->groupBy, $groupBy);
197 2
        return $this;
198
    }
199
200 2
    /**
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
    public function having(...$conditions) : Select
209
    {
210
        $this->having = $this->prepareCondition($conditions);
211
        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
    public function andHaving(...$conditions) : Select
223 1
    {
224
        $condition = $this->prepareCondition($conditions);
225 1
226
        if ($this->having instanceof CompositeBuilder
227 1
            && $this->having->getType() === 'AND') {
228 1
            $this->having->addPart($condition);
229
        } else {
230
            $this->having = new CompositeBuilder([$this->having, $condition]);
231 1
        }
232 1
        return $this;
233 1
    }
234 1
235
    /**
236
     * Adds a restriction over the groups of the query, forming a logical
237 1
     * disjunction with any existing having restrictions
238
     *
239
     * @param  string[] $conditions the query restriction predicates
240
     *
241
     * @return Select
242
     */
243
    public function orHaving(...$conditions) : Select
244
    {
245
        $condition = $this->prepareCondition($conditions);
246
247
        if ($this->having instanceof CompositeBuilder
248
            && $this->having->getType() === 'OR') {
249
            $this->having->addPart($condition);
250
        } else {
251
            $this->having = new CompositeBuilder([$this->having, $condition], 'OR');
252
        }
253
        return $this;
254
    }
255
256
    /**
257
     * Setup offset like a page number, start from 1
258
     *
259
     * @param  integer $page
260 1
     *
261
     * @return Select
262 1
     * @throws DbException
263
     */
264 1
    public function setPage(int $page = 1) : Select
265 1
    {
266
        if (!$this->limit) {
267
            throw new DbException('Please setup limit for use method `setPage`');
268 1
        }
269 1
        $this->offset = $this->limit * ($page - 1);
270 1
        return $this;
271 1
    }
272
273
    /**
274 1
     * Prepare Select query part
275
     *
276
     * @return string
277
     */
278
    protected function prepareSelect() : string
279
    {
280
        return 'SELECT ' . implode(', ', $this->select);
281
    }
282
283
    /**
284
     * prepareWhere
285
     *
286
     * @return string
287
     */
288
    protected function prepareGroupBy() : string
289
    {
290
        return !empty($this->groupBy) ? ' GROUP BY ' . implode(', ', $this->groupBy) : '';
291
    }
292
293
    /**
294
     * prepareWhere
295 1
     *
296
     * @return string
297 1
     */
298
    protected function prepareHaving() : string
299
    {
300
        return $this->having ? ' HAVING ' . $this->having : '';
301 1
    }
302
}
303