Files
emails/api/common/Implement/Repository.php
2022-11-29 08:57:56 -03:00

187 lines
5.9 KiB
PHP

<?php
namespace ProVM\Common\Implement;
use PDO;
use PDOException;
use ProVM\Common\Exception\Database\BlankResult;
use Psr\Log\LoggerInterface;
use ProVM\Common\Define\Model as ModelInterface;
abstract class Repository
{
public function __construct(PDO $connection, LoggerInterface $logger)
{
$this->setConnection($connection)
->setLogger($logger);
}
protected PDO $connection;
protected string $table;
protected LoggerInterface $logger;
public function getConnection(): PDO
{
return $this->connection;
}
public function getTable(): string
{
return $this->table;
}
public function getLogger(): LoggerInterface
{
return $this->logger;
}
public function setConnection(PDO $pdo): Repository
{
$this->connection = $pdo;
return $this;
}
public function setTable(string $table): Repository
{
$this->table = $table;
return $this;
}
public function setLogger(LoggerInterface $logger): Repository
{
$this->logger = $logger;
return $this;
}
abstract protected function fieldsForUpdate(): array;
abstract protected function valuesForUpdate(ModelInterface $model): array;
protected function idProperty(): string
{
return 'getId';
}
protected function idField(): string
{
return 'id';
}
public function update(ModelInterface $model, ModelInterface $old): void
{
$query = "UPDATE `{$this->getTable()}` SET ";
$model_values = $this->valuesForUpdate($model);
$old_values = $this->valuesForUpdate($old);
$columns = [];
$values = [];
foreach ($this->fieldsForUpdate() as $i => $column) {
if (isset($model_values[$i]) and $old_values[$i] !== $model_values[$i]) {
$columns []= "`{$column}` = ?";
$values []= $model_values[$i];
}
}
if (count($columns) === 0) {
return;
}
$query .= implode(', ', $columns) . " WHERE {$this->idField()} = ?";
$values []= $old->{$this->idProperty()}();
$st = $this->getConnection()->prepare($query);
$st->execute($values);
}
abstract protected function fieldsForInsert(): array;
abstract protected function valuesForInsert(ModelInterface $model): array;
protected function insert(ModelInterface $model): void
{
$fields = $this->fieldsForInsert();
$fields_string = implode(', ', array_map(function($field) {
return "`{$field}`";
}, $fields));
$fields_questions = implode(', ', array_fill(0, count($fields), '?'));
$query = "INSERT INTO `{$this->getTable()}` ({$fields_string}) VALUES ({$fields_questions})";
$values = $this->valuesForInsert($model);
$st = $this->getConnection()->prepare($query);
$st->execute($values);
}
abstract protected function defaultFind(ModelInterface $model): ModelInterface;
public function save(ModelInterface &$model): void
{
try {
$old = $this->defaultFind($model);
$this->update($model, $old);
} catch (BlankResult $e) {
$this->insert($model);
$model->setId($this->getConnection()->lastInsertId());
} catch(PDOException $e) {
$this->getLogger()->error($e);
throw $e;
}
}
abstract public function load(array $row): ModelInterface;
abstract protected function fieldsForCreate(): array;
abstract protected function valuesForCreate(array $data): array;
abstract protected function defaultSearch(array $data): ModelInterface;
public function create(array $data): ModelInterface
{
try {
return $this->defaultSearch($data);
} catch (PDOException | BlankResult $e) {
$data[$this->idField()] = 0;
return $this->load($data);
}
}
protected function getId(ModelInterface $model): int
{
return $model->getId();
}
public function resetIndex(): void
{
$query = "ALTER TABLE `{$this->getTable()}` AUTO_INCREMENT = 1";
$this->getConnection()->query($query);
}
public function optimize(): void
{
$query = "OPTIMIZE TABLE `{$this->getTable()}`";
$this->getConnection()->query($query);
}
public function delete(ModelInterface $model): void
{
$query = "DELETE FROM `{$this->getTable()}` WHERE `{$this->idField()}` = ?";
$st = $this->getConnection()->prepare($query);
$st->execute([$this->getId($model)]);
$this->resetIndex();
$this->optimize();
}
protected function fetchOne(string $query, ?array $values = null): ModelInterface
{
if ($values !== null) {
$st = $this->getConnection()->prepare($query);
$st->execute($values);
} else {
$st = $this->getConnection()->query($query);
}
$row = $st->fetch(PDO::FETCH_ASSOC);
if (!$row) {
throw new BlankResult();
}
return $this->load($row);
}
protected function fetchMany(string $query, ?array $values = null): array
{
if ($values !== null) {
$st = $this->getConnection()->prepare($query);
$st->execute($values);
} else {
$st = $this->getConnection()->query($query);
}
$rows = $st->fetchAll(PDO::FETCH_ASSOC);
if (!$rows) {
throw new BlankResult();
}
return array_map([$this, 'load'], $rows);
}
public function fetchAll(): array
{
$query = "SELECT * FROM `{$this->getTable()}`";
return $this->fetchMany($query);
}
public function fetchById(int $id): ModelInterface
{
$query = "SELECT * FROM `{$this->getTable()}` WHERE `{$this->idField()}` = ?";
return $this->fetchOne($query, [$id]);
}
}