Completed
Push — v2 ( 3f2240...40dd63 )
by Berend
03:07
created

QueryBuilder   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 432
Duplicated Lines 6.71 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 55
lcom 1
cbo 0
dl 29
loc 432
ccs 136
cts 136
cp 1
rs 6
c 0
b 0
f 0

29 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A __toString() 0 19 5
A select() 0 7 2
A getSelectClause() 0 4 1
B getSelectQuery() 0 30 7
A insert() 0 7 1
A getInsertClause() 0 12 2
A getInsertQuery() 0 4 1
A update() 0 7 1
A getUpdateClause() 0 10 2
A getUpdateQuery() 14 14 3
A delete() 0 6 1
A getDeleteClause() 0 4 1
A getDeleteQuery() 15 15 3
A join() 0 6 1
A leftJoin() 0 6 1
A rightJoin() 0 6 1
A crossJoin() 0 6 1
A getJoinClause() 0 10 2
A where() 0 6 1
A getWhereClause() 0 8 2
A groupBy() 0 6 1
A getGroupByClause() 0 8 2
A orderBy() 0 12 3
A getOrderByClause() 0 8 2
A limit() 0 6 1
A getLimitClause() 0 8 2
A offset() 0 6 1
A getOffsetClause() 0 8 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like QueryBuilder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use QueryBuilder, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * This file is part of the miBadger package.
5
 *
6
 * @author Michael Webbers <[email protected]>
7
 * @license http://opensource.org/licenses/Apache-2.0 Apache v2 License
8
 */
9
10
namespace miBadger\Query;
11
12
/**
13
 * The query builder class.
14
 *
15
 * @since 1.0.0
16
 */
17
class QueryBuilder implements QueryInterface
18
{
19
	/* @var string The modifier. SELECT, INSERT INTO, UPDATE or DELETE */
20
	private $modifier;
21
22
	/* @var string The table name. */
23
	private $table;
24
25
	/* @var array The columns. */
26
	private $columns;
27
28
	/* @var array The values. */
29
	private $values;
30
31
	/* @var array The join conditions. */
32
	private $join;
33
34
	/* @var QueryExpression The where clause. */
35
	private $where;
36
37
	/* @var array The group by conditions. */
38
	private $groupBy;
39
40
	/* @var array The order by conditions. */
41
	private $orderBy;
42
43
	/* @var string The limit. */
44
	private $limit;
45
46
	/* @var string The offset. */
47
	private $offset;
48
49
	/**
50
	 * Construct a query builder object with the given table.
51
	 *
52
	 * @param string $table
53
	 */
54 45
	public function __construct($table)
55
	{
56 45
		$this->table = $table;
57 45
		$this->join = [];
58 45
		$this->where = '';
0 ignored issues
show
Documentation Bug introduced by
It seems like '' of type string is incompatible with the declared type object<miBadger\Query\QueryExpression> of property $where.

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...
59 45
		$this->groupBy = [];
60 45
		$this->orderBy = [];
61 45
	}
62
63
	/**
64
	 * Returns a string representation of the query object.
65
	 *
66
	 * @return string a string representation of the query object.
67
	 */
68 45
	public function __toString()
69
	{
70 45
		switch ($this->modifier) {
71 45
			case self::SELECT:
72 33
				return $this->getSelectQuery();
73
74 12
			case self::INSERT:
75 3
				return $this->getInsertQuery();
76
77 9
			case self::UPDATE:
78 4
				return $this->getUpdateQuery();
79
80 5
			case self::DELETE:
81 3
				return $this->getDeleteQuery();
82
83
			default:
84 2
				return '';
85
		}
86
	}
87
88
	/**
89
	 * {@inheritdoc}
90
	 */
91 33
	public function select($columns = ['*'])
92
	{
93 33
		$this->columns = is_array($columns) ? $columns : func_get_args();
94 33
		$this->modifier = self::SELECT;
95
96 33
		return $this;
97
	}
98
99
	/**
100
	 * Returns the select clause.
101
	 *
102
	 * @return string the select clause.
103
	 */
104 33
	private function getSelectClause()
105
	{
106 33
		return sprintf('SELECT %s FROM %s', implode(', ', $this->columns), $this->table);
107
	}
108
109
	/**
110
	 * Returns the select query.
111
	 *
112
	 * @return string the select query.
113
	 */
114 33
	private function getSelectQuery()
115
	{
116 33
		$result = $this->getSelectClause();
117
118 33
		if ($join = $this->getJoinClause()) {
119 8
			$result .= ' ' . $join;
120
		}
121
122 33
		if ($where = $this->getWhereClause()) {
123 9
			$result .= ' ' . $where;
124
		}
125
126 33
		if ($groupBy = $this->getGroupByClause()) {
127 2
			$result .= ' ' . $groupBy;
128
		}
129
130 33
		if ($orderBy = $this->getOrderByClause()) {
131 4
			$result .= ' ' . $orderBy;
132
		}
133
134 33
		if ($limit = $this->getLimitClause()) {
135 4
			$result .= ' ' . $limit;
136
		}
137
138 33
		if ($offset = $this->getOffsetClause()) {
139 2
			$result .= ' ' . $offset;
140
		}
141
142 33
		return $result;
143
	}
144
145
	/**
146
	 * {@inheritdoc}
147
	 */
148 3
	public function insert(array $values)
149
	{
150 3
		$this->values = $values;
151 3
		$this->modifier = self::INSERT;
152
153 3
		return $this;
154
	}
155
156
	/**
157
	 * Returns the insert clause.
158
	 *
159
	 * @return string the insert clause.
160
	 */
161 3
	private function getInsertClause()
162
	{
163 3
		$columns = [];
164 3
		$values = [];
165
166 3
		foreach ($this->values as $key => $value) {
167 3
			$columns[] = $key;
168 3
			$values[] = sprintf('%s', $value);
169
		}
170
171 3
		return sprintf('INSERT INTO %s (%s) VALUES (%s)', $this->table, implode(', ', $columns), implode(', ', $values));
172
	}
173
174
	/**
175
	 * Returns the insert query.
176
	 *
177
	 * @return string the insert query.
178
	 */
179 3
	private function getInsertQuery()
180
	{
181 3
		return $this->getInsertClause();
182
	}
183
184
	/**
185
	 * {@inheritdoc}
186
	 */
187 4
	public function update(array $values)
188
	{
189 4
		$this->values = $values;
190 4
		$this->modifier = self::UPDATE;
191
192 4
		return $this;
193
	}
194
195
	/**
196
	 * Returns the update clause.
197
	 *
198
	 * @return string the update clause.
199
	 */
200 4
	private function getUpdateClause()
201
	{
202 4
		$placeholders = [];
203
204 4
		foreach ($this->values as $key => $value) {
205 4
			$placeholders[] = sprintf('%s = %s', $key, $value);
206
		}
207
208 4
		return sprintf('UPDATE %s SET %s', $this->table, implode(', ', $placeholders));
209
	}
210
211
	/**
212
	 * Returns the update query.
213
	 *
214
	 * @return string the update query.
215
	 */
216 4 View Code Duplication
	private function getUpdateQuery()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
217
	{
218 4
		$result = $this->getUpdateClause();
219
220 4
		if ($where = $this->getWhereClause()) {
221 4
			$result .= ' ' . $where;
222
		}
223
224 4
		if ($limit = $this->getLimitClause()) {
225 1
			$result .= ' ' . $limit;
226
		}
227
228 4
		return $result;
229
	}
230
231
	/**
232
	 * {@inheritdoc}
233
	 */
234 3
	public function delete()
235
	{
236 3
		$this->modifier = self::DELETE;
237
238 3
		return $this;
239
	}
240
241
	/**
242
	 * Returns the delete clause.
243
	 *
244
	 * @return string the delete clause.
245
	 */
246 3
	private function getDeleteClause()
247
	{
248 3
		return sprintf('DELETE FROM %s', $this->table);
249
	}
250
251
	/**
252
	 * Returns the delete query.
253
	 *
254
	 * @return string the delete query.
255
	 */
256 3 View Code Duplication
	private function getDeleteQuery()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
257
	{
258
259 3
		$result = $this->getDeleteClause();
260
261 3
		if ($where = $this->getWhereClause()) {
262 2
			$result .= ' ' . $where;
263
		}
264
265 3
		if ($limit = $this->getLimitClause()) {
266 1
			$result .= ' ' . $limit;
267
		}
268
269 3
		return $result;
270
	}
271
272
	/**
273
	 * {@inheritdoc}
274
	 */
275 2
	public function join($table, $primary, $operator, $secondary)
276
	{
277 2
		$this->join[] = ['INNER JOIN', $table, $primary, $operator, $secondary];
278
279 2
		return $this;
280
	}
281
282
	/**
283
	 * {@inheritdoc}
284
	 */
285 2
	public function leftJoin($table, $primary, $operator, $secondary)
286
	{
287 2
		$this->join[] = ['LEFT JOIN', $table, $primary, $operator, $secondary];
288
289 2
		return $this;
290
	}
291
292
	/**
293
	 * {@inheritdoc}
294
	 */
295 2
	public function rightJoin($table, $primary, $operator, $secondary)
296
	{
297 2
		$this->join[] = ['RIGHT JOIN', $table, $primary, $operator, $secondary];
298
299 2
		return $this;
300
	}
301
302
	/**
303
	 * {@inheritdoc}
304
	 */
305 2
	public function crossJoin($table, $primary, $operator, $secondary)
306
	{
307 2
		$this->join[] = ['CROSS JOIN', $table, $primary, $operator, $secondary];
308
309 2
		return $this;
310
	}
311
312 33
	private function getJoinClause()
313
	{
314 33
		$result = [];
315
316 33
		foreach ($this->join as $key => $value) {
317 8
			$result[] = sprintf('%s %s ON %s %s %s', $value[0], $value[1], $value[2], $value[3], $value[4]);
318
		}
319
320 33
		return implode(' ', $result);
321
	}
322
323
	/**
324
	 * {@inheritdoc}
325
	 */
326 15
	public function where(QueryExpression $whereClause)
327
	{
328 15
		$this->where = $whereClause;
329
330 15
		return $this;
331
	}
332
333
	/**
334
	 * Returns the where clause.
335
	 *
336
	 * @return string the where clause.
337
	 */
338 40
	private function getWhereClause()
339
	{
340 40
		if (empty($this->where)) {
341 25
			return '';
342
		}
343
344 15
		return sprintf('WHERE %s', (string) $this->where);
345
	}
346
347
	/**
348
	 * {@inheritdoc}
349
	 */
350 2
	public function groupBy($column)
351
	{
352 2
		$this->groupBy[] = $column;
353
354 2
		return $this;
355
	}
356
357
	/**
358
	 * Returns the group by clause.
359
	 *
360
	 * @return string the group by clause.
361
	 */
362 33
	private function getGroupByClause()
363
	{
364 33
		if (empty($this->groupBy)) {
365 31
			return '';
366
		}
367
368 2
		return sprintf('GROUP BY %s', implode(', ', $this->groupBy));
369
	}
370
371
	/**
372
	 * {@inheritdoc}
373
	 */
374 4
	public function orderBy($column, $order = null)
375
	{
376 4
		if (strcasecmp($order, 'asc') == 0) {
377 1
			$column .= ' ASC';
378 3
		} elseif(strcasecmp($order, 'desc') == 0) {
379 2
			$column .= ' DESC';
380
		}
381
382 4
		$this->orderBy[] = $column;
383
384 4
		return $this;
385
	}
386
387
	/**
388
	 * Returns the order by clause.
389
	 *
390
	 * @return string the order by clause.
391
	 */
392 33
	private function getOrderByClause()
393
	{
394 33
		if (empty($this->orderBy)) {
395 29
			return '';
396
		}
397
398 4
		return sprintf('ORDER BY %s', implode(', ', $this->orderBy));
399
	}
400
401
	/**
402
	 * {@inheritdoc}
403
	 */
404 6
	public function limit($limit)
405
	{
406 6
		$this->limit = $limit;
407
408 6
		return $this;
409
	}
410
411
	/**
412
	 * Returns the limit clause.
413
	 *
414
	 * @return string the limit clause.
415
	 */
416 40
	private function getLimitClause()
417
	{
418 40
		if (!$this->limit) {
419 34
			return '';
420
		}
421
422 6
		return sprintf('LIMIT %s', $this->limit);
423
	}
424
425
	/**
426
	 * {@inheritdoc}
427
	 */
428 2
	public function offset($offset)
429
	{
430 2
		$this->offset = $offset;
431
432 2
		return $this;
433
	}
434
435
	/**
436
	 * Returns the offset clause.
437
	 *
438
	 * @return string the offset clause.
439
	 */
440 33
	private function getOffsetClause()
441
	{
442 33
		if (!$this->limit || !$this->offset) {
443 31
			return '';
444
		}
445
446 2
		return sprintf('OFFSET %s', $this->offset);
447
	}
448
}
449