Completed
Push — master ( 466d49...06d08c )
by smiley
05:19
created

SelectAbstract::cached()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 0
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\DBResult;
17
use chillerlan\Database\Query\Traits\WhereTrait;
18
19
abstract class SelectAbstract extends StatementAbstract implements SelectInterface{
20
	use WhereTrait;
21
22
	/**
23
	 * @var bool
24
	 */
25
	protected $distinct = false;
26
27
	/**
28
	 * @var array
29
	 */
30
	protected $cols = [];
31
32
	/**
33
	 * @var array
34
	 */
35
	protected $from = [];
36
37
	/**
38
	 * @var array
39
	 */
40
	protected $orderby = [];
41
42
	/**
43
	 * @var array
44
	 */
45
	protected $groupby = [];
46
47
	public function cached():SelectInterface{
48
		$this->cached = true;
49
50
		return $this;
51
	}
52
53
	/**
54
	 * @param        $val1
55
	 * @param        $val2
56
	 * @param string $operator
57
	 * @param bool   $bind
58
	 * @param string $join
59
	 *
60
	 * @return \chillerlan\Database\Query\SelectInterface
61
	 */
62
	public function where($val1, $val2, $operator = '=', $bind = true, $join = 'AND'):SelectInterface{
63
		return $this->_addWhere($val1, $val2, $operator, $bind, $join);
64
	}
65
66
	/**
67
	 * @param null $join
68
	 *
69
	 * @return \chillerlan\Database\Query\SelectInterface
70
	 */
71
	public function openBracket($join = null):SelectInterface{
72
		return $this->_openBracket($join); // @codeCoverageIgnore
73
	}
74
75
	/**
76
	 * @return \chillerlan\Database\Query\SelectInterface
77
	 */
78
	public function closeBracket():SelectInterface{
79
		return $this->_closeBracket(); // @codeCoverageIgnore
80
	}
81
82
	/**
83
	 * @return \chillerlan\Database\Query\SelectInterface
84
	 */
85
	public function distinct():SelectInterface{
86
		$this->distinct = true;
87
88
		return $this;
89
	}
90
91
	/**
92
	 * @param      $expr1
93
	 * @param null $expr2
94
	 * @param null $func
95
	 *
96
	 * @return void
97
	 */
98
	protected function addColumn($expr1, $expr2 = null, $func = null){
99
		// @todo: quotes
100
		switch(true){
101 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...
102
				$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...
103 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...
104
				$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...
105 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...
106
				$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...
107
			case !$expr2 && !$func:
108
			default:
109
				$col = $this->quote($expr1);
110
		}
111
112
		$this->cols[$expr2 ?? $expr1] = $col;
113
	}
114
115
	/**
116
	 * @param array $expressions
117
	 *
118
	 * @return \chillerlan\Database\Query\SelectInterface
119
	 */
120
	public function cols(array $expressions):SelectInterface{
121
122
		foreach($expressions as $k => $ref){
123
124
			if(is_string($k)){
125
				is_array($ref)
126
					? $this->addColumn($ref[0], $k, $ref[1] ?? null)
127
					: $this->addColumn($ref ,$k);
128
			}
129
			else{
130
				is_array($ref)
131
					? $this->addColumn($ref[0], null, $ref[1] ?? null)
132
					: $this->addColumn($ref);
133
			}
134
135
		}
136
137
		return $this;
138
	}
139
140
	/**
141
	 * @param string      $table
142
	 * @param string|null $ref
143
	 */
144
	protected function _addFrom(string $table, string $ref = null){
145
		// @todo: quotes
146
		$from = $this->quote($table);
147
148
		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...
149
			$from = sprintf('%s AS %s', $this->quote($ref), $this->quote($table));// @todo: index hint
150
		}
151
152
		$this->from[$ref ?? $table] = $from;
153
	}
154
155
	/**
156
	 * @param array $expressions
157
	 *
158
	 * @return \chillerlan\Database\Query\SelectInterface
159
	 */
160
	public function from(array $expressions):SelectInterface{
161
162
		foreach($expressions as $k => $ref){
163
164
			if(is_string($k)){
165
				$this->_addFrom($k, $ref);
166
			}
167
			else{
168
				$x = explode(' ', $ref);
169
170
				if(count($x) === 2){
171
					$this->_addFrom($x[0], $x[1]);
172
				}
173
				else{
174
					$this->_addFrom($ref);
175
				}
176
			}
177
178
		}
179
180
		return $this;
181
	}
182
183
	/**
184
	 * @param int $limit
185
	 *
186
	 * @return \chillerlan\Database\Query\SelectInterface
187
	 */
188
	public function limit(int $limit):SelectInterface{
189
		$this->limit = $limit;
190
191
		return $this;
192
	}
193
194
	/**
195
	 * @param int $offset
196
	 *
197
	 * @return \chillerlan\Database\Query\SelectInterface
198
	 */
199
	public function offset(int $offset):SelectInterface{
200
		$this->offset = $offset;
201
202
		return $this;
203
	}
204
205
	/**
206
	 * @param array $expressions
207
	 *
208
	 * @return \chillerlan\Database\Query\SelectInterface
209
	 */
210
	public function orderBy(array $expressions):SelectInterface{
211
212
		foreach($expressions as $alias => $expression){
213
214
			if(is_string($alias)){
215
216
				if(is_array($expression)){
217
					$dir = strtoupper($expression[0]);
218
219
					if(in_array($dir, ['ASC', 'DESC'])){
220
						$this->orderby[] =  isset($expression[1]) ? strtoupper($expression[1]).'('.$this->quote($alias).') '.$dir : $dir;
221
					}
222
223
				}
224
				else{
225
					$dir = strtoupper($expression);
226
227
					if(in_array($dir, ['ASC', 'DESC'])){
228
						$this->orderby[] =  $this->quote($alias).' '.$dir;
229
					}
230
231
				}
232
233
			}
234
			else{
235
				$this->orderby[] = $this->quote($expression);
236
			}
237
238
		}
239
240
		return $this;
241
	}
242
243
	/**
244
	 * @param array $expressions
245
	 *
246
	 * @return \chillerlan\Database\Query\SelectInterface
247
	 */
248
	public function groupBy(array $expressions):SelectInterface{
249
250
		foreach($expressions as $expression){
251
			$this->groupby[] = $this->quote($expression);
252
		}
253
254
		return $this;
255
	}
256
257
	/**
258
	 * @todo
259
	 *
260
	 * @return int
261
	 * @throws \chillerlan\Database\Query\QueryException
262
	 */
263
	public function count():int{
264
265
		if(empty($this->from)){
266
			throw new QueryException('no FROM expression specified');
267
		}
268
269
		$glue = ','.PHP_EOL."\t";
270
271
		$sql  = 'SELECT ';
272
		$sql .= $this->distinct ? 'DISTINCT ' : '';
273
		$sql .= 'COUNT(*) AS  '.$this->quote('count');
274
		$sql .= 'FROM '.implode($glue , $this->from);
275
		$sql .= $this->_getWhere();
276
		$sql .= !empty($this->groupby) ? PHP_EOL.'GROUP BY '.implode($glue, $this->groupby) : '';
277
278
		$q = $this->DBDriver->prepared($sql, $this->bindValues);
279
280
		if($q instanceof DBResult && $q->length > 0){
281
			return (int)$q[0]->count;
282
		}
283
284
		return -1;
285
	}
286
287
}
288