Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
100.00% |
1 / 1 |
|
100.00% |
26 / 26 |
CRAP | |
100.00% |
108 / 108 |
Repository | |
100.00% |
1 / 1 |
|
100.00% |
26 / 26 |
41 | |
100.00% |
108 / 108 |
mapRow | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
mapModel | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
__construct | |
100.00% |
1 / 1 |
2 | |
100.00% |
6 / 6 |
|||
setTable | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
getTable | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
select | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
one | |
100.00% |
1 / 1 |
3 | |
100.00% |
12 / 12 |
|||
oneOr404 | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
find | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
findOr404 | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
list | |
100.00% |
1 / 1 |
2 | |
100.00% |
9 / 9 |
|||
setListLimit | |
100.00% |
1 / 1 |
2 | |
100.00% |
9 / 9 |
|||
count | |
100.00% |
1 / 1 |
2 | |
100.00% |
8 / 8 |
|||
paginate | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
delete | |
100.00% |
1 / 1 |
2 | |
100.00% |
7 / 7 |
|||
destroy | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
save | |
100.00% |
1 / 1 |
2 | |
100.00% |
9 / 9 |
|||
querySave | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
update | |
100.00% |
1 / 1 |
3 | |
100.00% |
9 / 9 |
|||
flush | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
exists | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
join | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
leftJoin | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
rightJoin | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
if | |
100.00% |
1 / 1 |
2 | |
100.00% |
2 / 2 |
|||
filter | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
sort | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
debug | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
<?php | |
namespace Win\Repositories; | |
use PDO; | |
use PDOException; | |
use Win\InjectableTrait; | |
use Win\HttpException; | |
use Win\Services\Pagination; | |
use Win\Models\Model; | |
/** | |
* Base Database Repository | |
* | |
* @method Model[] list() | |
* @method Model one() | |
* @method Model oneOr404() | |
* @method Model find($id) | |
* @method Model findOr404($id) | |
*/ | |
abstract class Repository | |
{ | |
use InjectableTrait; | |
static PDO $globalPdo; | |
public PDO $pdo; | |
public Pagination $pagination; | |
protected $table = ''; | |
protected $pk = 'id'; | |
protected Sql $sql; | |
/** | |
* @param Model $model | |
* @return mixed[] | |
*/ | |
abstract public static function mapRow($model); | |
abstract public static function mapModel($row); | |
public function __construct() | |
{ | |
if (!isset(static::$globalPdo)) { | |
static::$globalPdo = require BASE_PATH . '/config/database.php'; | |
} | |
$this->pdo = static::$globalPdo; | |
$this->sql = new Sql($this->table); | |
$this->pagination = new Pagination(); | |
} | |
/** | |
* Define a tabela manualmente | |
* @param string $table | |
*/ | |
public function setTable($table) | |
{ | |
$this->table = $table; | |
return $this; | |
} | |
public function getTable() | |
{ | |
return $this->table; | |
} | |
/** | |
* Define as colunas da busca | |
* @param string $columns | |
*/ | |
public function select($columns) | |
{ | |
$this->sql->columns[] = $columns; | |
return $this; | |
} | |
/** | |
* Retorna o primeiro resultado da busca | |
* @return Model | |
*/ | |
public function one() | |
{ | |
try { | |
$this->sql->setLimit(0, 1); | |
$query = $this->sql->select(); | |
$values = $this->sql->values(); | |
$this->flush(); | |
$stmt = $this->pdo->prepare($query); | |
$stmt->execute($values); | |
$row = $stmt->fetch(); | |
if ($row !== false) { | |
return $this->mapModel($row); | |
} | |
} catch (PDOException $e) { | |
throw new DbException('Ocorreu um erro ao ler no banco de dados.', 500, $e); | |
} | |
} | |
/** | |
* Retorna o primeiro resultado da busca ou redireciona para Página 404 | |
*/ | |
public function oneOr404() | |
{ | |
$model = $this->one(); | |
if (is_null($model)) { | |
throw new HttpException('O registro não foi encontrado no banco de dados.', 404); | |
} | |
return $model; | |
} | |
/** | |
* Retorna o registro pela PK | |
* @param int $id | |
*/ | |
public function find($id) | |
{ | |
return $this->if($this->pk, $id)->one(); | |
} | |
/** | |
* Retorna o registro pela PK ou redireciona para Página 404 | |
* @param int $id | |
*/ | |
public function findOr404($id) | |
{ | |
return $this->if($this->pk, $id)->oneOr404(); | |
} | |
/** | |
* Retorna o todos os resultados da busca | |
*/ | |
public function list() | |
{ | |
try { | |
$this->setListLimit(); | |
$query = $this->sql->select(); | |
$values = $this->sql->values(); | |
$this->flush(); | |
$stmt = $this->pdo->prepare($query); | |
$stmt->execute($values); | |
return array_map([$this, 'mapModel'], $stmt->fetchAll()); | |
} catch (PDOException $e) { | |
throw new DbException('Ocorreu um erro ao ler no banco de dados.', 500, $e); | |
} | |
} | |
protected function setListLimit() | |
{ | |
$pagination = $this->pagination; | |
if ($pagination->pageSize > 0) { | |
$query = $this->sql->selectCount(); | |
$values = $this->sql->values(); | |
$stmt = $this->pdo->prepare($query); | |
$stmt->execute($values); | |
$pagination->count = $stmt->fetchColumn(); | |
$this->sql->setLimit($pagination->offset(), $pagination->pageSize); | |
} | |
} | |
/** | |
* Retorna o total de resultados da busca | |
* @return int | |
*/ | |
public function count() | |
{ | |
try { | |
$query = $this->sql->selectCount(); | |
$values = $this->sql->values(); | |
$this->flush(); | |
$stmt = $this->pdo->prepare($query); | |
$stmt->execute($values); | |
return (int) $stmt->fetchColumn(); | |
} catch (PDOException $e) { | |
throw new DbException('Ocorreu um erro ao ler no banco de dados.', 500, $e); | |
} | |
} | |
/** | |
* Define um limite das buscas com list() | |
* @param int $pageSize | |
* @param int $currentPage | |
*/ | |
public function paginate($pageSize, $currentPage = 1) | |
{ | |
$this->pagination->pageSize = $pageSize; | |
$this->pagination->current = max($currentPage, 1); | |
return $this; | |
} | |
/** | |
* Remove todos os registros da busca | |
*/ | |
public function delete() | |
{ | |
try { | |
$query = $this->sql->delete(); | |
$values = $this->sql->values(); | |
$this->flush(); | |
$this->pdo->prepare($query)->execute($values); | |
} catch (PDOException $e) { | |
throw new DbException('Ocorreu um erro ao escrever no banco de dados.', 500, $e); | |
} | |
} | |
/** | |
* Remove o registro pela PK | |
* @param int $id | |
*/ | |
public function destroy($id) | |
{ | |
$this->if($this->pk, $id)->delete(); | |
} | |
/** | |
* Salva o registro no banco | |
* @param Model $model | |
*/ | |
public function save(Model $model) | |
{ | |
try { | |
$this->sql->setValues($this->mapRow($model)); | |
$query = $this->querySave($model); | |
$values = array_values($this->sql->values()); | |
$this->flush(); | |
$this->pdo->prepare($query)->execute($values); | |
$model->id = $model->id ?? $this->pdo->lastInsertId(); | |
return $this; | |
} catch (PDOException $e) { | |
throw new DbException('Ocorreu um erro ao escrever no banco de dados.', 500, $e); | |
} | |
} | |
/** | |
* @param Model $model | |
* @return string | |
*/ | |
protected function querySave($model) | |
{ | |
if ($this->exists($model->id)) { | |
$this->if($this->pk, $model->id); | |
return $this->sql->update(); | |
} else { | |
return $this->sql->insert(); | |
} | |
} | |
/** | |
* Atualiza somente as colunas informadas | |
* @param mixed[] $columns | |
* @return int | |
*/ | |
public function update($columns) | |
{ | |
try { | |
$this->sql->setValues($columns); | |
$query = $this->sql->update(); | |
$values = array_values($this->sql->values()); | |
$this->flush(); | |
$stmt = $this->pdo->prepare($query); | |
$stmt->execute($values); | |
return $stmt ? $stmt->rowCount() : null; | |
} catch (PDOException $e) { | |
throw new DbException('Ocorreu um erro ao escrever no banco de dados.', 500, $e); | |
} | |
} | |
/** | |
* Remove todos os filtros, ordenação, etc | |
*/ | |
public function flush() | |
{ | |
$this->sql->__construct($this->table); | |
return $this; | |
} | |
/** | |
* Retorna TRUE se o model existir no banco | |
* @param int $id | |
* @return bool | |
*/ | |
protected function exists($id) | |
{ | |
$orm = new static(); | |
$orm->pdo = $this->pdo; | |
$orm->table = $this->table; | |
return $orm->if($this->pk, $id)->count() > 0; | |
} | |
/** | |
* Adiciona (inner) join | |
* @param string $query | |
* @param array $values | |
*/ | |
public function join($query, ...$values) | |
{ | |
$this->sql->addJoin('JOIN ' . $query, $values); | |
return $this; | |
} | |
/** | |
* Adiciona left join | |
* @param string $query | |
* @param array $values | |
*/ | |
public function leftJoin($query, ...$values) | |
{ | |
$this->sql->addJoin('LEFT JOIN ' . $query, $values); | |
return $this; | |
} | |
/** | |
* Adiciona right join | |
* @param string $query | |
* @param array $values | |
*/ | |
public function rightJoin($query, ...$values) | |
{ | |
$this->sql->addJoin('RIGHT JOIN ' . $query, $values); | |
return $this; | |
} | |
/** | |
* Aplica filtros | |
* @param string $comparator | |
* @param mixed $values | |
* @example if('name', 'John') | |
* @example if('name = ? OR email = ?', 'John', 'email') | |
*/ | |
public function if($comparator, ...$values) | |
{ | |
$this->sql->addWhere($comparator, $values); | |
return $this; | |
} | |
/** | |
* Aplica filtros (aceita bind params) | |
* @param string $query | |
* @param mixed[] $values | |
* @example filter('name = :name OR age > 0', [':name' => 'John']) | |
*/ | |
public function filter($query, $values = []) | |
{ | |
$this->sql->addWhere($query, $values); | |
return $this; | |
} | |
/** | |
* Ordem por um campo | |
* @param string $rule | |
* @param int $priority | |
*/ | |
public function sort($rule, $priority = 0) | |
{ | |
$this->sql->addOrderBy($rule, $priority); | |
return $this; | |
} | |
/** | |
* Exibe a query e os valores para debug | |
* @param string $method | |
* @return array<string,mixed> | |
*/ | |
public function debug($method = 'select') | |
{ | |
return [$this->sql->$method(), ...$this->sql->values()]; | |
} | |
} |