Merged in feature/MAPG-140-solve-persistent-model-anomalies (pull request #121)
Feature/MAPG-140 solve persistent model anomalies
This commit is contained in:
commit
80b850fdd7
@ -1,7 +1,7 @@
|
||||
<?php namespace MapGuesser\Cli;
|
||||
|
||||
use MapGuesser\Database\Query\Modify;
|
||||
use MapGuesser\Model\User;
|
||||
use MapGuesser\PersistentData\PersistentDataManager;
|
||||
use MapGuesser\PersistentData\Model\User;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@ -20,10 +20,8 @@ class AddUserCommand extends Command
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$user = new User([
|
||||
'email' => $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('<error>Adding user failed!</error>');
|
||||
$output->writeln('');
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?php namespace MapGuesser\Controller;
|
||||
|
||||
use MapGuesser\Interfaces\Request\IRequest;
|
||||
use MapGuesser\Util\Geo\Bounds;
|
||||
use MapGuesser\Response\HtmlContent;
|
||||
use MapGuesser\Response\JsonContent;
|
||||
use MapGuesser\Interfaces\Response\IContent;
|
||||
@ -37,18 +36,16 @@ class GameController
|
||||
{
|
||||
$map = $this->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()];
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -1,11 +1,9 @@
|
||||
<?php namespace MapGuesser\Controller;
|
||||
|
||||
use MapGuesser\Database\Query\Select;
|
||||
use MapGuesser\Interfaces\Database\IResultSet;
|
||||
use MapGuesser\Interfaces\Request\IRequest;
|
||||
use MapGuesser\Interfaces\Response\IContent;
|
||||
use MapGuesser\Interfaces\Response\IRedirect;
|
||||
use MapGuesser\Model\User;
|
||||
use MapGuesser\Repository\UserRepository;
|
||||
use MapGuesser\Response\HtmlContent;
|
||||
use MapGuesser\Response\JsonContent;
|
||||
use MapGuesser\Response\Redirect;
|
||||
@ -14,16 +12,17 @@ class LoginController
|
||||
{
|
||||
private IRequest $request;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(IRequest $request)
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
<?php namespace MapGuesser\Controller;
|
||||
|
||||
use DateTime;
|
||||
use MapGuesser\Database\Query\Modify;
|
||||
use MapGuesser\Database\Query\Select;
|
||||
use MapGuesser\Interfaces\Authentication\IUser;
|
||||
use MapGuesser\Interfaces\Authorization\ISecured;
|
||||
use MapGuesser\Interfaces\Database\IResultSet;
|
||||
use MapGuesser\Interfaces\Request\IRequest;
|
||||
use MapGuesser\Interfaces\Response\IContent;
|
||||
use MapGuesser\PersistentData\Model\Map;
|
||||
use MapGuesser\PersistentData\Model\Place;
|
||||
use MapGuesser\PersistentData\PersistentDataManager;
|
||||
use MapGuesser\Repository\MapRepository;
|
||||
use MapGuesser\Repository\PlaceRepository;
|
||||
use MapGuesser\Response\HtmlContent;
|
||||
@ -21,6 +23,8 @@ class MapAdminController implements ISecured
|
||||
|
||||
private IRequest $request;
|
||||
|
||||
private PersistentDataManager $pdm;
|
||||
|
||||
private MapRepository $mapRepository;
|
||||
|
||||
private PlaceRepository $placeRepository;
|
||||
@ -28,6 +32,7 @@ class MapAdminController implements ISecured
|
||||
public function __construct(IRequest $request)
|
||||
{
|
||||
$this->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('<br>', "\n", $map['description']), 'bounds' => $bounds->toArray(), 'places' => &$places];
|
||||
$data = ['mapId' => $mapId, 'mapName' => $map->getName(), 'mapDescription' => str_replace('<br>', "\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"], '<br>', $_POST['description']);
|
||||
$map->setDescription(str_replace(["\n", "\r\n"], '<br>', $_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();
|
||||
|
||||
|
@ -19,6 +19,7 @@ class MapsController
|
||||
|
||||
public function getMaps(): IContent
|
||||
{
|
||||
//TODO: from repository
|
||||
$select = new Select(\Container::$dbConnection, 'maps');
|
||||
$select->columns([
|
||||
['maps', 'id'],
|
||||
|
@ -1,13 +1,14 @@
|
||||
<?php namespace MapGuesser\Controller;
|
||||
|
||||
use MapGuesser\Database\Query\Modify;
|
||||
use MapGuesser\Database\Query\Select;
|
||||
use MapGuesser\Interfaces\Database\IResultSet;
|
||||
use MapGuesser\Interfaces\Request\IRequest;
|
||||
use MapGuesser\Interfaces\Response\IContent;
|
||||
use MapGuesser\Interfaces\Response\IRedirect;
|
||||
use MapGuesser\Mailing\Mail;
|
||||
use MapGuesser\Model\User;
|
||||
use MapGuesser\PersistentData\PersistentDataManager;
|
||||
use MapGuesser\PersistentData\Model\User;
|
||||
use MapGuesser\PersistentData\Model\UserConfirmation;
|
||||
use MapGuesser\Repository\UserConfirmationRepository;
|
||||
use MapGuesser\Repository\UserRepository;
|
||||
use MapGuesser\Response\HtmlContent;
|
||||
use MapGuesser\Response\JsonContent;
|
||||
use MapGuesser\Response\Redirect;
|
||||
@ -16,16 +17,23 @@ class SignupController
|
||||
{
|
||||
private IRequest $request;
|
||||
|
||||
private PersistentDataManager $pdm;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
private UserConfirmationRepository $userConfirmationRepository;
|
||||
|
||||
public function __construct(IRequest $request)
|
||||
{
|
||||
$this->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();
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
<?php namespace MapGuesser\Controller;
|
||||
|
||||
use MapGuesser\Database\Query\Modify;
|
||||
use MapGuesser\Interfaces\Authorization\ISecured;
|
||||
use MapGuesser\Interfaces\Request\IRequest;
|
||||
use MapGuesser\Interfaces\Response\IContent;
|
||||
use MapGuesser\PersistentData\PersistentDataManager;
|
||||
use MapGuesser\PersistentData\Model\User;
|
||||
use MapGuesser\Response\HtmlContent;
|
||||
use MapGuesser\Response\JsonContent;
|
||||
|
||||
@ -11,9 +12,12 @@ class UserController implements ISecured
|
||||
{
|
||||
private IRequest $request;
|
||||
|
||||
private PersistentDataManager $pdm;
|
||||
|
||||
public function __construct(IRequest $request)
|
||||
{
|
||||
$this->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);
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?php namespace MapGuesser\Database\Query;
|
||||
|
||||
use MapGuesser\Interfaces\Database\IConnection;
|
||||
use MapGuesser\Interfaces\Database\IResultSet;
|
||||
use MapGuesser\Database\Utils;
|
||||
|
||||
class Modify
|
||||
@ -14,8 +13,6 @@ class Modify
|
||||
|
||||
private array $attributes = [];
|
||||
|
||||
private array $original = [];
|
||||
|
||||
private ?string $externalId = null;
|
||||
|
||||
private bool $autoIncrement = true;
|
||||
@ -116,48 +113,15 @@ class Modify
|
||||
|
||||
private function update(): void
|
||||
{
|
||||
/*$diff = $this->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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -14,5 +14,7 @@ interface IRequest
|
||||
|
||||
public function session(): ISession;
|
||||
|
||||
public function setUser(?IUser $user): void;
|
||||
|
||||
public function user(): ?IUser;
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
<?php namespace MapGuesser\Model;
|
||||
|
||||
abstract class BaseModel
|
||||
{
|
||||
protected static array $fields;
|
||||
|
||||
protected $id = null;
|
||||
|
||||
public static function getFields(): array
|
||||
{
|
||||
return array_merge(['id'], static::$fields);
|
||||
}
|
||||
|
||||
public function __construct(array $data)
|
||||
{
|
||||
foreach ($data as $key => $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;
|
||||
}
|
||||
}
|
103
src/PersistentData/Model/Map.php
Normal file
103
src/PersistentData/Model/Map.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php namespace MapGuesser\PersistentData\Model;
|
||||
|
||||
use MapGuesser\Util\Geo\Bounds;
|
||||
|
||||
class Map extends Model
|
||||
{
|
||||
protected static string $table = 'maps';
|
||||
|
||||
protected static array $fields = ['name', 'description', 'bound_south_lat', 'bound_west_lng', 'bound_north_lat', 'bound_east_lng', 'area'];
|
||||
|
||||
private string $name = '';
|
||||
|
||||
private string $description = '';
|
||||
|
||||
private Bounds $bounds;
|
||||
|
||||
private float $area = 0.0;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
69
src/PersistentData/Model/Model.php
Normal file
69
src/PersistentData/Model/Model.php
Normal file
@ -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;
|
||||
}
|
||||
}
|
150
src/PersistentData/Model/Place.php
Normal file
150
src/PersistentData/Model/Place.php
Normal file
@ -0,0 +1,150 @@
|
||||
<?php namespace MapGuesser\PersistentData\Model;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use MapGuesser\Http\Request;
|
||||
use MapGuesser\PersistentData\PersistentDataManager;
|
||||
use MapGuesser\Util\Geo\Position;
|
||||
|
||||
class Place extends Model
|
||||
{
|
||||
protected static string $table = 'places';
|
||||
|
||||
protected static array $fields = ['map_id', 'lat', 'lng', 'pano_id_cached', 'pano_id_cached_timestamp'];
|
||||
|
||||
protected static array $relations = ['map' => 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');
|
||||
}
|
||||
}
|
@ -1,16 +1,18 @@
|
||||
<?php namespace MapGuesser\Model;
|
||||
<?php namespace MapGuesser\PersistentData\Model;
|
||||
|
||||
use MapGuesser\Interfaces\Authentication\IUser;
|
||||
|
||||
class User extends BaseModel implements 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 static array $types = ['user', 'admin'];
|
||||
|
||||
private string $password;
|
||||
private string $email = '';
|
||||
|
||||
private string $password = '';
|
||||
|
||||
private string $type = 'user';
|
||||
|
||||
@ -75,6 +77,11 @@ class User extends BaseModel implements IUser
|
||||
}
|
||||
}
|
||||
|
||||
public function getUniqueId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDisplayName(): string
|
||||
{
|
||||
return $this->email;
|
44
src/PersistentData/Model/UserConfirmation.php
Normal file
44
src/PersistentData/Model/UserConfirmation.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php namespace MapGuesser\PersistentData\Model;
|
||||
|
||||
class UserConfirmation extends Model
|
||||
{
|
||||
protected static string $table = 'user_confirmations';
|
||||
|
||||
protected static array $fields = ['user_id', 'token'];
|
||||
|
||||
private ?User $user = null;
|
||||
|
||||
private ?int $userId = null;
|
||||
|
||||
private string $token = '';
|
||||
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
206
src/PersistentData/PersistentDataManager.php
Normal file
206
src/PersistentData/PersistentDataManager.php
Normal file
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +1,19 @@
|
||||
<?php namespace MapGuesser\Repository;
|
||||
|
||||
use MapGuesser\Database\Query\Select;
|
||||
use MapGuesser\Interfaces\Database\IResultSet;
|
||||
use MapGuesser\PersistentData\Model\Map;
|
||||
use MapGuesser\PersistentData\PersistentDataManager;
|
||||
|
||||
class MapRepository
|
||||
{
|
||||
public function getById(int $mapId)
|
||||
{
|
||||
$select = new Select(\Container::$dbConnection, 'maps');
|
||||
$select->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);
|
||||
}
|
||||
}
|
||||
|
@ -1,95 +1,43 @@
|
||||
<?php namespace MapGuesser\Repository;
|
||||
|
||||
use MapGuesser\Util\Geo\Position;
|
||||
use MapGuesser\Database\Query\Select;
|
||||
use MapGuesser\Database\Query\Modify;
|
||||
use MapGuesser\Http\Request;
|
||||
use MapGuesser\Interfaces\Database\IResultSet;
|
||||
use DateTime;
|
||||
use DateInterval;
|
||||
use MapGuesser\PersistentData\Model\Place;
|
||||
use MapGuesser\PersistentData\PersistentDataManager;
|
||||
|
||||
class PlaceRepository
|
||||
{
|
||||
public function getById(int $placeId)
|
||||
private PersistentDataManager $pdm;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$place = $this->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);
|
||||
}
|
||||
}
|
||||
|
28
src/Repository/UserConfirmationRepository.php
Normal file
28
src/Repository/UserConfirmationRepository.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php namespace MapGuesser\Repository;
|
||||
|
||||
use MapGuesser\Database\Query\Select;
|
||||
use MapGuesser\PersistentData\Model\UserConfirmation;
|
||||
use MapGuesser\PersistentData\PersistentDataManager;
|
||||
|
||||
class UserConfirmationRepository
|
||||
{
|
||||
private PersistentDataManager $pdm;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
28
src/Repository/UserRepository.php
Normal file
28
src/Repository/UserRepository.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php namespace MapGuesser\Repository;
|
||||
|
||||
use MapGuesser\Database\Query\Select;
|
||||
use MapGuesser\PersistentData\Model\User;
|
||||
use MapGuesser\PersistentData\PersistentDataManager;
|
||||
|
||||
class UserRepository
|
||||
{
|
||||
private PersistentDataManager $pdm;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user