From 8a03d9e6758fba73dfb2b0080ba0ef3bf5226122 Mon Sep 17 00:00:00 2001 From: Aldarien Date: Tue, 11 Oct 2022 11:39:25 -0300 Subject: [PATCH] Reorder and cleanup of Repository --- src/Alias/Model/Repository.php | 271 +++++++++++++++++++------------ src/Concept/Model/Repository.php | 214 +++++++++++------------- 2 files changed, 260 insertions(+), 225 deletions(-) diff --git a/src/Alias/Model/Repository.php b/src/Alias/Model/Repository.php index 1557e65..02e0912 100644 --- a/src/Alias/Model/Repository.php +++ b/src/Alias/Model/Repository.php @@ -5,7 +5,6 @@ use ProVM\Concept\Database\Connection; use ProVM\Concept\Database\QueryBuilder; use ProVM\Concept\Model; use ProVM\Concept\Model\Factory; -use ProVM\Concept\Model\Mapping; use ProVM\Concept\Model\Repository as RepositoryInterface; abstract class Repository implements RepositoryInterface @@ -19,62 +18,84 @@ abstract class Repository implements RepositoryInterface } protected Connection $connection; - public function setConnection(Connection $connection): Repository - { - $this->connection = $connection; - return $this; - } + protected QueryBuilder $builder; + protected Factory $factory; + protected string $model; + protected string $table; + protected array $columns; + protected array $required_columns; + protected array $optional_columns; + protected array $properties; + 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 + public function getTable(): string { - $class = $this->getModel(); - return (new $class()) - ->setRepository($this); + return $this->table; + } + public function getColumns(): array + { + return $this->columns ?? array_merge($this->getRequiredColumns(), $this->getOptionalColumns()); + } + public function getRequiredColumns(): array + { + if (isset($this->optional_columns) and !isset($this->required_columns)) { + return array_diff($this->getColumns(), $this->getOptionalColumns()); + } + return $this->required_columns ?? $this->getColumns(); + } + public function getOptionalColumns(): array + { + if (isset($this->required_columns) and !isset($this->optional_columns)) { + return array_diff($this->getColumns(), $this->getRequiredColumns()); + } + return $this->optional_columns ?? []; + } + public function getProperties(): array + { + return $this->properties ?? $this->getColumns(); + } + + + 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; } - 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) { @@ -82,23 +103,18 @@ abstract class Repository implements RepositoryInterface } return $this; } - public function addColumn(string $column): RepositoryInterface + public function setRequiredColumns(array $columns): RepositoryInterface { - $this->columns []= $column; + foreach ($columns as $item) { + $this->addRequiredColumn($item); + } return $this; } - public function getColumns(): array + public function setOptionalColumns(array $columns): RepositoryInterface { - return $this->columns ?? array_merge($this->getRequired(), $this->getOptional()); - } - protected array $properties; - public function getProperties(): array - { - return $this->properties; - } - public function addProperty(string $property): RepositoryInterface - { - $this->properties []= $property; + foreach ($columns as $item) { + $this->addOptionalColumn($item); + } return $this; } public function setProperties(array $properties): RepositoryInterface @@ -108,47 +124,34 @@ abstract class Repository implements RepositoryInterface } return $this; } - protected array $required; - public function setRequired(array $columns): RepositoryInterface + + public function addColumn(string $column): RepositoryInterface { - foreach ($columns as $item) { - $this->addRequired($item); - } + $this->columns []= $column; return $this; } - public function addRequired(string $column): RepositoryInterface + public function addRequiredColumn(string $column): RepositoryInterface { - $this->required []= $column; + $this->required_columns []= $column; return $this; } - public function getRequired(): array + public function addOptionalColumn(string $column): RepositoryInterface { - 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); - } + $this->optional_columns []= $column; return $this; } - public function addOptional(string $column): RepositoryInterface + public function addProperty(string $property): RepositoryInterface { - $this->optional []= $column; + $this->properties []= $property; 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 getNewModel(): Model + { + $class = $this->getModel(); + return (new $class()) + ->setRepository($this); + } public function getMethod(string $property, bool $get = true): string { $m = str_replace(' ', '', ucwords(str_replace('_', ' ', $property))); @@ -165,45 +168,105 @@ abstract class Repository implements RepositoryInterface } return strtolower(implode('_', $parts)); } - public function fillData(Model $model, array $data): Model + + protected function compareProp(string $property, ?array $data = null): bool { - foreach ($this->getProperties() as $property) { - $m = $this->getMethod($property, false); - if (in_array($property, $this->getRequired())) { - $model->{$m}($data[$property]); - continue; + if ($data === null) { + return in_array($property, $this->getRequiredColumns()); + } + return in_array($property, $this->getOptionalColumns()) and key_exists($property, $data); + } + protected function compareProperty(string $property, ?array $data = null, ?string &$tmp_property = null): bool + { + $tmp_property = $property; + if ($this->compareProp($tmp_property, $data)) { + return true; + } + $tmp_property = "{$property}_id"; + return $this->compareProp($tmp_property, $data); + } + protected function validateDefaultProperty(mixed $value): bool + { + $defaults = [ + 0, + '', + null + ]; + return in_array($value, $defaults); + } + protected function editModel(Model $model, string $getter, string $setter, mixed $value, bool $optional = false): Model + { + try { + $val = $model->{$getter}(); + if ($optional and $this->validateDefaultProperty($val)) { + $model->{$setter}($value); } - if (in_array("{$property}_id", $this->getRequired())) { - $model->{$m}($data["{$property}_id"]); - continue; - } - if (in_array($property, $this->getOptional()) and isset($data[$property])) { - $model->{$m}($data[$property]); - continue; - } - if (in_array("{$property}_id", $this->getOptional()) and isset($data["{$property}_id"])) { - $model->{$m}($data["{$property}_id"]); - continue; - } - error_log("Missing {$property} in data for " . get_called_class() . "::fillData"); + } catch (\Error|\Exception $e) { + $model->{$setter}($value); } return $model; } - public function mapArray(Model $model, array $data): array + public function mapModel(Model $model, array $data): Model { - foreach ($this->getColumns() as $column) { - $m = $this->getMethod($column); - if (!method_exists($model, $m)) { - error_log("Missing getter for {$column} in " . get_called_class() . "::mapArray"); + /** + * Default Model map + * It is assumed that the Model properties are named like the table columns + */ + foreach ($this->getProperties() as $property) { + $getter = $this->getMethod($property); + $setter = $this->getMethod($property, false); + if ($this->compareProperty($property, tmp_property: $tmp)) { + $model = $this->editModel($model, $getter, $setter, $data[$tmp]); continue; } - $data[$column] = $model->{$m}(); + if (!method_exists($model, $setter)) { + continue; + } + if ($this->compareProperty($property, $data, $tmp)) { + $model = $this->editModel($model, $getter, $setter, $data[$tmp], true); + } + try { + $value = $model->{$getter}(); + if ($this->validateDefaultProperty($value)) { + trigger_error("{$property} has default value in " . get_called_class()); + } + } catch (\Error | \Exception $e) { + trigger_error("Missing {$property} in data for " . get_called_class() . "::fillData", E_USER_WARNING); + } + } + return $model; + } + public function mapTable(Model $model, array $data): array + { + /** + * Default table map + * It is assumed that the table columns are named the same as the Model properties + */ + foreach ($this->getRequiredColumns() as $column) { + $m = $this->getMethod($column); + if (!method_exists($model, $m)) { + trigger_error("Missing getter for {$column} in " . get_called_class() . "::mapArray", E_USER_WARNING); + continue; + } + if (!isset($data[$column])) { + $data[$column] = $model->{$m}(); + } + } + foreach ($this->getOptionalColumns() as $column) { + $m = $this->getMethod($column); + if (!method_exists($model, $m)) { + continue; + } + if (!isset($data[$column])) { + $data[$column] = $model->{$m}(); + } } return $data; } + public function load(array $data): Model { - return $this->fillData($this->getNewModel() + return $this->mapModel($this->getNewModel() ->setId($data['id']), $data); } public function save(Model $model): void @@ -215,7 +278,7 @@ abstract class Repository implements RepositoryInterface $this->update($model); return; } - $values = array_replace(array_flip($this->getColumns()), $this->mapArray($model, [])); + $values = array_replace(array_flip($this->getColumns()), $this->mapTable($model, [])); $cols = array_fill(0, count($values), '?'); $query = $this->getQueryBuilder()->insert($this->getTable())->columns($this->getColumns())->values($cols); $this->getConnection()->execute($query, array_values($values)); @@ -225,7 +288,7 @@ abstract class Repository implements RepositoryInterface if (!$model->isDirty() and !$model->isNew()) { return; } - $values = $this->mapArray($model, []); + $values = $this->mapTable($model, []); $cols = array_map(function($column) { return "{$column} = ?"; }, $values); @@ -236,7 +299,7 @@ abstract class Repository implements RepositoryInterface } public function create(array $data): Model { - return $this->fillData($this->getNewModel() + return $this->mapModel($this->getNewModel() ->setNew(), $data); } public function edit(Model $model, array $data): Model diff --git a/src/Concept/Model/Repository.php b/src/Concept/Model/Repository.php index 91af17b..fac68fa 100644 --- a/src/Concept/Model/Repository.php +++ b/src/Concept/Model/Repository.php @@ -7,55 +7,119 @@ use ProVM\Concept\Model; interface Repository { + /** + * @return Connection + */ + public function getConnection(): Connection; + /** + * @return QueryBuilder + */ + public function getQueryBuilder(): QueryBuilder; + /** + * @return Factory + */ + public function getFactory(): Factory; + /** + * @return string + */ + public function getModel(): string; + /** + * @return string + */ + public function getTable(): string; + /** + * Get table columns + * @return array + */ + public function getColumns(): array; + /** + * Get required columns + * @return array + */ + public function getRequiredColumns(): array; + /** + * Get optional columns + * @return array + */ + public function getOptionalColumns(): array; + /** + * Get Model properties + * @return array + */ + public function getProperties(): array; + /** * @param Connection $connection * @return Repository */ public function setConnection(Connection $connection): Repository; - - /** - * @return Connection - */ - public function getConnection(): Connection; - /** * @param QueryBuilder $builder * @return Repository */ public function setQueryBuilder(QueryBuilder $builder): Repository; - - /** - * @return QueryBuilder - */ - public function getQueryBuilder(): QueryBuilder; - /** * @param Factory $factory * @return Repository */ public function setFactory(Factory $factory): Repository; - - /** - * @return Factory - */ - public function getFactory(): Factory; - /** * @param string $model_class * @return Repository */ public function setModel(string $model_class): Repository; + /** + * @param string $table + * @return Repository + */ + public function setTable(string $table): Repository; + /** + * Set columns in table + * @param array $columns + * @return Repository + */ + public function setColumns(array $columns): Repository; + /** + * Set required columns + * Optional + * @param array $columns + * @return Repository + */ + public function setRequiredColumns(array $columns): Repository; + /** + * Set optional columns + * @param array $columns + * @return Repository + */ + public function setOptionalColumns(array $columns): Repository; + /** + * Set Model properties + * @param array $properties + * @return Repository + */ + public function setProperties(array $properties): Repository; /** - * @return string + * @param string $column + * @return Repository */ - public function getModel(): string; - + public function addColumn(string $column): Repository; /** - * Get clean empty Model - * @return Model + * @param string $column + * @return Repository */ - public function getNewModel(): Model; + public function addRequiredColumn(string $column): Repository; + /** + * @param string $column + * @return Repository + */ + public function addOptionalColumn(string $column): Repository; + /** + * @param string $property + * @param $value + * @return Repository + */ + public function addProperty(string $property): Repository; /** * Set up the Repository @@ -70,94 +134,10 @@ interface Repository public function setup(): Repository; /** - * @return string + * Get clean empty Model + * @return Model */ - public function getTable(): string; - - /** - * @param string $table - * @return Repository - */ - public function setTable(string $table): Repository; - - /** - * Set columns in table - * @param array $columns - * @return Repository - */ - public function setColumns(array $columns): Repository; - - /** - * @param string $column - * @return Repository - */ - public function addColumn(string $column): Repository; - - /** - * Get table columns - * @return array - */ - public function getColumns(): array; - - /** - * Get Model properties - * @return array - */ - public function getProperties(): array; - - /** - * @param string $property - * @param $value - * @return Repository - */ - public function addProperty(string $property): Repository; - - /** - * Set Model properties - * @param array $properties - * @return Repository - */ - public function setProperties(array $properties): Repository; - - /** - * Set required columns - * Optional - * @param array $columns - * @return Repository - */ - public function setRequired(array $columns): Repository; - - /** - * @param string $column - * @return Repository - */ - public function addRequired(string $column): Repository; - - /** - * Get required columns - * @return array - */ - public function getRequired(): array; - - /** - * Set optional columns - * @param array $columns - * @return Repository - */ - public function setOptional(array $columns): Repository; - - /** - * @param string $column - * @return Repository - */ - public function addOptional(string $column): Repository; - - /** - * Get optional columns - * @return array - */ - public function getOptional(): array; - + public function getNewModel(): Model; /** * Get Model method * @param string $property @@ -165,7 +145,6 @@ interface Repository * @return string */ public function getMethod(string $property, bool $get = true): string; - /** * @param string $method * @return string @@ -178,15 +157,14 @@ interface Repository * @param array $data * @return Model */ - public function fillData(Model $model, array $data): Model; - + public function mapModel(Model $model, array $data): Model; /** * Fill data array with Model values. Accepts a preset data array * @param Model $model * @param array $data * @return array */ - public function mapArray(Model $model, array $data): array; + public function mapTable(Model $model, array $data): array; /** * Transform result array to Model @@ -194,28 +172,24 @@ interface Repository * @return Model */ public function load(array $data): Model; - /** * Save Model to table * @param Model $model * @return void */ public function save(Model $model): void; - /** * Update table value with Model * @param Model $model * @return void */ public function update(Model $model): void; - /** * Create new Model with data * @param array $data * @return Model */ public function create(array $data): Model; - /** * Edit Model with data * @param Model $model @@ -223,7 +197,6 @@ interface Repository * @return Model */ public function edit(Model $model, array $data): Model; - /** * Delete Model from table * @param Model $model @@ -237,7 +210,6 @@ interface Repository * @return Model */ public function fetchById(int $id): Model; - /** * Fetch all Models * @return array