187 lines
5.9 KiB
PHP
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]);
|
|
}
|
|
} |