Files
emails/api/common/Implement/Repository.php
2023-06-08 20:49:27 -04:00

196 lines
6.2 KiB
PHP

<?php
namespace ProVM\Common\Implement;
use PDO;
use PDOException;
use Psr\Log\LoggerInterface;
use ProVM\Common\Exception\Database\BlankResult;
use ProVM\Common\Define;
abstract class Repository implements Define\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): Define\Repository
{
$this->connection = $pdo;
return $this;
}
public function setTable(string $table): Define\Repository
{
$this->table = $table;
return $this;
}
public function setLogger(LoggerInterface $logger): Define\Repository
{
$this->logger = $logger;
return $this;
}
public function isInstalled(): bool
{
$query = "SHOW TABLES LIKE '{$this->getTable()}'";
$st = $this->getConnection()->query($query);
if ($st === false) {
throw new PDOException("Could not run query {$query}");
}
return $st->rowCount() > 0;
}
public function update(Define\Model $model, Define\Model $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);
}
public function save(Define\Model &$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;
}
}
public function create(array $data): Define\Model
{
try {
return $this->defaultSearch($data);
} catch (PDOException | BlankResult $e) {
$data[$this->idField()] = 0;
return $this->load($data);
}
}
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(Define\Model $model): void
{
$query = "DELETE FROM `{$this->getTable()}` WHERE `{$this->idField()}` = ?";
$st = $this->getConnection()->prepare($query);
$st->execute([$this->getId($model)]);
$this->resetIndex();
$this->optimize();
}
public function fetchAll(): array
{
$query = "SELECT * FROM `{$this->getTable()}`";
return $this->fetchMany($query);
}
public function fetchById(int $id): Define\Model
{
$query = "SELECT * FROM `{$this->getTable()}` WHERE `{$this->idField()}` = ?";
return $this->fetchOne($query, [$id]);
}
protected function idProperty(): string
{
return 'getId';
}
protected function idField(): string
{
return 'id';
}
protected function insert(Define\Model $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);
}
protected function getId(Define\Model $model): int
{
return $model->getId();
}
protected function fetchOne(string $query, ?array $values = null): Define\Model
{
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);
}
abstract public function install(): void;
abstract public function load(array $row): Define\Model;
abstract protected function fieldsForUpdate(): array;
abstract protected function valuesForUpdate(Define\Model $model): array;
abstract protected function fieldsForInsert(): array;
abstract protected function valuesForInsert(Define\Model $model): array;
abstract protected function defaultFind(Define\Model $model): Define\Model;
abstract protected function fieldsForCreate(): array;
abstract protected function valuesForCreate(array $data): array;
abstract protected function defaultSearch(array $data): Define\Model;
}