From d6750777c2e5b1db1f390e852b8cdbbc3b3cfbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Thu, 18 Jun 2020 00:19:42 +0200 Subject: [PATCH] MAPG-140 add PersistentDataManager and refactor of models --- src/Database/Query/Modify.php | 44 +--- src/Database/Query/Select.php | 14 +- src/Model/BaseModel.php | 49 ----- src/PersistentData/Model/Model.php | 69 +++++++ src/{ => PersistentData}/Model/User.php | 6 +- src/PersistentData/PersistentDataManager.php | 206 +++++++++++++++++++ 6 files changed, 295 insertions(+), 93 deletions(-) delete mode 100644 src/Model/BaseModel.php create mode 100644 src/PersistentData/Model/Model.php rename src/{ => PersistentData}/Model/User.php (92%) create mode 100644 src/PersistentData/PersistentDataManager.php diff --git a/src/Database/Query/Modify.php b/src/Database/Query/Modify.php index 5554409..b0a6f82 100755 --- a/src/Database/Query/Modify.php +++ b/src/Database/Query/Modify.php @@ -1,7 +1,6 @@ generateDiff(); + $attributes = $this->attributes; + unset($attributes[$this->idName]); - if (count($diff) === 0) { - return; - }*/ - - $diff = $this->attributes; - unset($diff[$this->idName]); - - $set = $this->generateColumnsWithBinding(array_keys($diff)); + $set = $this->generateColumnsWithBinding(array_keys($attributes)); $query = 'UPDATE ' . Utils::backtick($this->table) . ' SET ' . $set . ' WHERE ' . Utils::backtick($this->idName) . '=?'; $stmt = $this->connection->prepare($query); - $stmt->execute(array_merge($diff, [$this->idName => $this->attributes[$this->idName]])); - } - - private function readFromDB(array $columns): void - { - $select = (new Select($this->connection, $this->table)) - ->setIdName($this->idName) - ->whereId($this->attributes[$this->idName]) - ->columns($columns); - - $this->original = $select->execute()->fetch(IResultSet::FETCH_ASSOC); - } - - private function generateDiff(): array - { - $this->readFromDB(array_keys($this->attributes)); - - $diff = []; - - foreach ($this->attributes as $name => $value) { - $original = $this->original[$name]; - - if ($original != $value) { - $diff[$name] = $value; - } - } - - return $diff; + $stmt->execute(array_merge($attributes, [$this->idName => $this->attributes[$this->idName]])); } public static function generateColumnsWithBinding(array $columns): string diff --git a/src/Database/Query/Select.php b/src/Database/Query/Select.php index a379728..a2ffda6 100644 --- a/src/Database/Query/Select.php +++ b/src/Database/Query/Select.php @@ -32,10 +32,13 @@ class Select private array $limit; - public function __construct(IConnection $connection, string $table) + public function __construct(IConnection $connection, ?string $table = null) { $this->connection = $connection; - $this->table = $table; + + if ($table !== null) { + $this->table = $table; + } } public function setIdName(string $idName): Select @@ -52,6 +55,13 @@ class Select return $this; } + public function from(string $table): Select + { + $this->table = $table; + + return $this; + } + public function columns(array $columns): Select { $this->columns = array_merge($this->columns, $columns); diff --git a/src/Model/BaseModel.php b/src/Model/BaseModel.php deleted file mode 100644 index 48713f7..0000000 --- a/src/Model/BaseModel.php +++ /dev/null @@ -1,49 +0,0 @@ - $value) { - $method = 'set' . str_replace('_', '', ucwords($key, '_')); - - if (method_exists($this, $method)) { - $this->$method($value); - } - } - } - - public function setId($id): void - { - $this->id = $id; - } - - public function getId() - { - return $this->id; - } - - function toArray(): array - { - $array = []; - - foreach (self::getFields() as $key) { - $method = 'get' . str_replace('_', '', ucwords($key, '_')); - - if (method_exists($this, $method)) { - $array[$key] = $this->$method(); - } - } - - return $array; - } -} diff --git a/src/PersistentData/Model/Model.php b/src/PersistentData/Model/Model.php new file mode 100644 index 0000000..de4c483 --- /dev/null +++ b/src/PersistentData/Model/Model.php @@ -0,0 +1,69 @@ +id = $id; + } + + public function getId() + { + return $this->id; + } + + public function toArray(): array + { + $array = []; + + foreach (self::getFields() as $key) { + $method = 'get' . str_replace('_', '', ucwords($key, '_')); + + if (method_exists($this, $method)) { + $array[$key] = $this->$method(); + } + } + + return $array; + } + + public function saveSnapshot(): void + { + $this->snapshot = $this->toArray(); + } + + public function resetSnapshot(): void + { + $this->snapshot = []; + } + + public function getSnapshot(): array + { + return $this->snapshot; + } +} diff --git a/src/Model/User.php b/src/PersistentData/Model/User.php similarity index 92% rename from src/Model/User.php rename to src/PersistentData/Model/User.php index 0814a78..52165f5 100644 --- a/src/Model/User.php +++ b/src/PersistentData/Model/User.php @@ -1,11 +1,13 @@ -from($table); + + //TODO: only with some relations? + if ($withRelations) { + $relations = call_user_func([$type, 'getRelations']); + + $columns = []; + + foreach ($fields as $field) { + $columns[] = [$table, $field]; + } + + $columns = array_merge($columns, $this->getRelationColumns($relations)); + + $this->leftJoinRelations($select, $table, $relations); + $select->columns($columns); + } else { + $select->columns($fields); + } + + //TODO: return with array? + $data = $select->execute()->fetch(IResultSet::FETCH_ASSOC); + + if ($data === null) { + return null; + } + + $model = new $type(); + $this->fillWithData($data, $model); + + return $model; + } + + public function selectFromDbById($id, string $type, bool $withRelations = false): ?Model + { + $select = new Select(\Container::$dbConnection); + $select->whereId($id); + + return $this->selectFromDb($select, $type, $withRelations); + } + + public function fillWithData(array $data, Model $model): void + { + $relations = $model::getRelations(); + $relationData = []; + + foreach ($data as $key => $value) { + if ($this->extractRelationData($key, $value, $relationData, $relations)) { + continue; + } + + $method = 'set' . str_replace('_', '', ucwords($key, '_')); + + if (method_exists($model, $method)) { + $model->$method($value); + } + } + + $this->setRelations($model, $relationData); + + $model->saveSnapshot(); + } + + public function loadRelationsFromDb(Model $model, bool $recursive): void + { + foreach ($model::getRelations() as $relation => $relationType) { + $camel = str_replace('_', '', ucwords($relation, '_')); + + $methodGet = 'get' . $camel . 'Id'; + $methodSet = 'set' . $camel; + + $relationId = $model->$methodGet(); + + if ($relationId !== null) { + $relationModel = $this->selectFromDbById($relationId, $relationType, $recursive); + + $model->$methodSet($relationModel); + } + } + } + + public function saveToDb(Model $model): void + { + $this->syncRelations($model); + + $modified = $model->toArray(); + $id = $model->getId(); + + $modify = new Modify(\Container::$dbConnection, $model::getTable()); + + if ($id !== null) { + $original = $model->getSnapshot(); + + foreach ($original as $key => $value) { + if ($value === $modified[$key]) { + unset($modified[$key]); + } + } + + if (count($modified) > 0) { + $modify->setId($id); + $modify->fill($modified); + $modify->save(); + } + } else { + $modify->fill($modified); + $modify->save(); + + $model->setId($modify->getId()); + } + + $model->saveSnapshot(); + } + + public function deleteFromDb(Model $model): void + { + $modify = new Modify(\Container::$dbConnection, $model::getTable()); + $modify->setId($model->getId()); + $modify->delete(); + + $model->setId(null); + $model->resetSnapshot(); + } + + private function getRelationColumns(array $relations): array + { + $columns = []; + + foreach ($relations as $relation => $relationType) { + $relationTable = call_user_func([$relationType, 'getTable']); + foreach (call_user_func([$relationType, 'getFields']) as $relationField) { + $columns[] = [$relationTable, $relationField, $relation . '__' . $relationField]; + } + } + + return $columns; + } + + private function leftJoinRelations(Select $select, string $table, array $relations): void + { + foreach ($relations as $relation => $relationType) { + $relationTable = call_user_func([$relationType, 'getTable']); + $select->leftJoin($relationTable, [$relationTable, 'id'], '=', [$table, $relation . '_id']); + } + } + + private function extractRelationData(string $key, $value, array &$relationData, array $relations): bool + { + $found = false; + + foreach ($relations as $relation => $relationType) { + if (substr($key, 0, strlen($relation . '__')) === $relation . '__') { + $found = true; + $relationData[$relation][substr($key, strlen($relation . '__'))] = $value; + break; + } + } + + return $found; + } + + private function setRelations(Model $model, array &$relations): void + { + foreach ($model::getRelations() as $relation => $relationType) { + if (isset($relations[$relation])) { + $object = new $relationType(); + + $this->fillWithData($relations[$relation], $object); + + $method = 'set' . str_replace('_', '', ucwords($relation, '_')); + + $model->$method($object); + } + } + } + + private function syncRelations(Model $model): void + { + foreach ($model::getRelations() as $relation => $relationType) { + $camel = str_replace('_', '', ucwords($relation, '_')); + + $methodGet = 'get' . $camel; + $methodSet = 'set' . $camel . 'Id'; + + $relationModel = $model->$methodGet(); + + if ($relationModel !== null) { + $model->$methodSet($relationModel->getId()); + } + } + } +}