Passed
Push — master ( e65a8a...7854bb )
by Tomáš
02:15
created

QueryBuilder::getOrderBy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types = 1);
2
3
namespace Apicart\Utils\Sql;
4
5
final class QueryBuilder
6
{
7
8
	/**
9
	 * @var string|int|null
10
	 */
11
	private $offset;
12
13
	/**
14
	 * @var string|int|null
15
	 */
16
	private $limit;
17
18
	/**
19
	 * @var array
20
	 */
21
	private $parameters = [];
22
23
	/**
24
	 * @var string[]
25
	 */
26
	private $select = [];
27
28
	/**
29
	 * @var string[]
30
	 */
31
	private $join = [];
32
33
	/**
34
	 * @var string[]
35
	 */
36
	private $where = [];
37
38
	/**
39
	 * @var string[]
40
	 */
41
	private $groupBy = [];
42
43
	/**
44
	 * @var string[]
45
	 */
46
	private $orderBy = [];
47
48
49 2
	public static function create(): self
50
	{
51 2
		return new self;
52
	}
53
54
55 2
	public function select(string $columns): self
56
	{
57 2
		$this->select = [$columns];
58
59 2
		return $this;
60
	}
61
62
63 2
	public function addSelect(string $columns): self
64
	{
65 2
		$this->select[] = $columns;
66
67 2
		return $this;
68
	}
69
70
71 2
	public function from(string $tableName, string $alias = ''): self
72
	{
73 2
		$this->join[] = sprintf('FROM %s %s', $tableName, $alias);
74
75 2
		return $this;
76
	}
77
78
79
	public function addJoinDirectly(string $join): self
80
	{
81
		$this->join[] = $join;
82
83
		return $this;
84
	}
85
86
87
	public function join(string $tableName, string $alias, string $condition): self
88
	{
89
		return $this->innerJoin($tableName, $alias, $condition);
90
	}
91
92
93 2
	public function innerJoin(string $tableName, string $alias, string $condition): self
94
	{
95 2
		$this->join[$alias] = sprintf('INNER JOIN %s %s ON %s', $tableName, $alias, $condition);
96
97 2
		return $this;
98
	}
99
100
101 2
	public function leftJoin(string $tableName, string $alias, string $condition): self
102
	{
103 2
		$this->join[$alias] = sprintf('LEFT JOIN %s %s ON %s', $tableName, $alias, $condition);
104
105 2
		return $this;
106
	}
107
108
109
	public function addWhereDirectly(string $where): self
110
	{
111
		$this->where[] = $where;
112
113
		return $this;
114
	}
115
116
117 2
	public function where(string $condition): self
118
	{
119 2
		$this->where = [$condition];
120
121 2
		return $this;
122
	}
123
124
125 2
	public function andWhere(string $condition): self
126
	{
127 2
		$this->where[] = sprintf(' AND (%s)', $condition);
128
129 2
		return $this;
130
	}
131
132
133 2
	public function orWhere(string $condition): self
134
	{
135 2
		$this->where[] = sprintf(' OR (%s)', $condition);
136
137 2
		return $this;
138
	}
139
140
141
	public function groupBy(string $column): self
142
	{
143
		$this->groupBy = [$column];
144
145
		return $this;
146
	}
147
148
149
	public function addGroupBy(string $column): self
150
	{
151
		$this->groupBy[] = $column;
152
153
		return $this;
154
	}
155
156
157
	public function orderBy(string $column, string $order = 'DESC'): self
158
	{
159
		$this->orderBy = [$column . ' ' . $order];
160
161
		return $this;
162
	}
163
164
165
	public function addOrderBy(string $column, string $order = 'DESC'): self
166
	{
167
		$this->orderBy[] = $column . ' ' . $order;
168
169
		return $this;
170
	}
171
172
173
	/**
174
	 * @param string|int $limit
175
	 */
176
	public function setLimit($limit): self
177
	{
178
		$this->limit = $limit;
179
180
		return $this;
181
	}
182
183
184
	/**
185
	 * @param string|int $offset
186
	 */
187
	public function setOffset($offset): self
188
	{
189
		$this->offset = $offset;
190
191
		return $this;
192
	}
193
194
195 2
	public function setParameters(array $parameters): self
196
	{
197 2
		$this->parameters = $parameters;
198
199 2
		return $this;
200
	}
201
202
203
	/**
204
	 * @param int|string|bool|float $value
205
	 */
206 2
	public function setParameter(string $key, $value): self
207
	{
208 2
		$this->parameters[$key] = $value;
209
210 2
		return $this;
211
	}
212
213
214 1
	public function getSql(): string
215
	{
216 1
		$sql = 'SELECT ';
217
218
		// apply columns
219 1
		$sql .= implode(', ', $this->select);
220 1
		$sql .= PHP_EOL;
221
222
		// apply joins
223 1
		$sql .= implode(PHP_EOL, $this->join);
224 1
		$sql .= PHP_EOL;
225
226
		// apply conditions
227 1
		if ($this->where !== []) {
228 1
			$sql .= 'WHERE ';
229
230 1
			for ($index = 0; $index < count($this->where); $index++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
231 1
				$condition = $this->where[$index];
232
233 1
				if ($index === 0) {
234 1
					$condition = preg_replace('/^ (AND|OR) /', '', $condition);
235
				}
236
237 1
				$sql .= $condition;
238
			}
239
240 1
			$sql .= PHP_EOL;
241
		}
242
243
		// apply group by
244 1
		if ($this->groupBy !== []) {
245
			$sql .= 'GROUP BY ';
246
			$sql .= implode(',', $this->groupBy);
247
			$sql .= PHP_EOL;
248
		}
249
250
		// apply orders
251 1
		if ($this->orderBy !== []) {
252
			$sql .= 'ORDER BY ';
253
			$sql .= implode(',', $this->orderBy);
254
			$sql .= PHP_EOL;
255
		}
256
257 1
		if ($this->limit) {
258
			$sql .= 'LIMIT ' . $this->limit;
259
			$sql .= PHP_EOL;
260
		}
261 1
		if ($this->offset) {
262
			$sql .= 'OFFSET ' . $this->offset;
263
		}
264
265 1
		return $this->replaceParameters($sql);
266
	}
267
268
269 2
	public function getParameters(): array
270
	{
271 2
		return $this->parameters;
272
	}
273
274
275
	/**
276
	 * @param mixed $default
277
	 * @return mixed
278
	 */
279
	public function getParameter(string $key, $default = null)
280
	{
281
		return $this->parameters[$key] ?? $default;
282
	}
283
284
285
	/**
286
	 * @return string[]
287
	 */
288
	public function getSelect(): array
289
	{
290
		return $this->select;
291
	}
292
293
294
	/**
295
	 * @return string[]
296
	 */
297
	public function getJoin(): array
298
	{
299
		return $this->join;
300
	}
301
302
303
	/**
304
	 * @return string[]
305
	 */
306
	public function getWhere(): array
307
	{
308
		return $this->where;
309
	}
310
311
312
	/**
313
	 * @return string[]
314
	 */
315
	public function getGroupBy(): array
316
	{
317
		return $this->groupBy;
318
	}
319
320
321
	/**
322
	 * @return string[]
323
	 */
324
	public function getOrderBy(): array
325
	{
326
		return $this->orderBy;
327
	}
328
329
330
	/**
331
	 * @return int|string|null
332
	 */
333
	public function getLimit()
334
	{
335
		return $this->limit;
336
	}
337
338
339
	/**
340
	 * @return int|string|null
341
	 */
342
	public function getOffset()
343
	{
344
		return $this->offset;
345
	}
346
347
348 1
	private function replaceParameters(string $sql): string
349
	{
350 1
		$userParameters = $this->getParameters();
351 1
		$newParameters = [];
352
353 1
		$parametrizedSql = preg_replace_callback(
354 1
			'#([ (]+):([a-zA-Z0-9]+)#',
355
			function ($match) use (&$newParameters, $userParameters) {
356 1
				$newParameter = $userParameters[$match[2]];
357
358
				// expand array parameter into string of parameters e.g. $1,$2,$3...
359 1
				if (is_array($newParameter)) {
360 1
					$output = $match[1];
361 1
					foreach ($newParameter as $data) {
362 1
						$newParameters[] = $data;
363 1
						$output .= sprintf('$%d,', count($newParameters));
364
					}
365 1
					$output = substr($output, 0, -1);
366
367 1
					return $output;
368
				}
369
370 1
				$newParameters[] = $newParameter;
371
372 1
				return sprintf('%s$%d', $match[1], count($newParameters));
373 1
			},
374
			$sql
375
		);
376
377 1
		$this->parameters = $newParameters;
378
379 1
		return $parametrizedSql;
380
	}
381
382
}
383