request = $request;
$this->pdm = new PersistentDataManager();
$this->mapRepository = new MapRepository();
$this->placeRepository = new PlaceRepository();
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
$this->challengeRepository = new ChallengeRepository();
$this->guessRepository = new GuessRepository();
$this->placeInChallengeRepository = new PlaceInChallengeRepository();
$this->userInChallengeRepository = new UserInChallengeRepository();
}
public function authorize(): bool
{
$user = $this->request->user();
return $user !== null && $user->hasPermission(IUser::PERMISSION_ADMIN);
}
public function getMapEditor(): IContent
{
$mapId = (int) $this->request->query('mapId');
if ($mapId) {
$map = $this->mapRepository->getById($mapId);
$places = $this->getPlaces($map);
} else {
$map = new Map();
$map->setName(self::$unnamedMapName);
$places = [];
}
return new HtmlContent('admin/map_editor', [
'mapId' => $mapId,
'mapName' => $map->getName(),
'mapDescription' => str_replace('
', "\n", $map->getDescription()),
'bounds' => $map->getBounds()->toArray(),
'places' => &$places
]);
}
public function getPlace(): IContent
{
$placeId = (int) $this->request->query('placeId');
$place = $this->placeRepository->getById($placeId);
return new JsonContent(['panoId' => $place->getFreshPanoId()]);
}
public function saveMap(): IContent
{
$mapId = (int) $this->request->query('mapId');
\Container::$dbConnection->startTransaction();
if ($mapId) {
$map = $this->mapRepository->getById($mapId);
} else {
$map = new Map();
$map->setName(self::$unnamedMapName);
$this->pdm->saveToDb($map);
}
if (isset($_POST['added'])) {
$addedIds = [];
foreach ($_POST['added'] as $placeRaw) {
$placeRaw = json_decode($placeRaw, true);
$place = new Place();
$place->setMap($map);
$place->setLat((float) $placeRaw['lat']);
$place->setLng((float) $placeRaw['lng']);
$place->setPov(new Pov(
(float) $placeRaw['pov']['heading'],
(float) $placeRaw['pov']['pitch'],
(float) $placeRaw['pov']['zoom']
));
if ($placeRaw['panoId'] === -1) {
$place->setPanoIdCachedTimestampDate(new DateTime('-1 day'));
}
$this->pdm->saveToDb($place);
$addedIds[] = ['tempId' => $placeRaw['id'], 'id' => $place->getId()];
}
} else {
$addedIds = [];
}
if (isset($_POST['edited'])) {
foreach ($_POST['edited'] as $placeRaw) {
$placeRaw = json_decode($placeRaw, true);
$place = $this->placeRepository->getById((int) $placeRaw['id']);
$place->setLat((float) $placeRaw['lat']);
$place->setLng((float) $placeRaw['lng']);
$place->setPov(new Pov(
(float) $placeRaw['pov']['heading'],
(float) $placeRaw['pov']['pitch'],
(float) $placeRaw['pov']['zoom']
));
$place->setPanoIdCachedTimestampDate(new DateTime('-1 day'));
$this->pdm->saveToDb($place);
}
}
if (isset($_POST['deleted'])) {
foreach ($_POST['deleted'] as $placeRaw) {
$placeRaw = json_decode($placeRaw, true);
$place = $this->placeRepository->getById((int) $placeRaw['id']);
$this->deletePlace($place);
}
}
$mapBounds = $this->calculateMapBounds($map);
$map->setBounds($mapBounds);
$map->setArea($mapBounds->calculateApproximateArea());
if (isset($_POST['name'])) {
$map->setName($_POST['name'] ? $_POST['name'] : self::$unnamedMapName);
}
if (isset($_POST['description'])) {
$map->setDescription(str_replace(["\n", "\r\n"], '
', $_POST['description']));
}
$this->pdm->saveToDb($map);
\Container::$dbConnection->commit();
return new JsonContent(['mapId' => $map->getId(), 'added' => $addedIds]);
}
public function deleteMap(): IContent
{
$mapId = (int) $this->request->query('mapId');
$map = $this->mapRepository->getById($mapId);
\Container::$dbConnection->startTransaction();
$this->deletePlaces($map);
$this->pdm->deleteFromDb($map);
\Container::$dbConnection->commit();
return new JsonContent(['success' => true]);
}
private function deletePlace(Place $place): void
{
foreach ($this->userPlayedPlaceRepository->getAllByPlace($place) as $userPlayedPlace) {
$this->pdm->deleteFromDb($userPlayedPlace);
}
foreach ($this->challengeRepository->getAllByPlace($place) as $challenge) {
$this->deleteChallenge($challenge);
}
$this->pdm->deleteFromDb($place);
}
private function deletePlaces(Map $map): void
{
foreach ($this->placeRepository->getAllForMap($map) as $place) {
$this->deletePlace($place);
}
}
private function deleteChallenge(Challenge $challenge): void
{
foreach ($this->userInChallengeRepository->getAllByChallenge($challenge) as $userInChallenge) {
$this->pdm->deleteFromDb($userInChallenge);
}
foreach ($this->guessRepository->getAllInChallenge($challenge, [PlaceInChallenge::class]) as $guess) {
$this->pdm->deleteFromDb($guess);
}
foreach ($this->placeInChallengeRepository->getAllByChallenge($challenge) as $placeInChallenge) {
$this->pdm->deleteFromDb($placeInChallenge);
}
$this->pdm->deleteFromDb($challenge);
}
private function calculateMapBounds(Map $map): Bounds
{
$bounds = new Bounds();
foreach ($this->placeRepository->getAllForMap($map) as $place) {
$bounds->extend($place->getPosition());
}
return $bounds;
}
private function &getPlaces(Map $map): array
{
$places = [];
foreach ($this->placeRepository->getAllForMap($map) as $place) {
$noPano = $place->getPanoIdCachedTimestampDate() !== null && $place->getPanoIdCached() === null;
$placeId = $place->getId();
$places[$placeId] = [
'id' => $placeId,
'lat' => $place->getLat(),
'lng' => $place->getLng(),
'panoId' => null,
'pov' => $place->getPov()->toArray(),
'noPano' => $noPano
];
}
return $places;
}
}