diff --git a/src/Alias/Model/Repository.php b/src/Alias/Model/Repository.php index ae24b4a..d115d5e 100644 --- a/src/Alias/Model/Repository.php +++ b/src/Alias/Model/Repository.php @@ -11,19 +11,10 @@ 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(); - } + public function __construct(protected Connection $connection, protected QueryBuilder $builder, protected Factory $factory) + {} - protected Connection $connection; - protected QueryBuilder $builder; - protected Factory $factory; protected string $model; - protected string $table; public function getConnection(): Connection { @@ -37,40 +28,6 @@ abstract class Repository implements RepositoryInterface { 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 { @@ -84,22 +41,19 @@ abstract class Repository implements RepositoryInterface } public function update(Model $model, Model $old): void { - $model_values = $this->valuesForUpdate($model); - $old_values = $this->valuesForUpdate($old); + $mapper = $this->getMapper(); + $model_values = $mapper->mapModelToTable($model); + $old_values = $mapper->mapModelToTable($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]; - } - } + $differences = array_diff_assoc($old_values, $model_values); + $columns = array_map(function($key) { + return "`{$key}` = ?"; + }, array_keys($differences)); + $values = array_values($differences); 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); @@ -115,8 +69,8 @@ abstract class Repository implements RepositoryInterface } public function delete(Model $model): void { - $query = $this->getQueryBuilder()->delete($this->getTable())->where(['id = ?']); - $this->getConnection()->execute($query, [$model->getId()]); + $query = $this->getQueryBuilder()->delete($this->getTable())->where(["{$this->idField()} = ?"]); + $this->getConnection()->execute($query, [$model->{$this->idProperty()}()]); $this->resetIndex(); $this->optimize(); } @@ -131,13 +85,14 @@ abstract class Repository implements RepositoryInterface } protected function insert(Model $model): void { - $fields = $this->fieldsForInsert(); + $mapper = $this->getMapper(); + $fields = $mapper->getColumns(); $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); + $values = array_values($mapper->mapModelToTable($model)); $this->getConnection()->execute($query, $values); } protected function resetIndex(): void @@ -197,6 +152,8 @@ abstract class Repository implements RepositoryInterface return $this->fetchMany($query); } + abstract protected function getMapper(): Model\Mapper; + abstract protected function fieldsForUpdate(): array; abstract protected function fieldsForInsert(): array; abstract protected function valuesForUpdate(Model $model): array; diff --git a/src/Concept/Model.php b/src/Concept/Model.php index 408c694..930a95f 100644 --- a/src/Concept/Model.php +++ b/src/Concept/Model.php @@ -2,7 +2,6 @@ namespace ProVM\Concept; use JsonSerializable; -use ProVM\Concept\Model\Repository; interface Model extends JsonSerializable { diff --git a/src/Concept/Model/Mapper.php b/src/Concept/Model/Mapper.php new file mode 100644 index 0000000..ee9eff3 --- /dev/null +++ b/src/Concept/Model/Mapper.php @@ -0,0 +1,11 @@ +map); + } + public function registerColumn(string $columnName, ?PropertyMap $propertyMap = null): Mapper + { + if ($propertyMap == null) { + $this->map[$columnName] = (new PropertyMap())->setColumn($columnName); + return $this; + } + $this->map[$columnName] = $propertyMap; + return $this; + } + public function mapModelToTable(Concept\Model $model): array + { + $data = []; + foreach ($this->map as $columnName => $propertyMap) { + $data[$columnName] = $propertyMap->mapToTable($model); + } + return $data; + } + public function mapTableToModel(array $data, Concept\Model $model): Concept\Model + { + foreach ($this->map as $propertyMap) { + $propertyMap->map($model, $data); + } + return $model; + } +} diff --git a/src/Implement/Model/Mapper/PropertyMap.php b/src/Implement/Model/Mapper/PropertyMap.php new file mode 100644 index 0000000..d5622f9 --- /dev/null +++ b/src/Implement/Model/Mapper/PropertyMap.php @@ -0,0 +1,63 @@ +property = $property; + return $this; + } + public function setColumn(string $column): PropertyMap + { + $this->column = $column; + return $this; + } + public function setCallback(Closure $callback): PropertyMap + { + $this->callback = $callback; + return $this; + } + public function setDefaultValue(mixed $defaultValue): PropertyMap + { + $this->defaultValue = $defaultValue; + return $this; + } + + public function map(Model $model, array $data): Model + { + $property = $this->property ?? $this->column; + if (isset($this->callback)) { + try { + $model->{$property} = call_user_func_array($this->callback, $data); + } catch (Exception) { + if (!isset($data[$this->column])) { + $model->{$property} = $this->defaultValue; + } else { + $model->{$property} = $data[$this->column]; + } + } + return $model; + } + if (!isset($data[$this->column])) { + $model->{$property} = $this->defaultValue; + } else { + $model->{$property} = $data[$this->column]; + } + return $model; + } + public function mapToTable(Model $model): mixed + { + $property = $this->property ?? $this->column; + return $model->{$property} ?? $this->defaultValue; + } +}