table; } public function setTable(string $table): Repository { $this->table = $table; return $this; } public function getConnection(): Define\Connection { return $this->connection; } public function load(array $data_row): Define\Model { $model = $this->create($data_row); $this->setIndex($model, $data_row[$this->getKey()]); return $model; } public function remove(Define\Model $model): void { $query = $this->connection->getQueryBuilder() ->delete()->from($this->getTable()) ->where("{$this->getKey()} = ?"); $this->connection->execute($query, [$this->getIndex($model)]); } /** * @throws EmptyResult */ public function fetchById(int $id): Define\Model { $query = $this->connection->getQueryBuilder() ->select() ->from($this->getTable()) ->where("{$this->getKey()} = ?"); return $this->fetchOne($query, [$id]); } /** * @throws EmptyResult */ public function fetchAll(null|string|array $ordering = null): array { $query = $this->connection->getQueryBuilder() ->select() ->from($this->getTable()); if ($ordering !== null) { $query->order($ordering); } return $this->fetchMany($query); } protected string $key = 'id'; public function setKey(string $key): Repository { $this->key = $key; return $this; } protected function getKey(): string { return $this->key; } protected function setIndex(Define\Model &$model, mixed $value): Repository { $model->{$this->getKey()} = $value; return $this; } protected function getIndex(Define\Model $model): mixed { return $model->id; } protected function parseData(Define\Model $model, ?array $data, Implement\Repository\MapperParser $data_map): Define\Model { if ($data === null) { return $model; } foreach ($data_map->getColumns() as $column) { if (!$data_map->hasMapper($column)) { $this->parsePlainColumn($model, $column, $data); continue; } $settings = $data_map->getMapper($column); if ($settings->parse($model, $column, $data)) { continue; } $property = $column; if ($settings->hasProperty()) { $property = $settings->property; } $this->setDefault($model, $property); } return $model; } protected function parsePlainColumn(Define\Model &$model, string $column, ?array $data): void { $property = $column; if (isset($data[$column])) { $model->{$property} = $data[$column]; return; } $this->setDefault($model, $property); } /** * @param Define\Model $model * @param string $property * @return void */ protected function setDefault(Define\Model &$model, string $property): void { try { $prop = new ReflectionProperty($model, $property); } catch (ReflectionException) { $model->{$property} = null; return; } $type = $prop->getType()->getName(); $value = match ($type) { 'int' => 0, 'float' => 0.0, 'string' => '', default => null, }; $model->{$property} = $value; } /** * @param array $columns * @param array $values * @return int * @throws PDOException */ protected function saveNew(array $columns, array $values): int { $query = $this->connection->getQueryBuilder() ->insert() ->into($this->getTable()) ->columns($columns) ->values(array_fill(0, count($columns), '?')); $this->connection->execute($query, $values); return $this->connection->getPDO()->lastInsertId(); } /** * @param Define\Model $model * @param array $columns * @param array $data * @return Define\Model * @throws EmptyResult */ protected function update(Define\Model $model, array $columns, array $data): Define\Model { $changes = []; $values = []; foreach ($columns as $column) { if (in_array($column, array_keys($data))) { $changes []= $column; $values []= $data[$column]; } } if (count($changes) === 0) { return $model; } $columns_string = implode(', ', array_map(function($property) {return "`{$property}` = ?";}, $changes)); $query = $this->connection->getQueryBuilder() ->update($this->getTable()) ->set($columns_string) ->where("{$this->getKey()} = ?"); $values []= $this->getIndex($model); try { $this->connection->execute($query, $values); } catch (PDOException $exception) { throw new EmptyResult($query, $exception, $data); } return $this->fetchById($this->getIndex($model)); } /** * @param string $query * @param array|null $data * @return Define\Model * @throws EmptyResult */ protected function fetchOne(string $query, ?array $data = null): Define\Model { try { $result = $this->connection->execute($query, $data)->fetch(PDO::FETCH_ASSOC); if ($result === false) { throw new EmptyResult($query, null, $data); } } catch (PDOException $exception) { throw new EmptyResult($query, $exception, $data); } return $this->load($result); } /** * @param string $query * @param array|null $data * @return array * @throws EmptyResult */ protected function fetchMany(string $query, ?array $data = null): array { try { $results = $this->connection->execute($query, $data)->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $exception) { throw new EmptyResult($query, $exception, $data); } return array_map([$this, 'load'], $results); } /** * @param string $query * @param array|null $data * @return array * @throws EmptyResult */ protected function fetchAsArray(string $query, ?array $data = null): array { try { $results = $this->connection->execute($query, $data)->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $exception) { throw new EmptyResult($query, $exception, $data); } return $results; } public function filterData(array $data): array { return $data; } }