Files
models/src/Alias/Model/Repository.php
2022-09-12 17:23:29 -03:00

247 lines
7.2 KiB
PHP

<?php
namespace ProVM\Alias\Model;
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;
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;
public function setConnection(Connection $connection): Repository
{
$this->connection = $connection;
return $this;
}
public function getConnection(): Connection
{
return $this->connection;
}
protected QueryBuilder $builder;
public function setQueryBuilder(QueryBuilder $builder): RepositoryInterface
{
$this->builder = $builder;
return $this;
}
public function getQueryBuilder(): QueryBuilder
{
return $this->builder;
}
protected Factory $factory;
public function setFactory(Factory $factory): RepositoryInterface
{
$this->factory = $factory;
return $this;
}
public function getFactory(): Factory
{
return $this->factory;
}
protected string $model;
public function setModel(string $model_class): RepositoryInterface
{
$this->model = $model_class;
return $this;
}
public function getModel(): string
{
return $this->model;
}
public function getNewModel(): Model
{
$class = $this->getModel();
return (new $class())
->setRepository($this);
}
protected string $table;
public function setTable(string $table): RepositoryInterface
{
$this->table = $table;
return $this;
}
public function getTable(): string
{
return $this->table;
}
protected array $columns;
public function setColumns(array $columns): RepositoryInterface
{
foreach ($columns as $column) {
$this->addColumn($column);
}
return $this;
}
public function addColumn(string $column): RepositoryInterface
{
$this->columns []= $column;
return $this;
}
public function getColumns(): array
{
return $this->columns;
}
protected array $required;
public function setRequired(array $columns): RepositoryInterface
{
foreach ($columns as $item) {
$this->addRequired($item);
}
return $this;
}
public function addRequired(string $column): RepositoryInterface
{
$this->required []= $column;
return $this;
}
public function getRequired(): array
{
if (isset($this->optional) and !isset($this->required)) {
return array_diff($this->getColumns(), $this->getOptional());
}
return $this->required ?? $this->getColumns();
}
protected array $optional;
public function setOptional(array $columns): RepositoryInterface
{
foreach ($columns as $item) {
$this->addColumn($item);
}
return $this;
}
public function addOptional(string $column): RepositoryInterface
{
$this->optional []= $column;
return $this;
}
public function getOptional(): array
{
if (isset($this->required) and !isset($this->optional)) {
return array_diff($this->getColumns(), $this->getRequired());
}
return $this->optional ?? [];
}
public function getMethod(string $column, bool $get = true): string
{
$m = str_replace(' ', '', ucwords(str_replace('_', ' ', $column)));
if ($get) {
return "get{$m}";
}
return "set{$m}";
}
public function getProperty(string $method): string
{
$parts = preg_split('/(?=[A-Z])/', $method);
if (in_array(strtolower($parts[0]), ['get', 'set'])) {
array_shift($parts);
}
return strtolower(implode('_', $parts));
}
public function fillData(Model $model, array $data): Model
{
foreach ($this->getRequired() as $column) {
$m = 'set' . ucwords($column);
$model->{$m}($data[$column]);
}
foreach ($this->getOptional() as $column) {
if (isset($data[$column])) {
$m = 'set' . ucwords($column);
$model->{$m}($data[$column]);
}
}
return $model;
}
public function mapArray(Model $model, array $data): array
{
foreach ($this->getColumns() as $column) {
$m = $this->getMethod($column);
$val = $model->{$m}();
if (isset($data[$column])) {
continue;
}
$data[$column] = $val;
}
return $data;
}
public function load(array $data): Model
{
return $this->fillData($this->getNewModel()
->setId($data['id']), $data);
}
public function save(Model $model): void
{
if (!$model->isDirty() and !$model->isNew()) {
return;
}
if (!$model->isNew()) {
$this->update($model);
return;
}
$values = $this->mapArray($model, []);
$cols = array_fill(0, count($values), '?');
$query = $this->getQueryBuilder()->insert($this->getTable())->columns($this->getColumns())->values($cols);
$this->getConnection()->execute($query, $values);
}
public function update(Model $model): void
{
if (!$model->isDirty() and !$model->isNew()) {
return;
}
$values = $this->mapArray($model, []);
$cols = array_map(function($column) {
return "{$column} = ?";
}, $values);
$values = array_values($values);
$values []= $model->getId();
$query = $this->getQueryBuilder()->update($this->getTable())->set($cols)->where(['id = ?']);
$this->getConnection()->execute($query, $values);
}
public function create(array $data): Model
{
return $this->fillData($this->getNewModel()
->setNew(), $data);
}
public function edit(Model $model, array $data): Model
{
foreach ($this->getColumns() as $col) {
if (isset($data[$col])) {
$m = 'set' . ucwords($col);
$model->{$m}($data[$col]);
}
}
return $model;
}
public function delete(Model $model): void
{
$query = $this->getQueryBuilder()->delete($this->getTable())->where(['id = ?']);
$this->getConnection()->execute($query, [$model->getId()]);
}
public function fetchById(int $id): Model
{
$query = $this->getQueryBuilder()
->select()
->from($this->getTable())
->where([['id', '?']])
->limit(1);
return $this->load($this->getConnection()->execute($query, [$id])->getAsArray()[0]);
}
public function fetchAll(): array
{
$query = $this->getQueryBuilder()
->select()
->from($this->getTable());
return array_map([$this, 'load'], $this->getConnection()->query($query)->getAsArray());
}
}