Issues (83)

src/Databases/MySQL/MySQLSelect.php (3 issues)

Labels
1
<?php
2
namespace Kir\MySQL\Databases\MySQL;
3
4
use Kir\MySQL\Builder\Internal\Types;
5
use Kir\MySQL\Builder\RunnableSelect;
6
use Kir\MySQL\Builder\Select;
7
use Kir\MySQL\Builder\Statement;
8
use Kir\MySQL\Builder\Traits\GroupByBuilder;
9
use Kir\MySQL\Builder\Traits\HavingBuilder;
10
use Kir\MySQL\Builder\Traits\JoinBuilder;
11
use Kir\MySQL\Builder\Traits\LimitBuilder;
12
use Kir\MySQL\Builder\Traits\OffsetBuilder;
13
use Kir\MySQL\Builder\Traits\OrderByBuilder;
14
use Kir\MySQL\Builder\Traits\TableBuilder;
15
use Kir\MySQL\Builder\Traits\TableNameBuilder;
16
use Kir\MySQL\Builder\Traits\UnionBuilder;
17
use Kir\MySQL\Builder\Traits\WhereBuilder;
18
use RuntimeException;
19
20
/**
21
 * @phpstan-import-type DBTableNameType from Types
22
 */
23
abstract class MySQLSelect extends Statement implements RunnableSelect {
24
	use TableNameBuilder;
25
	use TableBuilder;
26
	use JoinBuilder;
27
	use WhereBuilder;
28
	use HavingBuilder;
29
	use GroupByBuilder;
30
	use OrderByBuilder;
31
	use LimitBuilder;
32
	use OffsetBuilder;
33
	use UnionBuilder;
34
35
	/** @var array<int|string, string> */
36
	private array $fields = [];
37
	private bool $calcFoundRows = false;
38
	private bool $forUpdate = false;
39
	private bool $distinct = false;
40
41
	/**
42
	 * @param bool $distinct
43
	 * @return $this
44
	 */
45
	public function distinct(bool $distinct = true) {
46
		$this->distinct = $distinct;
47
		return $this;
48
	}
49
50
	/**
51
	 * @param string|Select $expression
52
	 * @param string|null $alias
53
	 * @return $this
54
	 */
55
	public function field($expression, $alias = null) {
56
		if (is_object($expression)) {
57
			$expression = (string) $expression;
58
			$expression = trim($expression);
59
			$expression = rtrim($expression, ';');
60
			$expression = trim($expression);
61
			$lines = explode("\n", $expression);
62
			$lines = array_map(static fn($line) => "\t\t{$line}", $lines);
63
			$expression = implode("\n", $lines);
64
			$expression = sprintf("(\n%s\n\t)", $expression);
65
		}
66
		if ($alias === null) {
67
			$this->fields[] = $expression;
68
		} else {
69
			$this->fields[$alias] = $expression;
70
		}
71
		return $this;
72
	}
73
74
	/**
75
	 * @param array<string, string>|array<int, string> $fields
76
	 * @return $this
77
	 */
78
	public function fields(array $fields) {
79
		foreach ($fields as $alias => $expression) {
80
			$this->field($expression, is_int($alias) ? null : $alias);
81
		}
82
		return $this;
83
	}
84
85
	/**
86
	 * @return array<int|string, string>
87
	 */
88
	public function getFields(): array {
89
		return $this->fields;
90
	}
91
92
	/**
93
	 * @param bool $enabled
94
	 * @return $this
95
	 */
96
	public function forUpdate(bool $enabled = true) {
97
		$this->forUpdate = $enabled;
98
		return $this;
99
	}
100
101
	/**
102
	 * @return bool
103
	 */
104
	public function getCalcFoundRows(): bool {
105
		return $this->calcFoundRows;
106
	}
107
108
	/**
109
	 * @param bool $calcFoundRows
110
	 * @return $this
111
	 */
112
	public function setCalcFoundRows($calcFoundRows = true) {
113
		if (ini_get("mysql.trace_mode")) {
114
			throw new RuntimeException('This function cant operate with mysql.trace_mode is set.');
115
		}
116
		$this->calcFoundRows = $calcFoundRows;
117
		return $this;
118
	}
119
120
	/**
121
	 * @param ($table is null ? DBTableNameType : string) $alias
0 ignored issues
show
The type Kir\MySQL\Databases\MySQL\is was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
122
	 * @param null|DBTableNameType $table
0 ignored issues
show
The type Kir\MySQL\Databases\MySQL\DBTableNameType was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
123
	 * @return $this
124
	 */
125
	public function from($alias, $table = null) {
126
		if($table === null) {
127
			[$alias, $table] = [$table, $alias];
128
			$this->addTable($alias, (string) $table);
0 ignored issues
show
(string)$table of type string is incompatible with the type Kir\MySQL\Builder\Traits\DBTableNameType expected by parameter $table of Kir\MySQL\Databases\MySQL\MySQLSelect::addTable(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

128
			$this->addTable($alias, /** @scrutinizer ignore-type */ (string) $table);
Loading history...
129
		} else {
130
			$this->addTable($alias, $table);
131
		}
132
		return $this;
133
	}
134
135
	/**
136
	 * @return string
137
	 */
138
	public function __toString(): string {
139
		$query = "SELECT";
140
		if ($this->calcFoundRows) {
141
			$query .= " SQL_CALC_FOUND_ROWS";
142
		}
143
		if ($this->distinct) {
144
			$query .= " DISTINCT";
145
		}
146
		$query .= "\n";
147
		$query = $this->buildFields($query);
148
		if (count($this->getTables())) {
149
			$query .= "FROM\n";
150
		}
151
		$query = $this->buildTables($query);
152
		$query = $this->buildJoins($query);
153
		$query = $this->buildWhereConditions($query);
154
		$query = $this->buildGroups($query);
155
		$query = $this->buildHavingConditions($query);
156
		$query = $this->buildOrder($query);
157
		$query = $this->buildLimit($query, $this->getOffset());
158
		$query = $this->buildOffset($query);
159
		$query = $this->buildUnions($query);
160
		$query = $this->buildForUpdate($query);
161
		return $query;
162
	}
163
164
	/**
165
	 * @param string $query
166
	 * @return string
167
	 */
168
	private function buildFields(string $query): string {
169
		$fields = [];
170
		if (count($this->fields)) {
171
			foreach ($this->fields as $alias => $expression) {
172
				if (is_numeric($alias)) {
173
					$fields[] = "\t{$expression}";
174
				} else {
175
					$fields[] = "\t{$expression} AS `{$alias}`";
176
				}
177
			}
178
		} else {
179
			$fields[] = "\t*";
180
		}
181
		return $query.implode(",\n", $fields)."\n";
182
	}
183
184
	/**
185
	 * @param string $query
186
	 * @return string
187
	 */
188
	private function buildForUpdate(string $query): string {
189
		if ($this->forUpdate) {
190
			$query .= "FOR UPDATE\n";
191
		}
192
		return $query;
193
	}
194
}
195