Completed
Push — master ( 57d77d...021fc0 )
by smiley
02:58
created

SelectAbstract::where()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 5
1
<?php
2
/**
3
 * Class SelectAbstract
4
 *
5
 * @filesource   SelectAbstract.php
6
 * @created      03.06.2017
7
 * @package      chillerlan\Database\Query\Dialects
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2017 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\Database\Query;
14
15
16
use chillerlan\Database\Query\Traits\WhereTrait;
17
18
abstract class SelectAbstract extends StatementAbstract implements SelectInterface{
19
	use WhereTrait;
20
21
	/**
22
	 * @var bool
23
	 */
24
	protected $distinct = false;
25
26
	/**
27
	 * @var array
28
	 */
29
	protected $cols = [];
30
31
	/**
32
	 * @var array
33
	 */
34
	protected $from = [];
35
36
	/**
37
	 * @var array
38
	 */
39
	protected $orderby = [];
40
41
	/**
42
	 * @var array
43
	 */
44
	protected $groupby = [];
45
46
47
	/**
48
	 * @param        $val1
49
	 * @param        $val2
50
	 * @param string $operator
51
	 * @param bool   $bind
52
	 * @param string $join
53
	 *
54
	 * @return \chillerlan\Database\Query\SelectInterface
55
	 */
56
	public function where($val1, $val2, $operator = '=', $bind = true, $join = 'AND'):SelectInterface{
57
		return $this->_addWhere($val1, $val2, $operator, $bind, $join);
58
	}
59
60
	/**
61
	 * @param null $join
62
	 *
63
	 * @return \chillerlan\Database\Query\SelectInterface
64
	 */
65
	public function openBracket($join = null):SelectInterface{
66
		return $this->_openBracket($join); // @codeCoverageIgnore
67
	}
68
69
	/**
70
	 * @return \chillerlan\Database\Query\SelectInterface
71
	 */
72
	public function closeBracket():SelectInterface{
73
		return $this->_closeBracket(); // @codeCoverageIgnore
74
	}
75
76
	/**
77
	 * @return \chillerlan\Database\Query\SelectInterface
78
	 */
79
	public function distinct():SelectInterface{
80
		$this->distinct = true;
81
82
		return $this;
83
	}
84
85
	/**
86
	 * @param      $expr1
87
	 * @param null $expr2
88
	 * @param null $func
89
	 *
90
	 * @return void
91
	 */
92
	protected function addColumn($expr1, $expr2 = null, $func = null){
93
		// @todo: quotes
94
		switch(true){
95 View Code Duplication
			case  $expr2 && $func:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
96
				$col = sprintf('%s(%s) AS %s', strtoupper($func), $this->quote($expr1), $this->quote($expr2)); break;
0 ignored issues
show
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
97 View Code Duplication
			case  $expr2 && !$func:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
98
				$col = sprintf('%s AS %s', $this->quote($expr1), $this->quote($expr2)); break;
0 ignored issues
show
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
99 View Code Duplication
			case !$expr2 && $func:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
100
				$col = sprintf('%s(%s)', strtoupper($func), $this->quote($expr1)); break;
0 ignored issues
show
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
101
			case !$expr2 && !$func:
102
			default:
103
				$col = $this->quote($expr1);
104
		}
105
106
		$this->cols[$expr2 ?? $expr1] = $col;
107
	}
108
109
	/**
110
	 * @param array $expressions
111
	 *
112
	 * @return \chillerlan\Database\Query\SelectInterface
113
	 */
114
	public function cols(array $expressions):SelectInterface{
115
116
		foreach($expressions as $k => $ref){
117
118
			if(is_string($k)){
119
				is_array($ref)
120
					? $this->addColumn($ref[0], $k, $ref[1] ?? null)
121
					: $this->addColumn($ref ,$k);
122
			}
123
			else{
124
				is_array($ref)
125
					? $this->addColumn($ref[0], null, $ref[1] ?? null)
126
					: $this->addColumn($ref);
127
			}
128
129
		}
130
131
		return $this;
132
	}
133
134
	/**
135
	 * @param string      $table
136
	 * @param string|null $ref
137
	 */
138
	protected function _addFrom(string $table, string $ref = null){
139
		// @todo: quotes
140
		$from = $this->quote($table);
141
142
		if($ref){
0 ignored issues
show
Bug Best Practice introduced by
The expression $ref of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
143
			$from = sprintf('%s AS %s', $this->quote($ref), $this->quote($table));// @todo: index hint
144
		}
145
146
		$this->from[$ref ?? $table] = $from;
147
	}
148
149
	/**
150
	 * @param array $expressions
151
	 *
152
	 * @return \chillerlan\Database\Query\SelectInterface
153
	 */
154
	public function from(array $expressions):SelectInterface{
155
156
		foreach($expressions as $k => $ref){
157
158
			if(is_string($k)){
159
				$this->_addFrom($k, $ref);
160
			}
161
			else{
162
				$x = explode(' ', $ref);
163
164
				if(count($x) === 2){
165
					$this->_addFrom($x[0], $x[1]);
166
				}
167
				else{
168
					$this->_addFrom($ref);
169
				}
170
			}
171
172
		}
173
174
		return $this;
175
	}
176
177
	/**
178
	 * @param int $limit
179
	 *
180
	 * @return \chillerlan\Database\Query\SelectInterface
181
	 */
182
	public function limit(int $limit):SelectInterface{
183
		$this->limit = $limit;
184
185
		return $this;
186
	}
187
188
	/**
189
	 * @param int $offset
190
	 *
191
	 * @return \chillerlan\Database\Query\SelectInterface
192
	 */
193
	public function offset(int $offset):SelectInterface{
194
		$this->offset = $offset;
195
196
		return $this;
197
	}
198
199
	/**
200
	 * @param array $expressions
201
	 *
202
	 * @return \chillerlan\Database\Query\SelectInterface
203
	 */
204
	public function orderBy(array $expressions):SelectInterface{
205
206
		foreach($expressions as $alias => $expression){
207
208
			if(is_string($alias)){
209
210
				if(is_array($expression)){
211
					$dir = strtoupper($expression[0]);
212
213
					if(in_array($dir, ['ASC', 'DESC'])){
214
						$this->orderby[] =  isset($expression[1]) ? strtoupper($expression[1]).'('.$this->quote($alias).') '.$dir : $dir;
215
					}
216
217
				}
218
				else{
219
					$dir = strtoupper($expression);
220
221
					if(in_array($dir, ['ASC', 'DESC'])){
222
						$this->orderby[] =  $this->quote($alias).' '.$dir;
223
					}
224
225
				}
226
227
			}
228
			else{
229
				$this->orderby[] = $this->quote($expression);
230
			}
231
232
		}
233
234
		return $this;
235
	}
236
237
	/**
238
	 * @param array $expressions
239
	 *
240
	 * @return \chillerlan\Database\Query\SelectInterface
241
	 */
242
	public function groupBy(array $expressions):SelectInterface{
243
244
		foreach($expressions as $expression){
245
			$this->groupby[] = $this->quote($expression);
246
		}
247
248
		return $this;
249
	}
250
251
	/**
252
	 * @todo
253
	 *
254
	 * @return int
255
	 * @throws \chillerlan\Database\Query\QueryException
256
	 */
257
	public function count():int{
258
259
		if(empty($this->from)){
260
			throw new QueryException('no FROM expression specified');
261
		}
262
263
		$glue = ','.PHP_EOL."\t";
264
265
		$sql  = 'SELECT ';
266
		$sql .= $this->distinct ? 'DISTINCT ' : '';
267
		$sql .= 'COUNT(*) AS  '.$this->quote('count');
268
		$sql .= 'FROM '.implode($glue , $this->from);
269
		$sql .= $this->_getWhere();
270
		$sql .= !empty($this->groupby) ? PHP_EOL.'GROUP BY '.implode($glue, $this->groupby) : '';
271
272
		$q = $this->DBDriver->prepared($sql, $this->bindValues);
273
274
		if($q->length){
275
			return (int)$q[0]->count;
276
		}
277
278
		return -1;
279
	}
280
281
}
282