Orm::exists()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 1
b 1
f 0
1
<?php
2
3
namespace Win\Repositories\Database;
4
5
use Win\Application;
6
use Win\Common\Pagination;
7
use Win\Models\Model;
8
use Win\HttpException;
9
10
/**
11
 * Object Relational Mapping
12
 */
13
abstract class Orm
14
{
15
	const TABLE = '';
16
	const PK = 'id';
17
18
	public Connection $conn;
19
	public ?Pagination $pagination = null;
20
	protected Sql $sql;
21
22
	/**
23
	 * @param Model $model
24
	 * @return mixed[]
25
	 */
26
	abstract public static function mapRow($model);
27
28
	abstract public static function mapModel($row);
29
30
	/**
31
	 * @param Connection $connection
32
	 */
33
	public function __construct(?Connection $connection = null)
34
	{
35
		$this->conn = $connection ?: Application::app()->conn;
36
		$this->sql = new Sql(static::TABLE);
37
	}
38
39
	/**
40
	 * Executa SQL
41
	 * @param string $query
42
	 * @param mixed[]
43
	 */
44
	protected function execute($query, ...$values)
45
	{
46
		return $this->conn->execute($query, $values);
47
	}
48
49
	/**
50
	 * Retorna o primeiro resultado da busca
51
	 * @return Model
52
	 */
53
	public function one()
54
	{
55
		$this->sql->setLimit(0, 1);
56
57
		$query = $this->sql->select();
58
		$values = $this->sql->values();
59
		$row = $this->conn->fetch($query, $values);
60
		$this->flush();
61
62
		if ($row !== false) {
63
			return $this->mapModel($row);
64
		}
65
	}
66
67
	/**
68
	 * Retorna o primeiro resultado da busca ou redireciona para Página 404
69
	 */
70
	public function oneOr404()
71
	{
72
		$model = $this->one();
73
		if (is_null($model)) {
74
			throw new HttpException('Model not found', 404);
75
		}
76
77
		return $model;
78
	}
79
80
	/**
81
	 * Retorna o registro pela PK
82
	 * @param int $id
83
	 */
84
	public function find($id)
85
	{
86
		return $this->filter(static::PK, $id)->one();
87
	}
88
89
	/**
90
	 * Retorna o registro pela PK ou redireciona para Página 404
91
	 * @param int $id
92
	 */
93
	public function findOr404($id)
94
	{
95
		return $this->filter(static::PK, $id)->oneOr404();
96
	}
97
98
	/**
99
	 * Retorna o todos os resultados da busca
100
	 */
101
	public function list()
102
	{
103
		if (!is_null($this->pagination)) {
104
			$this->setLimit();
105
		}
106
107
		$query = $this->sql->select();
108
		$values = $this->sql->values();
109
		$rows = $this->conn->fetchAll($query, $values);
110
		$this->flush();
111
112
		return array_map([$this, 'mapModel'], $rows);
113
	}
114
115
	/**
116
	 * Retorna o total de resultados da busca
117
	 * @return int
118
	 */
119
	public function count()
120
	{
121
		$query = $this->sql->selectCount();
122
		$values = $this->sql->values();
123
124
		$count = $this->conn->fetchCount($query, $values);
125
		$this->flush();
126
127
		return $count;
128
	}
129
130
	/**
131
	 * Remove todos os registros da busca
132
	 */
133
	public function delete()
134
	{
135
		$query = $this->sql->delete();
136
		$values = $this->sql->values();
137
		$this->conn->execute($query, $values);
138
		$this->flush();
139
	}
140
141
	/**
142
	 * Remove o registro pela PK
143
	 * @param int $id
144
	 */
145
	public function destroy($id)
146
	{
147
		$this->filter(static::PK, $id);
148
149
		$query = $this->sql->delete();
150
		$values = $this->sql->values();
151
		$this->conn->execute($query, $values);
152
		$this->flush();
153
	}
154
155
	/**
156
	 * Salva o registro no banco
157
	 * @param Model $model
158
	 */
159
	public function save(Model $model)
160
	{
161
		$model->validate();
162
		$this->sql = new Sql(static::TABLE, $this->mapRow($model));
163
164
		if ($this->exists($model->id)) {
165
			$this->filter(static::PK, $model->id);
166
			$query = $this->sql->update();
167
		} else {
168
			$query = $this->sql->insert();
169
		}
170
		$values = array_values($this->sql->values());
171
		$this->conn->execute($query, $values);
172
		$model->id = $model->id ?? $this->conn->lastInsertId();
173
174
		$this->flush();
175
		return $model;
176
	}
177
178
	/**
179
	 * Atualiza somente as colunas informadas
180
	 * @param mixed[] $columns
181
	 * @return int
182
	 */
183
	public function update($columns)
184
	{
185
		$this->sql->setValues($columns);
186
		$query = $this->sql->update();
187
		$values = array_values($this->sql->values());
188
		$stmt = $this->conn->stmt($query, $values);
189
		$this->flush();
190
191
		return $stmt->rowCount();
192
	}
193
194
	/**
195
	 * Remove todos os filtros e ordenação
196
	 */
197
	public function flush()
198
	{
199
		$this->sql = new Sql(static::TABLE);
200
201
		return $this;
202
	}
203
204
	/**
205
	 * Retorna TRUE se o model existir no banco
206
	 * @param int $id
207
	 * @return bool
208
	 */
209
	protected function exists($id)
210
	{
211
		$orm = new static($this->conn);
212
		return $orm->filter(static::PK, $id)->count() > 0;
213
	}
214
215
	/**
216
	 * Define as colunas da busca
217
	 * @param string $columns
218
	 */
219
	public function select(...$columns)
220
	{
221
		$this->sql->columns = $columns;
222
223
		return $this;
224
	}
225
226
	/**
227
	 * Adiciona (inner) join
228
	 * @param string $query
229
	 */
230
	public function join($query)
231
	{
232
		$this->sql->addJoin('JOIN ' . $query);
233
234
		return $this;
235
	}
236
237
	/**
238
	 * Adiciona left join
239
	 * @param string $query
240
	 */
241
	public function leftJoin($query)
242
	{
243
		$this->sql->addJoin('LEFT JOIN ' . $query);
244
245
		return $this;
246
	}
247
248
	/**
249
	 * Adiciona right join
250
	 * @param string $query
251
	 */
252
	public function rightJoin($query)
253
	{
254
		$this->sql->addJoin('RIGHT JOIN ' . $query);
255
256
		return $this;
257
	}
258
259
	/**
260
	 * Aplica filtros
261
	 * @param string $comparator
262
	 * @param mixed $values
263
	 * @example filter('name', 'John')
264
	 * @example filter('name = ? OR email = ?', 'John', 'email')
265
	 */
266
	public function filter($comparator, ...$values)
267
	{
268
		$this->sql->addWhere($comparator, $values);
269
270
		return $this;
271
	}
272
273
	/**
274
	 * Aplica filtros (aceita bind params)
275
	 * @param string $query
276
	 * @param mixed[] $values
277
	 * @example filterBy('name = :name OR age > 0', [':name' => 'John'])
278
	 */
279
	public function filterBy($query, $values = [])
280
	{
281
		$this->sql->addWhere($query, $values);
282
283
		return $this;
284
	}
285
286
	/**
287
	 * Ordem por um campo
288
	 * @param string $rule
289
	 * @param int $priority
290
	 */
291
	public function sort($rule, $priority = 0)
292
	{
293
		$this->sql->addOrderBy($rule, $priority);
294
295
		return $this;
296
	}
297
298
	/**
299
	 * Define um limite das buscas com list()
300
	 * @param int $pageSize
301
	 * @param int $currentPage
302
	 */
303
	public function paginate($pageSize, $currentPage = 1)
304
	{
305
		$this->pagination = new Pagination($pageSize, $currentPage);
306
		return $this;
307
	}
308
309
	/**
310
	 * Define o limit com base na paginação
311
	 */
312
	private function setLimit()
313
	{
314
		$query = $this->sql->selectCount();
315
		$values = $this->sql->values();
316
		$count = $this->conn->fetchCount($query, $values);
317
318
		if ($count && $this->pagination) {
319
			$this->pagination->setCount($count);
320
			$this->sql->setLimit($this->pagination->offset, $this->pagination->pageSize);
321
		}
322
	}
323
324
	/**
325
	 * Exibe a query e os valores para debug
326
	 * @param string $method
327
	 * @return array<string,mixed>
328
	 */
329
	public function debug($method = 'select')
330
	{
331
		return [$this->sql->$method(), $this->sql->values()];
332
	}
333
}
334