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()]; | |
| } | |
| } |