diff --git a/src/Cli/AddUserCommand.php b/src/Cli/AddUserCommand.php
index 45fb57d..90f3ba3 100644
--- a/src/Cli/AddUserCommand.php
+++ b/src/Cli/AddUserCommand.php
@@ -1,7 +1,7 @@
$input->getArgument('email'),
- ]);
-
+ $user = new User();
+ $user->setEmail($input->getArgument('email'));
$user->setPlainPassword($input->getArgument('password'));
if ($input->hasArgument('type')) {
@@ -31,9 +29,8 @@ class AddUserCommand extends Command
}
try {
- $modify = new Modify(\Container::$dbConnection, 'users');
- $modify->fill($user->toArray());
- $modify->save();
+ $pdm = new PersistentDataManager();
+ $pdm->saveToDb($user);
} catch (\Exception $e) {
$output->writeln('Adding user failed!');
$output->writeln('');
diff --git a/src/Controller/GameController.php b/src/Controller/GameController.php
index c9472d9..0027e2c 100644
--- a/src/Controller/GameController.php
+++ b/src/Controller/GameController.php
@@ -1,7 +1,6 @@
mapRepository->getById($mapId);
- $bounds = Bounds::createDirectly($map['bound_south_lat'], $map['bound_west_lng'], $map['bound_north_lat'], $map['bound_east_lng']);
-
$session = $this->request->session();
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
$session->set('state', [
'mapId' => $mapId,
- 'area' => $map['area'],
+ 'area' => $map->getArea(),
'rounds' => []
]);
}
- return ['mapId' => $mapId, 'mapName' => $map['name'], 'bounds' => $bounds->toArray()];
+ return ['mapId' => $mapId, 'mapName' => $map->getName(), 'bounds' => $map->getBounds()->toArray()];
}
}
diff --git a/src/Controller/GameFlowController.php b/src/Controller/GameFlowController.php
index 913cfa6..b15ffa7 100644
--- a/src/Controller/GameFlowController.php
+++ b/src/Controller/GameFlowController.php
@@ -4,6 +4,7 @@ use MapGuesser\Interfaces\Request\IRequest;
use MapGuesser\Util\Geo\Position;
use MapGuesser\Response\JsonContent;
use MapGuesser\Interfaces\Response\IContent;
+use MapGuesser\PersistentData\Model\Place;
use MapGuesser\Repository\PlaceRepository;
class GameFlowController
@@ -33,11 +34,14 @@ class GameFlowController
}
if (count($state['rounds']) === 0) {
- $place = $this->placeRepository->getForMapWithValidPano($mapId);
- $state['rounds'][] = $place;
+ $placesWithoutPano = [];
+ $place = $this->placeRepository->getRandomForMapWithValidPano($mapId, [], $placesWithoutPano);
+
+ $this->addNewRoundToState($state, $place, $placesWithoutPano);
+
$session->set('state', $state);
- $data = ['panoId' => $place['panoId']];
+ $data = ['panoId' => $place->getPanoIdCached()];
} else {
$rounds = count($state['rounds']);
$last = $state['rounds'][$rounds - 1];
@@ -93,18 +97,20 @@ class GameFlowController
$exclude = array_merge($exclude, $round['placesWithoutPano'], [$round['placeId']]);
}
- $place = $this->placeRepository->getForMapWithValidPano($mapId, $exclude);
- $state['rounds'][] = $place;
- $session->set('state', $state);
+ $placesWithoutPano = [];
+ $place = $this->placeRepository->getRandomForMapWithValidPano($mapId, $exclude, $placesWithoutPano);
- $panoId = $place['panoId'];
+ $this->addNewRoundToState($state, $place, $placesWithoutPano);
+
+ $panoId = $place->getPanoIdCached();
} else {
$state['rounds'] = [];
- $session->set('state', $state);
$panoId = null;
}
+ $session->set('state', $state);
+
$data = [
'result' => [
'position' => $position->toArray(),
@@ -116,6 +122,16 @@ class GameFlowController
return new JsonContent($data);
}
+ private function addNewRoundToState(&$state, Place $place, array $placesWithoutPano): void
+ {
+ $state['rounds'][] = [
+ 'placesWithoutPano' => $placesWithoutPano,
+ 'placeId' => $place->getId(),
+ 'position' => $place->getPosition(),
+ 'panoId' => $place->getPanoIdCached()
+ ];
+ }
+
private function calculateDistance(Position $realPosition, Position $guessPosition): float
{
return $realPosition->calculateDistanceTo($guessPosition);
diff --git a/src/Controller/LoginController.php b/src/Controller/LoginController.php
index a8227af..f83633d 100644
--- a/src/Controller/LoginController.php
+++ b/src/Controller/LoginController.php
@@ -1,11 +1,9 @@
request = $request;
+ $this->userRepository = new UserRepository();
}
public function getLoginForm()
{
- $session = $this->request->session();
-
- if ($session->get('user')) {
+ if ($this->request->user() !== null) {
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
}
@@ -33,26 +32,18 @@ class LoginController
public function login(): IContent
{
- $session = $this->request->session();
-
- if ($session->get('user')) {
+ if ($this->request->user() !== null) {
$data = ['success' => true];
return new JsonContent($data);
}
- $select = new Select(\Container::$dbConnection, 'users');
- $select->columns(User::getFields());
- $select->where('email', '=', $this->request->post('email'));
+ $user = $this->userRepository->getByEmail($this->request->post('email'));
- $userData = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
-
- if ($userData === null) {
+ if ($user === null) {
$data = ['error' => 'user_not_found'];
return new JsonContent($data);
}
- $user = new User($userData);
-
if (!$user->getActive()) {
$data = ['error' => 'user_not_active'];
return new JsonContent($data);
@@ -63,7 +54,7 @@ class LoginController
return new JsonContent($data);
}
- $session->set('user', $user);
+ $this->request->setUser($user);
$data = ['success' => true];
return new JsonContent($data);
@@ -71,7 +62,7 @@ class LoginController
public function logout(): IRedirect
{
- $this->request->session()->delete('user');
+ $this->request->setUser(null);
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
}
diff --git a/src/Controller/MapAdminController.php b/src/Controller/MapAdminController.php
index 075017a..d12ccbf 100644
--- a/src/Controller/MapAdminController.php
+++ b/src/Controller/MapAdminController.php
@@ -1,13 +1,15 @@
request = $request;
+ $this->pdm = new PersistentDataManager();
$this->mapRepository = new MapRepository();
$this->placeRepository = new PlaceRepository();
}
@@ -45,18 +50,14 @@ class MapAdminController implements ISecured
if ($mapId) {
$map = $this->mapRepository->getById($mapId);
- $bounds = Bounds::createDirectly($map['bound_south_lat'], $map['bound_west_lng'], $map['bound_north_lat'], $map['bound_east_lng']);
- $places = $this->getPlaces($mapId);
+ $places = $this->getPlaces($map);
} else {
- $map = [
- 'name' => self::$unnamedMapName,
- 'description' => ''
- ];
- $bounds = Bounds::createDirectly(-90.0, -180.0, 90.0, 180.0);
+ $map = new Map();
+ $map->setName(self::$unnamedMapName);
$places = [];
}
- $data = ['mapId' => $mapId, 'mapName' => $map['name'], 'mapDescription' => str_replace('
', "\n", $map['description']), 'bounds' => $bounds->toArray(), 'places' => &$places];
+ $data = ['mapId' => $mapId, 'mapName' => $map->getName(), 'mapDescription' => str_replace('
', "\n", $map->getDescription()), 'bounds' => $map->getBounds()->toArray(), 'places' => &$places];
return new HtmlContent('admin/map_editor', $data);
}
@@ -64,9 +65,9 @@ class MapAdminController implements ISecured
{
$placeId = (int) $this->request->query('placeId');
- $placeData = $this->placeRepository->getById($placeId);
+ $place = $this->placeRepository->getById($placeId);
- $data = ['panoId' => $placeData['panoId']];
+ $data = ['panoId' => $place->getFreshPanoId()];
return new JsonContent($data);
}
@@ -76,8 +77,12 @@ class MapAdminController implements ISecured
\Container::$dbConnection->startTransaction();
- if (!$mapId) {
- $mapId = $this->addNewMap();
+ if ($mapId) {
+ $map = $this->mapRepository->getById($mapId);
+ } else {
+ $map = new Map();
+ $map->setName(self::$unnamedMapName);
+ $this->pdm->saveToDb($map);
}
if (isset($_POST['added'])) {
@@ -85,11 +90,18 @@ class MapAdminController implements ISecured
foreach ($_POST['added'] as $placeRaw) {
$placeRaw = json_decode($placeRaw, true);
- $addedIds[] = ['tempId' => $placeRaw['id'], 'id' => $this->placeRepository->addToMap($mapId, [
- 'lat' => (float) $placeRaw['lat'],
- 'lng' => (float) $placeRaw['lng'],
- 'pano_id_cached_timestamp' => $placeRaw['panoId'] === -1 ? (new DateTime('-1 day'))->format('Y-m-d H:i:s') : null
- ])];
+ $place = new Place();
+ $place->setMap($map);
+ $place->setLat((float) $placeRaw['lat']);
+ $place->setLng((float) $placeRaw['lng']);
+
+ if ($placeRaw['panoId'] === -1) {
+ $place->setPanoIdCachedTimestampDate(new DateTime('-1 day'));
+ }
+
+ $this->pdm->saveToDb($place);
+
+ $addedIds[] = ['tempId' => $placeRaw['id'], 'id' => $place->getId()];
}
} else {
$addedIds = [];
@@ -99,10 +111,12 @@ class MapAdminController implements ISecured
foreach ($_POST['edited'] as $placeRaw) {
$placeRaw = json_decode($placeRaw, true);
- $this->placeRepository->modify((int) $placeRaw['id'], [
- 'lat' => (float) $placeRaw['lat'],
- 'lng' => (float) $placeRaw['lng']
- ]);
+ $place = $this->placeRepository->getById((int) $placeRaw['id']);
+ $place->setLat((float) $placeRaw['lat']);
+ $place->setLng((float) $placeRaw['lng']);
+ $place->setPanoIdCachedTimestampDate(new DateTime('-1 day'));
+
+ $this->pdm->saveToDb($place);
}
}
@@ -110,45 +124,42 @@ class MapAdminController implements ISecured
foreach ($_POST['deleted'] as $placeRaw) {
$placeRaw = json_decode($placeRaw, true);
- $this->placeRepository->delete($placeRaw['id']);
+ $place = $this->placeRepository->getById((int) $placeRaw['id']);
+
+ $this->pdm->deleteFromDb($place);
}
}
- $mapBounds = $this->calculateMapBounds($mapId);
+ $mapBounds = $this->calculateMapBounds($map);
- $map = [
- 'bound_south_lat' => $mapBounds->getSouthLat(),
- 'bound_west_lng' => $mapBounds->getWestLng(),
- 'bound_north_lat' => $mapBounds->getNorthLat(),
- 'bound_east_lng' => $mapBounds->getEastLng(),
- 'area' => $mapBounds->calculateApproximateArea(),
- ];
+ $map->setBounds($mapBounds);
+ $map->setArea($mapBounds->calculateApproximateArea());
if (isset($_POST['name'])) {
- $map['name'] = $_POST['name'] ? $_POST['name'] : self::$unnamedMapName;
+ $map->setName($_POST['name'] ? $_POST['name'] : self::$unnamedMapName);
}
if (isset($_POST['description'])) {
- $map['description'] = str_replace(["\n", "\r\n"], '
', $_POST['description']);
+ $map->setDescription(str_replace(["\n", "\r\n"], '
', $_POST['description']));
}
- $this->saveMapData($mapId, $map);
+ $this->pdm->saveToDb($map);
\Container::$dbConnection->commit();
- $data = ['mapId' => $mapId, 'added' => $addedIds];
+ $data = ['mapId' => $map->getId(), 'added' => $addedIds];
return new JsonContent($data);
}
public function deleteMap() {
$mapId = (int) $this->request->query('mapId');
+ $map = $this->mapRepository->getById($mapId);
+
\Container::$dbConnection->startTransaction();
- $this->deletePlaces($mapId);
+ $this->deletePlaces($map);
- $modify = new Modify(\Container::$dbConnection, 'maps');
- $modify->setId($mapId);
- $modify->delete();
+ $this->pdm->deleteFromDb($map);
\Container::$dbConnection->commit();
@@ -156,26 +167,30 @@ class MapAdminController implements ISecured
return new JsonContent($data);
}
- private function deletePlaces(int $mapId): void
+ private function deletePlaces(Map $map): void
{
+ //TODO: relations?
$select = new Select(\Container::$dbConnection, 'places');
- $select->columns(['id']);
- $select->where('map_id', '=', $mapId);
+ $select->columns(Place::getFields());
+ $select->where('map_id', '=', $map->getId());
$result = $select->execute();
- while ($place = $result->fetch(IResultSet::FETCH_ASSOC)) {
- $modify = new Modify(\Container::$dbConnection, 'places');
- $modify->setId($place['id']);
- $modify->delete();
+ while ($placeData = $result->fetch(IResultSet::FETCH_ASSOC)) {
+ $place = new Place();
+
+ $this->pdm->fillWithData($placeData, $place);
+
+ $this->pdm->deleteFromDb($place);
}
}
- private function calculateMapBounds(int $mapId): Bounds
+ private function calculateMapBounds(Map $map): Bounds
{
+ //TODO: from repository or relations
$select = new Select(\Container::$dbConnection, 'places');
$select->columns(['lat', 'lng']);
- $select->where('map_id', '=', $mapId);
+ $select->where('map_id', '=', $map->getId());
$result = $select->execute();
@@ -187,35 +202,12 @@ class MapAdminController implements ISecured
return $bounds;
}
- private function addNewMap(): int
- {
- $modify = new Modify(\Container::$dbConnection, 'maps');
- $modify->fill([
- 'name' => self::$unnamedMapName,
- 'description' => '',
- 'bound_south_lat' => 0.0,
- 'bound_west_lng' => 0.0,
- 'bound_north_lat' => 0.0,
- 'bound_east_lng' => 0.0
- ]);
- $modify->save();
-
- return $modify->getId();
- }
-
- private function saveMapData(int $mapId, array $map): void
- {
- $modify = new Modify(\Container::$dbConnection, 'maps');
- $modify->setId($mapId);
- $modify->fill($map);
- $modify->save();
- }
-
- private function &getPlaces(int $mapId): array
+ private function &getPlaces(Map $map): array
{
+ //TODO: from repository or relations
$select = new Select(\Container::$dbConnection, 'places');
$select->columns(['id', 'lat', 'lng', 'pano_id_cached', 'pano_id_cached_timestamp']);
- $select->where('map_id', '=', $mapId);
+ $select->where('map_id', '=', $map->getId());
$result = $select->execute();
diff --git a/src/Controller/MapsController.php b/src/Controller/MapsController.php
index 0546ec7..932e69e 100644
--- a/src/Controller/MapsController.php
+++ b/src/Controller/MapsController.php
@@ -19,6 +19,7 @@ class MapsController
public function getMaps(): IContent
{
+ //TODO: from repository
$select = new Select(\Container::$dbConnection, 'maps');
$select->columns([
['maps', 'id'],
diff --git a/src/Controller/SignupController.php b/src/Controller/SignupController.php
index b50bfe2..77b3197 100644
--- a/src/Controller/SignupController.php
+++ b/src/Controller/SignupController.php
@@ -1,13 +1,14 @@
request = $request;
+ $this->pdm = new PersistentDataManager();
+ $this->userRepository = new UserRepository();
+ $this->userConfirmationRepository = new UserConfirmationRepository();
}
public function getSignupForm()
{
- $session = $this->request->session();
-
- if ($session->get('user')) {
+ if ($this->request->user() !== null) {
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
}
@@ -35,9 +43,7 @@ class SignupController
public function signup(): IContent
{
- $session = $this->request->session();
-
- if ($session->get('user')) {
+ if ($this->request->user() !== null) {
//TODO: return with some error
$data = ['success' => true];
return new JsonContent($data);
@@ -48,15 +54,9 @@ class SignupController
return new JsonContent($data);
}
- $select = new Select(\Container::$dbConnection, 'users');
- $select->columns(User::getFields());
- $select->where('email', '=', $this->request->post('email'));
-
- $userData = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
-
- if ($userData !== null) {
- $user = new User($userData);
+ $user = $this->userRepository->getByEmail($this->request->post('email'));
+ if ($user !== null) {
if ($user->getActive()) {
$data = ['error' => 'user_found'];
} else {
@@ -75,25 +75,21 @@ class SignupController
return new JsonContent($data);
}
- $user = new User([
- 'email' => $this->request->post('email'),
- ]);
-
+ $user = new User();
+ $user->setEmail($this->request->post('email'));
$user->setPlainPassword($this->request->post('password'));
\Container::$dbConnection->startTransaction();
- $modify = new Modify(\Container::$dbConnection, 'users');
- $modify->fill($user->toArray());
- $modify->save();
- $userId = $modify->getId();
+ $this->pdm->saveToDb($user);
$token = hash('sha256', serialize($user) . random_bytes(10) . microtime());
- $modify = new Modify(\Container::$dbConnection, 'user_confirmations');
- $modify->set('user_id', $userId);
- $modify->set('token', $token);
- $modify->save();
+ $confirmation = new UserConfirmation();
+ $confirmation->setUser($user);
+ $confirmation->setToken($token);
+
+ $this->pdm->saveToDb($confirmation);
\Container::$dbConnection->commit();
@@ -105,17 +101,11 @@ class SignupController
public function activate()
{
- $session = $this->request->session();
-
- if ($session->get('user')) {
+ if ($this->request->user() !== null) {
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
}
- $select = new Select(\Container::$dbConnection, 'user_confirmations');
- $select->columns(['id', 'user_id']);
- $select->where('token', '=', $this->request->query('token'));
-
- $confirmation = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
+ $confirmation = $this->userConfirmationRepository->getByToken($this->request->query('token'));
if ($confirmation === null) {
$data = [];
@@ -124,42 +114,27 @@ class SignupController
\Container::$dbConnection->startTransaction();
- $modify = new Modify(\Container::$dbConnection, 'user_confirmations');
- $modify->setId($confirmation['id']);
- $modify->delete();
+ $this->pdm->deleteFromDb($confirmation);
- $modify = new Modify(\Container::$dbConnection, 'users');
- $modify->setId($confirmation['user_id']);
- $modify->set('active', true);
- $modify->save();
+ $user = $this->userRepository->getById($confirmation->getUserId());
+ $user->setActive(true);
+
+ $this->pdm->saveToDb($user);
\Container::$dbConnection->commit();
- $select = new Select(\Container::$dbConnection, 'users');
- $select->columns(User::getFields());
- $select->whereId($confirmation['user_id']);
-
- $userData = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
- $user = new User($userData);
-
- $session->set('user', $user);
+ $this->request->setUser($user);
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
}
public function cancel()
{
- $session = $this->request->session();
-
- if ($session->get('user')) {
+ if ($this->request->user() !== null) {
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
}
- $select = new Select(\Container::$dbConnection, 'user_confirmations');
- $select->columns(['id', 'user_id']);
- $select->where('token', '=', $this->request->query('token'));
-
- $confirmation = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
+ $confirmation = $this->userConfirmationRepository->getByToken($this->request->query('token'));
if ($confirmation === null) {
$data = ['success' => false];
@@ -168,13 +143,11 @@ class SignupController
\Container::$dbConnection->startTransaction();
- $modify = new Modify(\Container::$dbConnection, 'user_confirmations');
- $modify->setId($confirmation['id']);
- $modify->delete();
+ $this->pdm->deleteFromDb($confirmation);
- $modify = new Modify(\Container::$dbConnection, 'users');
- $modify->setId($confirmation['user_id']);
- $modify->delete();
+ $user = $this->userRepository->getById($confirmation->getUserId());
+
+ $this->pdm->deleteFromDb($user);
\Container::$dbConnection->commit();
diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php
index f60f809..778217a 100644
--- a/src/Controller/UserController.php
+++ b/src/Controller/UserController.php
@@ -1,9 +1,10 @@
request = $request;
+ $this->pdm = new PersistentDataManager();
}
public function authorize(): bool
@@ -25,6 +29,9 @@ class UserController implements ISecured
public function getProfile(): IContent
{
+ /**
+ * @var User $user
+ */
$user = $this->request->user();
$data = ['user' => $user->toArray()];
@@ -33,6 +40,9 @@ class UserController implements ISecured
public function saveProfile(): IContent
{
+ /**
+ * @var User $user
+ */
$user = $this->request->user();
if (!$user->checkPassword($this->request->post('password'))) {
@@ -54,11 +64,7 @@ class UserController implements ISecured
$user->setPlainPassword($this->request->post('password_new'));
}
- $modify = new Modify(\Container::$dbConnection, 'users');
- $modify->fill($user->toArray());
- $modify->save();
-
- $this->request->session()->set('user', $user);
+ $this->pdm->saveToDb($user);
$data = ['success' => true];
return new JsonContent($data);
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/Interfaces/Authentication/IUser.php b/src/Interfaces/Authentication/IUser.php
index f95824c..b5f0182 100644
--- a/src/Interfaces/Authentication/IUser.php
+++ b/src/Interfaces/Authentication/IUser.php
@@ -8,5 +8,9 @@ interface IUser
public function hasPermission(int $permission): bool;
+ public function getUniqueId();
+
public function getDisplayName(): string;
+
+ public function checkPassword(string $password): bool;
}
diff --git a/src/Interfaces/Request/IRequest.php b/src/Interfaces/Request/IRequest.php
index 351550f..e4499e5 100644
--- a/src/Interfaces/Request/IRequest.php
+++ b/src/Interfaces/Request/IRequest.php
@@ -14,5 +14,7 @@ interface IRequest
public function session(): ISession;
+ public function setUser(?IUser $user): void;
+
public function user(): ?IUser;
}
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/Map.php b/src/PersistentData/Model/Map.php
new file mode 100644
index 0000000..919c156
--- /dev/null
+++ b/src/PersistentData/Model/Map.php
@@ -0,0 +1,103 @@
+bounds = Bounds::createDirectly(-90.0, -180.0, 90.0, 180.0);
+ }
+
+ public function setName(string $name): void
+ {
+ $this->name = $name;
+ }
+
+ public function setDescription(string $description): void
+ {
+ $this->description = $description;
+ }
+
+ public function setBounds(Bounds $bounds): void
+ {
+ $this->bounds = $bounds;
+ }
+
+ public function setBoundSouthLat(float $bound_south_lat): void
+ {
+ $this->bounds->setSouthLat($bound_south_lat);
+ }
+
+ public function setBoundWestLng(float $bound_west_lng): void
+ {
+ $this->bounds->setWestLng($bound_west_lng);
+ }
+
+ public function setBoundNorthLat(float $bound_north_lat): void
+ {
+ $this->bounds->setNorthLat($bound_north_lat);
+ }
+
+ public function setBoundEastLng(float $bound_east_lng): void
+ {
+ $this->bounds->setEastLng($bound_east_lng);
+ }
+
+ public function setArea(float $area): void
+ {
+ $this->area = $area;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ public function getDescription(): string
+ {
+ return $this->description;
+ }
+
+ public function getBounds(): Bounds
+ {
+ return $this->bounds;
+ }
+
+ public function getBoundSouthLat(): float
+ {
+ return $this->bounds->getSouthLat();
+ }
+
+ public function getBoundWestLng(): float
+ {
+ return $this->bounds->getWestLng();
+ }
+
+ public function getBoundNorthLat(): float
+ {
+ return $this->bounds->getNorthLat();
+ }
+
+ public function getBoundEastLng(): float
+ {
+ return $this->bounds->getEastLng();
+ }
+
+ public function getArea(): float
+ {
+ return $this->area;
+ }
+}
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/PersistentData/Model/Place.php b/src/PersistentData/Model/Place.php
new file mode 100644
index 0000000..d8d26b1
--- /dev/null
+++ b/src/PersistentData/Model/Place.php
@@ -0,0 +1,150 @@
+ Map::class];
+
+ private ?Map $map = null;
+
+ private ?int $mapId = null;
+
+ private Position $position;
+
+ private ?string $panoIdCached = null;
+
+ private ?DateTime $panoIdCachedTimestamp = null;
+
+ public function __construct()
+ {
+ $this->position = new Position(0.0, 0.0);
+ }
+
+ public function setMap(Map $map): void
+ {
+ $this->map = $map;
+ }
+
+ public function setMapId(int $mapId): void
+ {
+ $this->mapId = $mapId;
+ }
+
+ public function setPosition(Position $position): void
+ {
+ $this->position = $position;
+ }
+
+ public function setLat(float $lat): void
+ {
+ $this->position->setLat($lat);
+ }
+
+ public function setLng(float $lng): void
+ {
+ $this->position->setLng($lng);
+ }
+
+ public function setPanoIdCached(?string $panoIdCached): void
+ {
+ $this->panoIdCached = $panoIdCached;
+ }
+
+ public function setPanoIdCachedTimestampDate(?DateTime $panoIdCachedTimestamp): void
+ {
+ $this->panoIdCachedTimestamp = $panoIdCachedTimestamp;
+ }
+
+ public function setPanoIdCachedTimestamp(?string $panoIdCachedTimestamp): void
+ {
+ if ($panoIdCachedTimestamp !== null) {
+ $this->panoIdCachedTimestamp = new DateTime($panoIdCachedTimestamp);
+ }
+ }
+
+ public function getMap(): ?Map
+ {
+ return $this->map;
+ }
+
+ public function getMapId(): ?int
+ {
+ return $this->mapId;
+ }
+
+ public function getPosition(): Position
+ {
+ return $this->position;
+ }
+
+ public function getLat(): float
+ {
+ return $this->position->getLat();
+ }
+
+ public function getLng(): float
+ {
+ return $this->position->getLng();
+ }
+
+ public function getFreshPanoId(bool $canBeIndoor = false): ?string
+ {
+ if (
+ $this->panoIdCachedTimestamp !== null &&
+ (clone $this->panoIdCachedTimestamp)->add(new DateInterval('P1D')) > new DateTime()
+ ) {
+ return $this->panoIdCached;
+ }
+
+ $request = new Request('https://maps.googleapis.com/maps/api/streetview/metadata', Request::HTTP_GET);
+ $request->setQuery([
+ 'key' => $_ENV['GOOGLE_MAPS_SERVER_API_KEY'],
+ 'location' => $this->position->getLat() . ',' . $this->position->getLng(),
+ 'source' => $canBeIndoor ? 'default' : 'outdoor'
+ ]);
+
+ $response = $request->send();
+ $panoData = json_decode($response->getBody(), true);
+ $panoId = $panoData['status'] === 'OK' ? $panoData['pano_id'] : null;
+
+ // enable indoor panos if no outdoor found
+ if ($panoId === null && !$canBeIndoor) {
+ return $this->getFreshPanoId(true);
+ }
+
+ $this->panoIdCached = $panoId;
+ $this->panoIdCachedTimestamp = new DateTime('now');
+
+ (new PersistentDataManager())->saveToDb($this);
+
+ return $panoId;
+ }
+
+ public function getPanoIdCached(): ?string
+ {
+ return $this->panoIdCached;
+ }
+
+ public function getPanoIdCachedTimestampDate(): ?DateTime
+ {
+ return $this->panoIdCachedTimestamp;
+ }
+
+ public function getPanoIdCachedTimestamp(): ?string
+ {
+ if ($this->panoIdCachedTimestamp === null) {
+ return null;
+ }
+
+ return $this->panoIdCachedTimestamp->format('Y-m-d H:i:s');
+ }
+}
diff --git a/src/Model/User.php b/src/PersistentData/Model/User.php
similarity index 86%
rename from src/Model/User.php
rename to src/PersistentData/Model/User.php
index 0814a78..fc3b185 100644
--- a/src/Model/User.php
+++ b/src/PersistentData/Model/User.php
@@ -1,16 +1,18 @@
-id;
+ }
+
public function getDisplayName(): string
{
return $this->email;
diff --git a/src/PersistentData/Model/UserConfirmation.php b/src/PersistentData/Model/UserConfirmation.php
new file mode 100644
index 0000000..70a76d6
--- /dev/null
+++ b/src/PersistentData/Model/UserConfirmation.php
@@ -0,0 +1,44 @@
+user = $user;
+ }
+
+ public function setUserId(int $userId): void
+ {
+ $this->userId = $userId;
+ }
+
+ public function setToken(string $token): void
+ {
+ $this->token = $token;
+ }
+
+ public function getUser(): ?User
+ {
+ return $this->user;
+ }
+
+ public function getUserId(): ?int
+ {
+ return $this->userId;
+ }
+
+ public function getToken(): string
+ {
+ return $this->token;
+ }
+}
diff --git a/src/PersistentData/PersistentDataManager.php b/src/PersistentData/PersistentDataManager.php
new file mode 100644
index 0000000..3965066
--- /dev/null
+++ b/src/PersistentData/PersistentDataManager.php
@@ -0,0 +1,206 @@
+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());
+ }
+ }
+ }
+}
diff --git a/src/Repository/MapRepository.php b/src/Repository/MapRepository.php
index ba9e11a..cfb9885 100644
--- a/src/Repository/MapRepository.php
+++ b/src/Repository/MapRepository.php
@@ -1,16 +1,19 @@
columns(['id', 'name', 'description', 'bound_south_lat', 'bound_west_lng', 'bound_north_lat', 'bound_east_lng', 'area']);
- $select->whereId($mapId);
+ private PersistentDataManager $pdm;
- return $select->execute()->fetch(IResultSet::FETCH_ASSOC);
+ public function __construct()
+ {
+ $this->pdm = new PersistentDataManager();
+ }
+
+ public function getById(int $mapId): ?Map
+ {
+ return $this->pdm->selectFromDbById($mapId, Map::class);
}
}
diff --git a/src/Repository/PlaceRepository.php b/src/Repository/PlaceRepository.php
index 2a6b325..16f2afe 100644
--- a/src/Repository/PlaceRepository.php
+++ b/src/Repository/PlaceRepository.php
@@ -1,95 +1,43 @@
selectFromDbById($placeId);
-
- $panoId = $this->requestPanoId($place);
-
- $position = new Position($place['lat'], $place['lng']);
-
- return [
- 'position' => $position,
- 'panoId' => $panoId
- ];
+ $this->pdm = new PersistentDataManager();
}
- public function getForMapWithValidPano(int $mapId, array $exclude = []): array
+ public function getById(int $placeId): ?Place
+ {
+ return $this->pdm->selectFromDbById($placeId, Place::class);
+ }
+
+ public function getRandomForMapWithValidPano(int $mapId, array $exclude = [], array &$placesWithoutPano): Place
{
$placesWithoutPano = [];
do {
- $place = $this->selectFromDbForMap($mapId, $exclude);
+ $place = $this->selectRandomFromDbForMap($mapId, $exclude);
- $panoId = $this->requestPanoId($place);
+ $panoId = $place->getFreshPanoId();
if ($panoId === null) {
- $placesWithoutPano[] = $exclude[] = $place['id'];
+ $placesWithoutPano[] = $exclude[] = $place->getId();
}
} while ($panoId === null);
- $position = new Position($place['lat'], $place['lng']);
-
- return [
- 'placesWithoutPano' => $placesWithoutPano,
- 'placeId' => $place['id'],
- 'position' => $position,
- 'panoId' => $panoId
- ];
- }
-
- public function addToMap(int $mapId, array $place): int
- {
- $modify = new Modify(\Container::$dbConnection, 'places');
- $modify->set('map_id', $mapId);
- $modify->fill($place);
- $modify->save();
-
- return $modify->getId();
- }
-
- public function modify(int $id, array $place): void
- {
- $modify = new Modify(\Container::$dbConnection, 'places');
- $modify->setId($id);
- $modify->set('pano_id_cached', null);
- $modify->set('pano_id_cached_timestamp', null);
- $modify->fill($place);
- $modify->save();
- }
-
- public function delete(int $id): void
- {
- $modify = new Modify(\Container::$dbConnection, 'places');
- $modify->setId($id);
- $modify->delete();
- }
-
- private function selectFromDbById(int $placeId): array
- {
- $select = new Select(\Container::$dbConnection, 'places');
- $select->columns(['id', 'lat', 'lng', 'pano_id_cached', 'pano_id_cached_timestamp']);
- $select->whereId($placeId);
-
- $place = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
-
return $place;
}
- private function selectFromDbForMap(int $mapId, array $exclude): array
+ private function selectRandomFromDbForMap(int $mapId, array $exclude): ?Place
{
$select = new Select(\Container::$dbConnection, 'places');
- $select->columns(['id', 'lat', 'lng', 'pano_id_cached', 'pano_id_cached_timestamp']);
$select->where('id', 'NOT IN', $exclude);
$select->where('map_id', '=', $mapId);
@@ -99,49 +47,6 @@ class PlaceRepository
$select->orderBy('id');
$select->limit(1, $randomOffset);
- $place = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
-
- return $place;
- }
-
- private function requestPanoId(array $place, bool $canBeIndoor = false): ?string
- {
- if (
- $place['pano_id_cached_timestamp'] &&
- (new DateTime($place['pano_id_cached_timestamp']))->add(new DateInterval('P1D')) > new DateTime()
- ) {
- return $place['pano_id_cached'];
- }
-
- $request = new Request('https://maps.googleapis.com/maps/api/streetview/metadata', Request::HTTP_GET);
- $request->setQuery([
- 'key' => $_ENV['GOOGLE_MAPS_SERVER_API_KEY'],
- 'location' => $place['lat'] . ',' . $place['lng'],
- 'source' => $canBeIndoor ? 'default' : 'outdoor'
- ]);
-
- $response = $request->send();
-
- $panoData = json_decode($response->getBody(), true);
-
- $panoId = $panoData['status'] === 'OK' ? $panoData['pano_id'] : null;
-
- // enable indoor panos if no outdoor found
- if ($panoId === null && !$canBeIndoor) {
- return $this->requestPanoId($place, true);
- }
-
- $this->saveCachedPanoId($place['id'], $panoId);
-
- return $panoId;
- }
-
- private function saveCachedPanoId(int $placeId, ?string $panoId): void
- {
- $modify = new Modify(\Container::$dbConnection, 'places');
- $modify->setId($placeId);
- $modify->set('pano_id_cached', $panoId);
- $modify->set('pano_id_cached_timestamp', (new DateTime())->format('Y-m-d H:i:s'));
- $modify->save();
+ return $this->pdm->selectFromDb($select, Place::class);
}
}
diff --git a/src/Repository/UserConfirmationRepository.php b/src/Repository/UserConfirmationRepository.php
new file mode 100644
index 0000000..62df3ae
--- /dev/null
+++ b/src/Repository/UserConfirmationRepository.php
@@ -0,0 +1,28 @@
+pdm = new PersistentDataManager();
+ }
+
+ public function getById(int $userConfirmationId): ?UserConfirmation
+ {
+ return $this->pdm->selectFromDbById($userConfirmationId, UserConfirmation::class);
+ }
+
+ public function getByToken(string $token): ?UserConfirmation
+ {
+ $select = new Select(\Container::$dbConnection);
+ $select->where('token', '=', $token);
+
+ return $this->pdm->selectFromDb($select, UserConfirmation::class);
+ }
+}
diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php
new file mode 100644
index 0000000..b67771d
--- /dev/null
+++ b/src/Repository/UserRepository.php
@@ -0,0 +1,28 @@
+pdm = new PersistentDataManager();
+ }
+
+ public function getById(int $userId): ?User
+ {
+ return $this->pdm->selectFromDbById($userId, User::class);
+ }
+
+ public function getByEmail(string $email): ?User
+ {
+ $select = new Select(\Container::$dbConnection);
+ $select->where('email', '=', $email);
+
+ return $this->pdm->selectFromDb($select, User::class);
+ }
+}
diff --git a/src/Request/Request.php b/src/Request/Request.php
index fb95646..0b41fa7 100644
--- a/src/Request/Request.php
+++ b/src/Request/Request.php
@@ -3,6 +3,9 @@
use MapGuesser\Interfaces\Authentication\IUser;
use MapGuesser\Interfaces\Request\IRequest;
use MapGuesser\Interfaces\Request\ISession;
+use MapGuesser\PersistentData\Model\User;
+use MapGuesser\PersistentData\PersistentDataManager;
+use MapGuesser\Repository\UserRepository;
class Request implements IRequest
{
@@ -16,12 +19,24 @@ class Request implements IRequest
private Session $session;
+ private UserRepository $userRepository;
+
+ private ?User $user = null;
+
public function __construct(string $base, array &$get, array &$post, array &$session)
{
$this->base = $base;
$this->get = &$get;
$this->post = &$post;
$this->session = new Session($session);
+
+ $this->userRepository = new UserRepository();
+
+ $userId = $this->session->get('userId');
+
+ if ($userId !== null) {
+ $this->user = $this->userRepository->getById($userId);
+ }
}
public function setParsedRouteParams(array &$routeParams)
@@ -61,8 +76,18 @@ class Request implements IRequest
return $this->session;
}
+ public function setUser(?IUser $user): void
+ {
+ if ($user === null) {
+ $this->session->delete('userId');
+ return;
+ }
+
+ $this->session->set('userId', $user->getUniqueId());
+ }
+
public function user(): ?IUser
{
- return $this->session->get('user');
+ return $this->user;
}
}
diff --git a/src/Util/Geo/Bounds.php b/src/Util/Geo/Bounds.php
index 72501c1..99f1edb 100644
--- a/src/Util/Geo/Bounds.php
+++ b/src/Util/Geo/Bounds.php
@@ -59,6 +59,26 @@ class Bounds
}
}
+ public function setSouthLat(float $southLat): void
+ {
+ $this->southLat = $southLat;
+ }
+
+ public function setWestLng(float $westLng): void
+ {
+ $this->westLng = $westLng;
+ }
+
+ public function setNorthLat(float $northLat): void
+ {
+ $this->northLat = $northLat;
+ }
+
+ public function setEastLng(float $eastLng): void
+ {
+ $this->eastLng = $eastLng;
+ }
+
public function getSouthLat(): float
{
return $this->southLat;
diff --git a/src/Util/Geo/Position.php b/src/Util/Geo/Position.php
index 33eb0cd..bdd89ca 100644
--- a/src/Util/Geo/Position.php
+++ b/src/Util/Geo/Position.php
@@ -13,6 +13,16 @@ class Position
$this->lng = $lng;
}
+ public function setLat(float $lat): void
+ {
+ $this->lat = $lat;
+ }
+
+ public function setLng(float $lng): void
+ {
+ $this->lng = $lng;
+ }
+
public function getLat(): float
{
return $this->lat;