Passed
Push — master ( 4e8d12...2d631b )
by Ron
02:08
created

MySQLSelect::from()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 8
rs 10
cc 2
nc 2
nop 2
1
<?php
2
namespace Kir\MySQL\Databases\MySQL;
3
4
use Kir\MySQL\Builder\RunnableSelect;
5
use Kir\MySQL\Builder\Select;
6
use Kir\MySQL\Builder\Statement;
7
use Kir\MySQL\Builder\Traits\GroupByBuilder;
8
use Kir\MySQL\Builder\Traits\HavingBuilder;
9
use Kir\MySQL\Builder\Traits\OffsetBuilder;
10
use Kir\MySQL\Builder\Traits\OrderByBuilder;
11
use Kir\MySQL\Builder\Traits\TableBuilder;
12
use Kir\MySQL\Builder\Traits\JoinBuilder;
13
use Kir\MySQL\Builder\Traits\LimitBuilder;
14
use Kir\MySQL\Builder\Traits\TableNameBuilder;
15
use Kir\MySQL\Builder\Traits\UnionBuilder;
16
use Kir\MySQL\Builder\Traits\WhereBuilder;
17
use Kir\MySQL\Tools\VirtualTable;
18
use RuntimeException;
19
20
/**
21
 */
22
abstract class MySQLSelect extends Statement implements RunnableSelect {
23
	use TableNameBuilder;
24
	use TableBuilder;
25
	use JoinBuilder;
26
	use WhereBuilder;
27
	use HavingBuilder;
28
	use GroupByBuilder;
29
	use OrderByBuilder;
30
	use LimitBuilder;
31
	use OffsetBuilder;
32
	use UnionBuilder;
33
34
	/** @var array<int|string, string> */
35
	private $fields = [];
36
	/** @var bool */
37
	private $calcFoundRows = false;
38
	/** @var bool */
39
	private $forUpdate = false;
40
	/** @var bool */
41
	private $distinct = false;
42
43
	/**
44
	 * @param bool $distinct
45
	 * @return $this
46
	 */
47
	public function distinct(bool $distinct = true) {
48
		$this->distinct = $distinct;
49
		return $this;
50
	}
51
52
	/**
53
	 * @param string|Select $expression
54
	 * @param string|null $alias
55
	 * @return $this
56
	 */
57
	public function field($expression, $alias = null) {
58
		if (is_object($expression)) {
59
			$expression = (string) $expression;
60
			$expression = trim($expression);
61
			$expression = rtrim($expression, ';');
62
			$expression = trim($expression);
63
			$lines = explode("\n", $expression);
64
			$lines = array_map(static function($line) { return "\t\t{$line}"; }, $lines);
65
			$expression = implode("\n", $lines);
66
			$expression = sprintf("(\n%s\n\t)", $expression);
67
		}
68
		if ($alias === null) {
69
			$this->fields[] = $expression;
70
		} else {
71
			$this->fields[$alias] = $expression;
72
		}
73
		return $this;
74
	}
75
76
	/**
77
	 * @param array<string, string>|array<int, string> $fields
78
	 * @return $this
79
	 */
80
	public function fields(array $fields) {
81
		foreach ($fields as $alias => $expression) {
82
			$this->field($expression, is_int($alias) ? null : $alias);
83
		}
84
		return $this;
85
	}
86
87
	/**
88
	 * @return array<int|string, string>
89
	 */
90
	public function getFields(): array {
91
		return $this->fields;
92
	}
93
94
	/**
95
	 * @param bool $enabled
96
	 * @return $this
97
	 */
98
	public function forUpdate(bool $enabled = true) {
99
		$this->forUpdate = $enabled;
100
		return $this;
101
	}
102
103
	/**
104
	 * @return bool
105
	 */
106
	public function getCalcFoundRows(): bool {
107
		return $this->calcFoundRows;
108
	}
109
110
	/**
111
	 * @param bool $calcFoundRows
112
	 * @return $this
113
	 */
114
	public function setCalcFoundRows($calcFoundRows = true) {
115
		if (ini_get("mysql.trace_mode")) {
116
			throw new RuntimeException('This function cant operate with mysql.trace_mode is set.');
117
		}
118
		$this->calcFoundRows = $calcFoundRows;
119
		return $this;
120
	}
121
122
	/**
123
	 * @param null|string $alias
124
	 * @param null|string|Select|VirtualTable|array<int, null|int|float|string|array<string, mixed>> $table
125
	 * @return $this
126
	 */
127
	public function from(?string $alias, $table = null) {
128
		if($table === null) {
129
			[$alias, $table] = [$table, $alias];
130
			$this->addTable($alias, (string) $table);
131
		} else {
132
			$this->addTable($alias, $table);
133
		}
134
		return $this;
135
	}
136
137
	/**
138
	 * @return string
139
	 */
140
	public function __toString(): string {
141
		$query = "SELECT";
142
		if ($this->calcFoundRows) {
143
			$query .= " SQL_CALC_FOUND_ROWS";
144
		}
145
		if ($this->distinct) {
146
			$query .= " DISTINCT";
147
		}
148
		$query .= "\n";
149
		$query = $this->buildFields($query);
150
		if (count($this->getTables())) {
151
			$query .= "FROM\n";
152
		}
153
		$query = $this->buildTables($query);
154
		$query = $this->buildJoins($query);
155
		$query = $this->buildWhereConditions($query);
156
		$query = $this->buildGroups($query);
157
		$query = $this->buildHavingConditions($query);
158
		$query = $this->buildOrder($query);
159
		$query = $this->buildLimit($query, $this->getOffset());
160
		$query = $this->buildOffset($query);
161
		$query = $this->buildUnions($query);
162
		$query = $this->buildForUpdate($query);
163
		return $query;
164
	}
165
166
	/**
167
	 * @param string $query
168
	 * @return string
169
	 */
170
	private function buildFields(string $query): string {
171
		$fields = [];
172
		if (count($this->fields)) {
173
			foreach ($this->fields as $alias => $expression) {
174
				if (is_numeric($alias)) {
175
					$fields[] = "\t{$expression}";
176
				} else {
177
					$fields[] = "\t{$expression} AS `{$alias}`";
178
				}
179
			}
180
		} else {
181
			$fields[] = "\t*";
182
		}
183
		return $query.implode(",\n", $fields)."\n";
184
	}
185
186
	/**
187
	 * @param string $query
188
	 * @return string
189
	 */
190
	private function buildForUpdate(string $query): string {
191
		if ($this->forUpdate) {
192
			$query .= "FOR UPDATE\n";
193
		}
194
		return $query;
195
	}
196
}
197