MAPG-140 add PersistentDataManager and refactor of models
This commit is contained in:
1 parent
1a4d928143
commit
d6750777c2
6 files changed
+295
-93
No files matched your search
@@ -0,0 +1,69 @@
|
||||
<?php namespace MapGuesser\PersistentData\Model;
|
||||
|
||||
abstract class Model
|
||||
{
|
||||
protected static string $table;
|
||||
|
||||
protected static array $fields;
|
||||
|
||||
protected static array $relations = [];
|
||||
|
||||
protected $id = null;
|
||||
|
||||
private array $snapshot = [];
|
||||
|
||||
public static function getTable(): string
|
||||
{
|
||||
return static::$table;
|
||||
}
|
||||
|
||||
public static function getFields(): array
|
||||
{
|
||||
return array_merge(['id'], static::$fields);
|
||||
}
|
||||
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return static::$relations;
|
||||
}
|
||||
|
||||
public function setId($id): void
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php namespace MapGuesser\PersistentData\Model;
|
||||
|
||||
use MapGuesser\Interfaces\Authentication\IUser;
|
||||
|
||||
class User extends Model implements IUser
|
||||
{
|
||||
private static array $types = ['user', 'admin'];
|
||||
|
||||
protected static string $table = 'users';
|
||||
|
||||
protected static array $fields = ['email', 'password', 'type', 'active'];
|
||||
|
||||
private string $email;
|
||||
|
||||
private string $password;
|
||||
|
||||
private string $type = 'user';
|
||||
|
||||
private bool $active = false;
|
||||
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
public function setPassword(string $hashedPassword): void
|
||||
{
|
||||
$this->password = $hashedPassword;
|
||||
}
|
||||
|
||||
public function setPlainPassword(string $plainPassword): void
|
||||
{
|
||||
$this->password = password_hash($plainPassword, PASSWORD_BCRYPT);
|
||||
}
|
||||
|
||||
public function setType(string $type): void
|
||||
{
|
||||
if (in_array($type, self::$types)) {
|
||||
$this->type = $type;
|
||||
}
|
||||
}
|
||||
|
||||
public function setActive($active): void
|
||||
{
|
||||
$this->active = (bool) $active;
|
||||
}
|
||||
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function getActive(): bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function hasPermission(int $permission): bool
|
||||
{
|
||||
switch ($permission) {
|
||||
case IUser::PERMISSION_NORMAL:
|
||||
return true;
|
||||
break;
|
||||
case IUser::PERMISSION_ADMIN:
|
||||
return $this->type === 'admin';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDisplayName(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function checkPassword(string $password): bool
|
||||
{
|
||||
return password_verify($password, $this->password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php namespace MapGuesser\PersistentData;
|
||||
|
||||
use MapGuesser\Database\Query\Modify;
|
||||
use MapGuesser\Database\Query\Select;
|
||||
use MapGuesser\Interfaces\Database\IResultSet;
|
||||
use MapGuesser\PersistentData\Model\Model;
|
||||
|
||||
class PersistentDataManager
|
||||
{
|
||||
public function selectFromDb(Select $select, string $type, bool $withRelations = false): ?Model
|
||||
{
|
||||
$table = call_user_func([$type, 'getTable']);
|
||||
$fields = call_user_func([$type, 'getFields']);
|
||||
|
||||
$select->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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user