207 lines
6.2 KiB
PHP
207 lines
6.2 KiB
PHP
<?php
|
|
namespace ProVM\Alias\Model;
|
|
|
|
use PDOException;
|
|
use ProVM\Concept\Database\Connection;
|
|
use ProVM\Concept\Database\QueryBuilder;
|
|
use ProVM\Concept\Model;
|
|
use ProVM\Concept\Model\Factory;
|
|
use ProVM\Concept\Model\Repository as RepositoryInterface;
|
|
use ProVM\Exception\BlankResult;
|
|
|
|
abstract class Repository implements RepositoryInterface
|
|
{
|
|
public function __construct(Connection $connection, QueryBuilder $builder, Factory $factory)
|
|
{
|
|
$this->setConnection($connection)
|
|
->setQueryBuilder($builder)
|
|
->setFactory($factory)
|
|
->setup();
|
|
}
|
|
|
|
protected Connection $connection;
|
|
protected QueryBuilder $builder;
|
|
protected Factory $factory;
|
|
protected string $model;
|
|
protected string $table;
|
|
|
|
public function getConnection(): Connection
|
|
{
|
|
return $this->connection;
|
|
}
|
|
public function getQueryBuilder(): QueryBuilder
|
|
{
|
|
return $this->builder;
|
|
}
|
|
public function getFactory(): Factory
|
|
{
|
|
return $this->factory;
|
|
}
|
|
public function getModel(): string
|
|
{
|
|
return $this->model;
|
|
}
|
|
public function getTable(): string
|
|
{
|
|
return $this->table;
|
|
}
|
|
|
|
public function setConnection(Connection $connection): Repository
|
|
{
|
|
$this->connection = $connection;
|
|
return $this;
|
|
}
|
|
public function setQueryBuilder(QueryBuilder $builder): RepositoryInterface
|
|
{
|
|
$this->builder = $builder;
|
|
return $this;
|
|
}
|
|
public function setFactory(Factory $factory): RepositoryInterface
|
|
{
|
|
$this->factory = $factory;
|
|
return $this;
|
|
}
|
|
public function setModel(string $model_class): RepositoryInterface
|
|
{
|
|
$this->model = $model_class;
|
|
return $this;
|
|
}
|
|
public function setTable(string $table): RepositoryInterface
|
|
{
|
|
$this->table = $table;
|
|
return $this;
|
|
}
|
|
|
|
public function save(Model &$model): void
|
|
{
|
|
try {
|
|
$old = $this->defaultFind($model);
|
|
$this->update($model, $old);
|
|
} catch (BlankResult $e) {
|
|
$this->insert($model);
|
|
$model->setId($this->getConnection()->getPDO()->lastInsertId());
|
|
}
|
|
}
|
|
public function update(Model $model, Model $old): void
|
|
{
|
|
$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;
|
|
}
|
|
|
|
$values = array_values($values);
|
|
$values []= $old->{$this->idProperty()}();
|
|
$query = $this->getQueryBuilder()->update($this->getTable())->set($columns)->where(["{$this->idField()}} = ?"]);
|
|
$this->getConnection()->execute($query, $values);
|
|
}
|
|
public function create(array $data): Model
|
|
{
|
|
try {
|
|
return $this->defaultSearch($data);
|
|
} catch (PDOException | BlankResult $e) {
|
|
$data[$this->idField()] = 0;
|
|
return $this->load($data);
|
|
}
|
|
}
|
|
public function delete(Model $model): void
|
|
{
|
|
$query = $this->getQueryBuilder()->delete($this->getTable())->where(['id = ?']);
|
|
$this->getConnection()->execute($query, [$model->getId()]);
|
|
$this->resetIndex();
|
|
$this->optimize();
|
|
}
|
|
|
|
protected function idProperty(): string
|
|
{
|
|
return 'getId';
|
|
}
|
|
protected function idField(): string
|
|
{
|
|
return 'id';
|
|
}
|
|
protected function insert(Model $model): void
|
|
{
|
|
$fields = $this->fieldsForInsert();
|
|
$fields_string = array_map(function($field) {
|
|
return "`{$field}`";
|
|
}, $fields);
|
|
$fields_questions = array_fill(0, count($fields), '?');
|
|
$query = $this->getQueryBuilder()->insert($this->getTable())->columns($fields_string)->values($fields_questions);
|
|
$values = $this->valuesForInsert($model);
|
|
$this->getConnection()->execute($query, $values);
|
|
}
|
|
protected function resetIndex(): void
|
|
{
|
|
$query = "ALTER TABLE `{$this->getTable()}` AUTO_INCREMENT = 1";
|
|
$this->getConnection()->query($query);
|
|
}
|
|
protected function optimize(): void
|
|
{
|
|
$query = "OPTIMIZE TABLE `{$this->getTable()}`";
|
|
$this->getConnection()->query($query);
|
|
}
|
|
|
|
protected function fetchOne(string $query, ?array $values = null): Model
|
|
{
|
|
if ($values !== null) {
|
|
$rs = $this->getConnection()->prepare($query);
|
|
$rs->execute($values);
|
|
} else {
|
|
$rs = $this->getConnection()->query($query);
|
|
}
|
|
$row = $rs->getFirstAsArray();
|
|
if (!$row) {
|
|
throw new BlankResult();
|
|
}
|
|
return $this->load($row);
|
|
}
|
|
protected function fetchMany(string $query, ?array $values = null): array
|
|
{
|
|
if ($values !== null) {
|
|
$rs = $this->getConnection()->prepare($query);
|
|
$rs->execute($values);
|
|
} else {
|
|
$rs = $this->getConnection()->query($query);
|
|
}
|
|
$rows = $rs->getAsArray();
|
|
if (!$rows) {
|
|
throw new BlankResult();
|
|
}
|
|
return array_map([$this, 'load'], $rows);
|
|
}
|
|
|
|
public function fetchById(int $id): Model
|
|
{
|
|
$query = $this->getQueryBuilder()
|
|
->select()
|
|
->from($this->getTable())
|
|
->where(['id = ?'])
|
|
->limit(1);
|
|
return $this->fetchOne($query, [$id]);
|
|
}
|
|
public function fetchAll(): array
|
|
{
|
|
$query = $this->getQueryBuilder()
|
|
->select()
|
|
->from($this->getTable());
|
|
return $this->fetchMany($query);
|
|
}
|
|
|
|
abstract protected function fieldsForUpdate(): array;
|
|
abstract protected function fieldsForInsert(): array;
|
|
abstract protected function valuesForUpdate(Model $model): array;
|
|
abstract protected function valuesForInsert(Model $model): array;
|
|
abstract protected function defaultFind(Model $model): Model;
|
|
abstract protected function defaultSearch(array $data): Model;
|
|
}
|