MAPG-140 adapt PlaceRepository and classes that use it to use persistent model

This commit is contained in:
Bence Pőcze 2020-06-20 00:03:49 +02:00
parent 821a9d80c0
commit bd46809d3a
3 changed files with 85 additions and 149 deletions

View File

@ -4,6 +4,7 @@ use MapGuesser\Interfaces\Request\IRequest;
use MapGuesser\Util\Geo\Position; use MapGuesser\Util\Geo\Position;
use MapGuesser\Response\JsonContent; use MapGuesser\Response\JsonContent;
use MapGuesser\Interfaces\Response\IContent; use MapGuesser\Interfaces\Response\IContent;
use MapGuesser\PersistentData\Model\Place;
use MapGuesser\Repository\PlaceRepository; use MapGuesser\Repository\PlaceRepository;
class GameFlowController class GameFlowController
@ -33,11 +34,14 @@ class GameFlowController
} }
if (count($state['rounds']) === 0) { if (count($state['rounds']) === 0) {
$place = $this->placeRepository->getForMapWithValidPano($mapId); $placesWithoutPano = [];
$state['rounds'][] = $place; $place = $this->placeRepository->getRandomForMapWithValidPano($mapId, [], $placesWithoutPano);
$this->addNewRoundToState($state, $place, $placesWithoutPano);
$session->set('state', $state); $session->set('state', $state);
$data = ['panoId' => $place['panoId']]; $data = ['panoId' => $place->getPanoIdCached()];
} else { } else {
$rounds = count($state['rounds']); $rounds = count($state['rounds']);
$last = $state['rounds'][$rounds - 1]; $last = $state['rounds'][$rounds - 1];
@ -93,18 +97,20 @@ class GameFlowController
$exclude = array_merge($exclude, $round['placesWithoutPano'], [$round['placeId']]); $exclude = array_merge($exclude, $round['placesWithoutPano'], [$round['placeId']]);
} }
$place = $this->placeRepository->getForMapWithValidPano($mapId, $exclude); $placesWithoutPano = [];
$state['rounds'][] = $place; $place = $this->placeRepository->getRandomForMapWithValidPano($mapId, $exclude, $placesWithoutPano);
$session->set('state', $state);
$panoId = $place['panoId']; $this->addNewRoundToState($state, $place, $placesWithoutPano);
$panoId = $place->getPanoIdCached();
} else { } else {
$state['rounds'] = []; $state['rounds'] = [];
$session->set('state', $state);
$panoId = null; $panoId = null;
} }
$session->set('state', $state);
$data = [ $data = [
'result' => [ 'result' => [
'position' => $position->toArray(), 'position' => $position->toArray(),
@ -116,6 +122,16 @@ class GameFlowController
return new JsonContent($data); 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 private function calculateDistance(Position $realPosition, Position $guessPosition): float
{ {
return $realPosition->calculateDistanceTo($guessPosition); return $realPosition->calculateDistanceTo($guessPosition);

View File

@ -1,7 +1,6 @@
<?php namespace MapGuesser\Controller; <?php namespace MapGuesser\Controller;
use DateTime; use DateTime;
use MapGuesser\Database\Query\Modify;
use MapGuesser\Database\Query\Select; use MapGuesser\Database\Query\Select;
use MapGuesser\Interfaces\Authentication\IUser; use MapGuesser\Interfaces\Authentication\IUser;
use MapGuesser\Interfaces\Authorization\ISecured; use MapGuesser\Interfaces\Authorization\ISecured;
@ -9,6 +8,7 @@ use MapGuesser\Interfaces\Database\IResultSet;
use MapGuesser\Interfaces\Request\IRequest; use MapGuesser\Interfaces\Request\IRequest;
use MapGuesser\Interfaces\Response\IContent; use MapGuesser\Interfaces\Response\IContent;
use MapGuesser\PersistentData\Model\Map; use MapGuesser\PersistentData\Model\Map;
use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\PersistentDataManager; use MapGuesser\PersistentData\PersistentDataManager;
use MapGuesser\Repository\MapRepository; use MapGuesser\Repository\MapRepository;
use MapGuesser\Repository\PlaceRepository; use MapGuesser\Repository\PlaceRepository;
@ -50,7 +50,7 @@ class MapAdminController implements ISecured
if ($mapId) { if ($mapId) {
$map = $this->mapRepository->getById($mapId); $map = $this->mapRepository->getById($mapId);
$places = $this->getPlaces($mapId); $places = $this->getPlaces($map);
} else { } else {
$map = new Map(); $map = new Map();
$map->setName(self::$unnamedMapName); $map->setName(self::$unnamedMapName);
@ -65,9 +65,9 @@ class MapAdminController implements ISecured
{ {
$placeId = (int) $this->request->query('placeId'); $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); return new JsonContent($data);
} }
@ -83,7 +83,6 @@ class MapAdminController implements ISecured
$map = new Map(); $map = new Map();
$map->setName(self::$unnamedMapName); $map->setName(self::$unnamedMapName);
$this->pdm->saveToDb($map); $this->pdm->saveToDb($map);
$mapId = $map->getId();
} }
if (isset($_POST['added'])) { if (isset($_POST['added'])) {
@ -91,11 +90,18 @@ class MapAdminController implements ISecured
foreach ($_POST['added'] as $placeRaw) { foreach ($_POST['added'] as $placeRaw) {
$placeRaw = json_decode($placeRaw, true); $placeRaw = json_decode($placeRaw, true);
$addedIds[] = ['tempId' => $placeRaw['id'], 'id' => $this->placeRepository->addToMap($mapId, [ $place = new Place();
'lat' => (float) $placeRaw['lat'], $place->setMap($map);
'lng' => (float) $placeRaw['lng'], $place->setLat((float) $placeRaw['lat']);
'pano_id_cached_timestamp' => $placeRaw['panoId'] === -1 ? (new DateTime('-1 day'))->format('Y-m-d H:i:s') : null $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 { } else {
$addedIds = []; $addedIds = [];
@ -105,10 +111,12 @@ class MapAdminController implements ISecured
foreach ($_POST['edited'] as $placeRaw) { foreach ($_POST['edited'] as $placeRaw) {
$placeRaw = json_decode($placeRaw, true); $placeRaw = json_decode($placeRaw, true);
$this->placeRepository->modify((int) $placeRaw['id'], [ $place = $this->placeRepository->getById((int) $placeRaw['id']);
'lat' => (float) $placeRaw['lat'], $place->setLat((float) $placeRaw['lat']);
'lng' => (float) $placeRaw['lng'] $place->setLng((float) $placeRaw['lng']);
]); $place->setPanoIdCachedTimestampDate(new DateTime('-1 day'));
$this->pdm->saveToDb($place);
} }
} }
@ -116,11 +124,13 @@ class MapAdminController implements ISecured
foreach ($_POST['deleted'] as $placeRaw) { foreach ($_POST['deleted'] as $placeRaw) {
$placeRaw = json_decode($placeRaw, true); $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->setBounds($mapBounds); $map->setBounds($mapBounds);
$map->setArea($mapBounds->calculateApproximateArea()); $map->setArea($mapBounds->calculateApproximateArea());
@ -136,7 +146,7 @@ class MapAdminController implements ISecured
\Container::$dbConnection->commit(); \Container::$dbConnection->commit();
$data = ['mapId' => $mapId, 'added' => $addedIds]; $data = ['mapId' => $map->getId(), 'added' => $addedIds];
return new JsonContent($data); return new JsonContent($data);
} }
@ -147,7 +157,7 @@ class MapAdminController implements ISecured
\Container::$dbConnection->startTransaction(); \Container::$dbConnection->startTransaction();
$this->deletePlaces($mapId); $this->deletePlaces($map);
$this->pdm->deleteFromDb($map); $this->pdm->deleteFromDb($map);
@ -157,26 +167,30 @@ class MapAdminController implements ISecured
return new JsonContent($data); 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 = new Select(\Container::$dbConnection, 'places');
$select->columns(['id']); $select->columns(Place::getFields());
$select->where('map_id', '=', $mapId); $select->where('map_id', '=', $map->getId());
$result = $select->execute(); $result = $select->execute();
while ($place = $result->fetch(IResultSet::FETCH_ASSOC)) { while ($placeData = $result->fetch(IResultSet::FETCH_ASSOC)) {
$modify = new Modify(\Container::$dbConnection, 'places'); $place = new Place();
$modify->setId($place['id']);
$modify->delete(); $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 = new Select(\Container::$dbConnection, 'places');
$select->columns(['lat', 'lng']); $select->columns(['lat', 'lng']);
$select->where('map_id', '=', $mapId); $select->where('map_id', '=', $map->getId());
$result = $select->execute(); $result = $select->execute();
@ -188,11 +202,12 @@ class MapAdminController implements ISecured
return $bounds; return $bounds;
} }
private function &getPlaces(int $mapId): array private function &getPlaces(Map $map): array
{ {
//TODO: from repository or relations
$select = new Select(\Container::$dbConnection, 'places'); $select = new Select(\Container::$dbConnection, 'places');
$select->columns(['id', 'lat', 'lng', 'pano_id_cached', 'pano_id_cached_timestamp']); $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(); $result = $select->execute();

View File

@ -1,95 +1,43 @@
<?php namespace MapGuesser\Repository; <?php namespace MapGuesser\Repository;
use MapGuesser\Util\Geo\Position;
use MapGuesser\Database\Query\Select; use MapGuesser\Database\Query\Select;
use MapGuesser\Database\Query\Modify; use MapGuesser\PersistentData\Model\Place;
use MapGuesser\Http\Request; use MapGuesser\PersistentData\PersistentDataManager;
use MapGuesser\Interfaces\Database\IResultSet;
use DateTime;
use DateInterval;
class PlaceRepository class PlaceRepository
{ {
public function getById(int $placeId) private PersistentDataManager $pdm;
public function __construct()
{ {
$place = $this->selectFromDbById($placeId); $this->pdm = new PersistentDataManager();
$panoId = $this->requestPanoId($place);
$position = new Position($place['lat'], $place['lng']);
return [
'position' => $position,
'panoId' => $panoId
];
} }
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 = []; $placesWithoutPano = [];
do { do {
$place = $this->selectFromDbForMap($mapId, $exclude); $place = $this->selectRandomFromDbForMap($mapId, $exclude);
$panoId = $this->requestPanoId($place); $panoId = $place->getFreshPanoId();
if ($panoId === null) { if ($panoId === null) {
$placesWithoutPano[] = $exclude[] = $place['id']; $placesWithoutPano[] = $exclude[] = $place->getId();
} }
} while ($panoId === null); } 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; 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 = 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('id', 'NOT IN', $exclude);
$select->where('map_id', '=', $mapId); $select->where('map_id', '=', $mapId);
@ -99,49 +47,6 @@ class PlaceRepository
$select->orderBy('id'); $select->orderBy('id');
$select->limit(1, $randomOffset); $select->limit(1, $randomOffset);
$place = $select->execute()->fetch(IResultSet::FETCH_ASSOC); return $this->pdm->selectFromDb($select, Place::class);
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();
} }
} }