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; }