Compare commits

...

11 Commits

20 changed files with 409 additions and 328 deletions

View File

@ -2,6 +2,7 @@ CREATE TABLE `challenges` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`token` int(10) unsigned NOT NULL, `token` int(10) unsigned NOT NULL,
`time_limit` int(10) unsigned, `time_limit` int(10) unsigned,
`time_limit_type` enum('game', 'round') NOT NULL DEFAULT 'game',
`no_move` tinyint(1) NOT NULL DEFAULT 0, `no_move` tinyint(1) NOT NULL DEFAULT 0,
`no_pan` tinyint(1) NOT NULL DEFAULT 0, `no_pan` tinyint(1) NOT NULL DEFAULT 0,
`no_zoom` tinyint(1) NOT NULL DEFAULT 0, `no_zoom` tinyint(1) NOT NULL DEFAULT 0,
@ -48,6 +49,6 @@ CREATE TABLE `guesses` (
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `user_id` (`user_id`), KEY `user_id` (`user_id`),
KEY `place_in_challenge_id` (`place_in_challenge_id`), KEY `place_in_challenge_id` (`place_in_challenge_id`),
CONSTRAINT `guesses_user_id` FOREIGN KEY (`user_id`) REFERENCES `places` (`id`), CONSTRAINT `guesses_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`),
CONSTRAINT `guesses_place_in_challenge_id` FOREIGN KEY (`place_in_challenge_id`) REFERENCES `place_in_challenge` (`id`) CONSTRAINT `guesses_place_in_challenge_id` FOREIGN KEY (`place_in_challenge_id`) REFERENCES `place_in_challenge` (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

View File

@ -15,6 +15,17 @@
right: 0; right: 0;
background-color: #000000; background-color: #000000;
opacity: 0.5; opacity: 0.5;
z-index: 4;
}
#panningBlockerCover {
display: none;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
opacity: 0;
z-index: 3; z-index: 3;
} }
@ -22,7 +33,7 @@
position: absolute; position: absolute;
bottom: 30px; bottom: 30px;
right: 20px; right: 20px;
z-index: 2; z-index: 3;
} }
#guess.result { #guess.result {
@ -153,6 +164,10 @@
z-index: 2; z-index: 2;
} }
#goToStart {
display: none;
}
@media screen and (max-width: 599px) { @media screen and (max-width: 599px) {
#mapName { #mapName {
display: none; display: none;

View File

@ -77,6 +77,7 @@ div.mapItem>div.buttonContainer {
#restrictions { #restrictions {
margin-top: 1em; margin-top: 1em;
margin-bottom: 1em;
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
} }
@ -84,7 +85,7 @@ div.mapItem>div.buttonContainer {
font-weight: 500; font-weight: 500;
} }
#restrictions input[type=checkbox] { #restrictions input {
height: auto; height: auto;
margin: 0.5em; margin: 0.5em;
} }
@ -94,6 +95,10 @@ div.mapItem>div.buttonContainer {
margin-left: 2em; margin-left: 2em;
} }
#timeLimitType {
margin-left: 2em;
}
@media screen and (min-width: 1504px) { @media screen and (min-width: 1504px) {
#mapContainer { #mapContainer {
grid-template-columns: auto auto auto auto; grid-template-columns: auto auto auto auto;

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2}); const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 });
(function () { (function () {
var Game = { var Game = {
@ -215,8 +215,8 @@ const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2});
} }
}, },
getGameIdentifier: function() { getGameIdentifier: function () {
switch(Game.type) { switch (Game.type) {
case GameType.SINGLE: case GameType.SINGLE:
return '/game/' + mapId; return '/game/' + mapId;
case GameType.MULTI: case GameType.MULTI:
@ -295,72 +295,120 @@ const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2});
return; return;
} }
Game.history = this.response.history; Game.loadHistory(this.response.history);
if (this.response.history !== undefined) {
for (var i = 0; i < this.response.history.length; ++i) {
var round = this.response.history[i];
if (round.result) {
Game.rounds.push({ position: round.position, guessPosition: round.result.guessPosition, realMarker: null, guessMarkers: [] });
Game.addPositionToResultMap(true);
if (round.result.guessPosition) {
Game.addGuessPositionToResultMap(round.result.guessPosition, null, true);
}
Game.scoreSum += round.result.score;
if (round.allResults !== undefined) {
for (var j = 0; j < round.allResults.length; ++j) {
var result = round.allResults[j];
if (result.guessPosition) {
Game.addGuessPositionToResultMap(result.guessPosition, result, true);
}
}
}
}
}
}
if (this.response.finished) { if (this.response.finished) {
// TODO: refactor - it is necessary for mobile Game.transitToResultMap();
if (window.getComputedStyle(document.getElementById('guess')).visibility === 'hidden') {
document.getElementById('showGuessButton').click();
}
if (Game.adaptGuess) {
document.getElementById('guess').classList.remove('adapt');
}
if (Game.guessMarker) {
Game.guessMarker.setMap(null);
Game.guessMarker = null;
}
document.getElementById('guess').classList.add('result');
Game.map.setOptions({
draggableCursor: 'grab'
});
Game.showSummary(); Game.showSummary();
document.getElementById('continueButton').style.display = 'none'; } else {
return;
}
Game.panoId = this.response.place.panoId; if (this.response.restrictions) {
Game.pov = this.response.place.pov; Game.panorama.setOptions({
clickToGo: !this.response.restrictions.noMove,
linksControl: !this.response.restrictions.noMove,
scrollwheel: !this.response.restrictions.noZoom
});
if (this.response.restrictions.noPan) {
document.getElementById('panningBlockerCover').style.display = 'block';
}
}
Game.panoId = this.response.place.panoId;
Game.pov = this.response.place.pov;
Game.startNewRound();
}
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS); document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE); document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
Game.startNewRound();
}); });
}, },
transitToResultMap: function () {
// TODO: refactor - it is necessary for mobile
if (window.getComputedStyle(document.getElementById('guess')).visibility === 'hidden') {
document.getElementById('showGuessButton').click();
}
if (Game.adaptGuess) {
document.getElementById('guess').classList.remove('adapt');
}
if (Game.guessMarker) {
Game.guessMarker.setMap(null);
Game.guessMarker = null;
}
document.getElementById('guess').classList.add('result');
Game.map.setOptions({
draggableCursor: 'grab'
});
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
document.getElementById('continueButton').style.display = 'none';
document.getElementById('showSummaryButton').style.display = 'block';
} else if (Game.type == GameType.MULTI) {
if (Game.multi.owner) {
if (!Game.readyToContinue) {
document.getElementById('continueButton').disabled = true;
}
} else {
document.getElementById('continueButton').style.display = 'none';
}
}
},
loadHistory: function (history) {
if (!history)
return;
Game.history = history;
for (var i = 0; i < Game.rounds.length; ++i) {
var round = Game.rounds[i];
if (round.realMarker) {
round.realMarker.setMap(null);
}
for (var j = 0; j < round.guessMarkers.length; ++j) {
var guessMarker = round.guessMarkers[j];
guessMarker.marker.setMap(null);
guessMarker.line.setMap(null);
if (guessMarker.info) {
guessMarker.info.close();
}
}
}
Game.rounds = [];
for (var i = 0; i < Game.history.length; ++i) {
var round = Game.history[i];
if (round.result) {
Game.rounds.push({ position: round.position, guessPosition: round.result.guessPosition, realMarker: null, guessMarkers: [] });
Game.addPositionToResultMap(true);
if (round.result.guessPosition) {
Game.addGuessPositionToResultMap(round.result.guessPosition, null, true);
}
Game.scoreSum += round.result.score;
if (round.allResults !== undefined) {
for (var j = 0; j < round.allResults.length; ++j) {
var result = round.allResults[j];
if (result.guessPosition) {
Game.addGuessPositionToResultMap(result.guessPosition, result, true);
}
}
}
}
}
},
reset: function () { reset: function () {
if (Game.guessMarker) { if (Game.guessMarker) {
Game.guessMarker.setMap(null); Game.guessMarker.setMap(null);
@ -404,6 +452,13 @@ const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2});
// needs to be set visible after the show guess map hid it in mobile view // needs to be set visible after the show guess map hid it in mobile view
document.getElementById("navigation").style.visibility = 'visible'; document.getElementById("navigation").style.visibility = 'visible';
Game.panorama.setOptions({
clickToGo: true,
linksControl: true,
scrollwheel: true
});
document.getElementById('panningBlockerCover').style.display = null;
Game.initialize(); Game.initialize();
}, },
@ -476,7 +531,11 @@ const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2});
break; break;
case 'game_not_found': case 'game_not_found':
MapGuesser.showModalWithContent('Error', 'The game room was not found by this ID. Please check the link.'); MapGuesser.showModalWithContent('Error', 'The game was not found by this ID. Please check the link.');
break;
case 'anonymous_user':
MapGuesser.showModalWithContent('Error', 'You have to login to join a challenge!');
break; break;
default: default:
@ -542,25 +601,9 @@ const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2});
}, },
showResultMap: function (result, resultBounds) { showResultMap: function (result, resultBounds) {
// TODO: refactor - it is necessary for mobile
if (window.getComputedStyle(document.getElementById('guess')).visibility === 'hidden') {
document.getElementById('showGuessButton').click();
}
if (Game.adaptGuess) { Game.transitToResultMap();
document.getElementById('guess').classList.remove('adapt');
}
if (Game.guessMarker) {
Game.guessMarker.setMap(null);
Game.guessMarker = null;
}
document.getElementById('guess').classList.add('result');
Game.map.setOptions({
draggableCursor: 'grab'
});
Game.map.fitBounds(resultBounds); Game.map.fitBounds(resultBounds);
var distanceInfo = document.getElementById('distanceInfo'); var distanceInfo = document.getElementById('distanceInfo');
@ -579,19 +622,6 @@ const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2});
var scoreBar = document.getElementById('scoreBar'); var scoreBar = document.getElementById('scoreBar');
scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor; scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
scoreBar.style.width = scoreBarProperties.width; scoreBar.style.width = scoreBarProperties.width;
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
document.getElementById('continueButton').style.display = 'none';
document.getElementById('showSummaryButton').style.display = 'block';
} else if (roomId) {
if (Game.multi.owner) {
if (!Game.readyToContinue) {
document.getElementById('continueButton').disabled = true;
}
} else {
document.getElementById('continueButton').style.display = 'none';
}
}
}, },
guess: function () { guess: function () {
@ -628,48 +658,6 @@ const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2});
Game.pov = this.response.place.pov; Game.pov = this.response.place.pov;
} }
// if(this.response.history) {
// // game finished
// // delete everything but the last round
// for (var i = 0; i < Game.rounds.length -1; ++i) {
// var round = Game.rounds[i];
// if (round.realMarker) {
// round.realMarker.setMap(null);
// }
// for (var j = 0; j < round.guessMarkers.length; ++j) {
// var guessMarker = round.guessMarkers[j];
// guessMarker.marker.setMap(null);
// guessMarker.line.setMap(null);
// if (guessMarker.info) {
// guessMarker.info.close();
// }
// }
// }
// // Game.rounds = [];
// for (var i = 0; i < this.response.history.length; ++i) {
// var round = this.response.history[i];
// Game.rounds[i] = { position: round.position, guessPosition: round.result.guessPosition, realMarker: null, guessMarkers: [] };
// Game.addPositionToResultMap(true);
// if (round.result.guessPosition) {
// Game.addGuessPositionToResultMap(round.result.guessPosition, null, true);
// }
// Game.scoreSum += round.result.score;
// for (var j = 0; j < round.allResults.length; ++j) {
// var result = round.allResults[j];
// if (result.guessPosition) {
// Game.addGuessPositionToResultMap(result.guessPosition, result, true);
// }
// }
// }
// }
}, data); }, data);
}, },
@ -783,43 +771,6 @@ const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2});
}, },
showSummary: function () { showSummary: function () {
for (var i = 0; i < Game.rounds.length; ++i) {
var round = Game.rounds[i];
if (round.realMarker) {
round.realMarker.setMap(null);
}
for (var j = 0; j < round.guessMarkers.length; ++j) {
var guessMarker = round.guessMarkers[j];
guessMarker.marker.setMap(null);
guessMarker.line.setMap(null);
if (guessMarker.info) {
guessMarker.info.close();
}
}
}
Game.rounds = [];
for (var i = 0; i < Game.history.length; ++i) {
var round = Game.history[i];
Game.rounds.push({ position: round.position, guessPosition: round.result.guessPosition, realMarker: null, guessMarkers: [] });
Game.addPositionToResultMap(true);
if (round.result.guessPosition) {
Game.addGuessPositionToResultMap(round.result.guessPosition, null, true);
}
Game.scoreSum += round.result.score;
if(round.allResults !== undefined) {
for (var j = 0; j < round.allResults.length; ++j) {
var result = round.allResults[j];
if (result.guessPosition) {
Game.addGuessPositionToResultMap(result.guessPosition, result, true);
}
}
}
}
var distanceInfo = document.getElementById('distanceInfo'); var distanceInfo = document.getElementById('distanceInfo');
distanceInfo.children[0].style.display = 'none'; distanceInfo.children[0].style.display = 'none';
distanceInfo.children[1].style.display = 'none'; distanceInfo.children[1].style.display = 'none';
@ -829,11 +780,13 @@ const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2});
scoreInfo.children[1].style.display = 'block'; scoreInfo.children[1].style.display = 'block';
document.getElementById('showSummaryButton').style.display = null; document.getElementById('showSummaryButton').style.display = null;
if (!roomId || Game.multi.owner) { if (Game.type == GameType.SINGLE || Game.multi.owner) {
document.getElementById('startNewGameButton').style.display = 'block'; document.getElementById('startNewGameButton').style.display = 'block';
if (!Game.readyToContinue) { if (!Game.readyToContinue) {
document.getElementById('startNewGameButton').disabled = true; document.getElementById('startNewGameButton').disabled = true;
} }
} else if (Game.type == GameType.CHALLENGE) {
document.getElementById('goToStart').style.display = 'block';
} }
var resultBounds = new google.maps.LatLngBounds(); var resultBounds = new google.maps.LatLngBounds();
@ -1023,9 +976,9 @@ const GameType = Object.freeze({'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2});
document.getElementById("compass").style.transform = "translateY(-50%) rotate(" + heading + "deg)"; document.getElementById("compass").style.transform = "translateY(-50%) rotate(" + heading + "deg)";
}); });
if(roomId !== null) { if (roomId !== null) {
Game.type = GameType.MULTI; Game.type = GameType.MULTI;
} else if(challengeToken !== null) { } else if (challengeToken !== null) {
Game.type = GameType.CHALLENGE; Game.type = GameType.CHALLENGE;
} }

View File

@ -112,13 +112,15 @@
document.getElementById('playMode').style.visibility = 'hidden'; document.getElementById('playMode').style.visibility = 'hidden';
} }
document.getElementById('challengeButton').onclick = function () { if (document.getElementById('challengeButton')) {
MapGuesser.showModal('challenge'); document.getElementById('challengeButton').onclick = function () {
document.getElementById('createNewChallengeButton').href = '/challenge/new/' + this.dataset.mapId; MapGuesser.showModal('challenge');
document.getElementById('playMode').style.visibility = 'hidden'; document.getElementById('createNewChallengeButton').href = '/challenge/new/' + this.dataset.mapId;
document.getElementById('playMode').style.visibility = 'hidden';
var timeLimit = document.getElementById('timeLimit').value;
document.getElementById('timeLimitLabel').innerText = 'Time limit of ' + timeLimit + ' seconds per round'; var timeLimit = document.getElementById('timeLimit').value;
document.getElementById('timeLimitLabel').innerText = 'Time limit of ' + timeLimit + ' seconds per round';
};
} }
document.getElementById('closePlayModeButton').onclick = function () { document.getElementById('closePlayModeButton').onclick = function () {

View File

@ -97,7 +97,7 @@ class GameController
} }
public function getChallenge(): IContent public function getChallenge(): IContent
{ {
$challengeToken = $this->request->query('challengeToken'); $challengeToken = $this->request->query('challengeToken');
return new HtmlContent('game', ['challengeToken' => $challengeToken]); return new HtmlContent('game', ['challengeToken' => $challengeToken]);
@ -112,16 +112,19 @@ class GameController
$challenge->setToken($challengeToken); $challenge->setToken($challengeToken);
$challenge->setCreatedDate(new DateTime()); $challenge->setCreatedDate(new DateTime());
if($this->request->post('timerEnabled') !== null && $this->request->post('timeLimit') !== null) { if ($this->request->post('timerEnabled') !== null && $this->request->post('timeLimit') !== null) {
$challenge->setTimeLimit($this->request->post('timeLimit')); $challenge->setTimeLimit($this->request->post('timeLimit'));
} }
if($this->request->post('noMove') !== null) { if ($this->request->post('timeLimitType') !== null) {
$challenge->setTimeLimitType($this->request->post('timeLimitType'));
}
if ($this->request->post('noMove') !== null) {
$challenge->setNoMove(true); $challenge->setNoMove(true);
} }
if($this->request->post('noPan') !== null) { if ($this->request->post('noPan') !== null) {
$challenge->setNoPan(true); $challenge->setNoPan(true);
} }
if($this->request->post('noZoom') !== null) { if ($this->request->post('noZoom') !== null) {
$challenge->setNoZoom(true); $challenge->setNoZoom(true);
} }
@ -239,8 +242,19 @@ class GameController
$challengeToken_str = $this->request->query('challengeToken'); $challengeToken_str = $this->request->query('challengeToken');
$session = $this->request->session(); $session = $this->request->session();
$userId = $session->get('userId'); $userId = $session->get('userId');
if (!isset($userId))
{
return new JsonContent(['error' => 'anonymous_user']);
}
$challenge = $this->challengeRepository->getByTokenStr($challengeToken_str); $challenge = $this->challengeRepository->getByTokenStr($challengeToken_str);
if (!isset($challenge))
{
return new JsonContent(['error' => 'game_not_found']);
}
if(!$this->userInChallengeRepository->isUserParticipatingInChallenge($userId, $challenge)) { if(!$this->userInChallengeRepository->isUserParticipatingInChallenge($userId, $challenge)) {
// new player is joining // new player is joining
$userInChallenge = new UserInChallenge(); $userInChallenge = new UserInChallenge();

View File

@ -6,9 +6,13 @@ 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\Multi\MultiConnector; use MapGuesser\Multi\MultiConnector;
use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\PersistentDataManager; use MapGuesser\PersistentData\PersistentDataManager;
use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Guess; use MapGuesser\PersistentData\Model\Guess;
use MapGuesser\PersistentData\Model\Map;
use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\Model\PlaceInChallenge;
use MapGuesser\PersistentData\Model\User;
use MapGuesser\PersistentData\Model\UserPlayedPlace; use MapGuesser\PersistentData\Model\UserPlayedPlace;
use MapGuesser\Repository\ChallengeRepository; use MapGuesser\Repository\ChallengeRepository;
use MapGuesser\Repository\GuessRepository; use MapGuesser\Repository\GuessRepository;
@ -141,41 +145,61 @@ class GameFlowController
return new JsonContent(['ok' => true]); return new JsonContent(['ok' => true]);
} }
private function prepareChallengeResponse(int $userId, Challenge $challenge, int $currentRound): array private function prepareChallengeResponse(int $userId, Challenge $challenge, int $currentRound, bool $withHistory = false): array
{ {
$allGuessesInChallenge = iterator_to_array($this->guessRepository->getAllInChallenge($challenge)); $currentPlace = $this->placeRepository->getByRoundInChallenge($challenge, $currentRound);
foreach ($allGuessesInChallenge as $guess) { if (!isset($currentPlace) || $withHistory) {
$round = $guess->getPlaceInChallenge()->getRound(); $withRelations = [User::class, PlaceInChallenge::class, Place::class];
foreach ($this->guessRepository->getAllInChallenge($challenge, $withRelations) as $guess) {
if ($guess->getUser()->getId() === $userId) { $round = $guess->getPlaceInChallenge()->getRound();
$response['history'][$round]['position'] =
$guess->getPlaceInChallenge()->getPlace()->getPosition()->toArray(); if ($guess->getUser()->getId() === $userId) {
$response['history'][$round]['result'] = [ $response['history'][$round]['position'] =
$guess->getPlaceInChallenge()->getPlace()->getPosition()->toArray();
$response['history'][$round]['result'] = [
'guessPosition' => $guess->getPosition()->toArray(),
'distance' => $guess->getDistance(),
'score' => $guess->getScore()
];
} else {
$response['history'][$round]['allResults'][] = [
'userName' => $guess->getUser()->getDisplayName(),
'guessPosition' => $guess->getPosition()->toArray(), 'guessPosition' => $guess->getPosition()->toArray(),
'distance' => $guess->getDistance(), 'distance' => $guess->getDistance(),
'score' => $guess->getScore() 'score' => $guess->getScore()
]; ];
} else { }
$response['history'][$round]['allResults'][] = [
'userName' => $guess->getUser()->getDisplayName(),
'guessPosition' => $guess->getPosition()->toArray(),
'distance' => $guess->getDistance(),
'score' => $guess->getScore()
];
} }
} }
if (!isset($currentPlace)) { // game finished
$currentPlace = $this->placeRepository->getByRoundInChallenge($challenge, $currentRound);
if(!isset($currentPlace)) { // game finished
$response['finished'] = true; $response['finished'] = true;
} else { // continue game } else { // continue game
$response['place'] = [ $response['place'] = [
'panoId' => $currentPlace->getPanoIdCached(), 'panoId' => $currentPlace->getPanoIdCached(),
'pov' => [$currentPlace->getPov()->toArray()] 'pov' => $currentPlace->getPov()->toArray()
];
$prevRound = $currentRound - 1;
if ($prevRound >= 0) {
foreach ($this->guessRepository->getAllInChallengeByRound($prevRound, $challenge, [User::class]) as $guess) {
if ($guess->getUser()->getId() != $userId) {
$response['allResults'][] = [
'userName' => $guess->getUser()->getDisplayName(),
'guessPosition' => $guess->getPosition()->toArray(),
'distance' => $guess->getDistance(),
'score' => $guess->getScore()
];
}
}
}
$response['restrictions'] = [
'timeLimit' => $challenge->getTimeLimit(),
'noMove' => $challenge->getNoMove(),
'noPan' => $challenge->getNoPan(),
'noZoom' => $challenge->getNoZoom()
]; ];
} }
@ -187,7 +211,7 @@ class GameFlowController
$session = $this->request->session(); $session = $this->request->session();
$userId = $session->get('userId'); $userId = $session->get('userId');
$challengeToken_str = $this->request->query('challengeToken'); $challengeToken_str = $this->request->query('challengeToken');
$userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str); $userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str, [Challenge::class]);
if (!isset($userInChallenge)) { if (!isset($userInChallenge)) {
return new JsonContent(['error' => 'game_not_found']); return new JsonContent(['error' => 'game_not_found']);
@ -196,16 +220,13 @@ class GameFlowController
$challenge = $userInChallenge->getChallenge(); $challenge = $userInChallenge->getChallenge();
$currentRound = $userInChallenge->getCurrentRound(); $currentRound = $userInChallenge->getCurrentRound();
$response = $this->prepareChallengeResponse($userId, $challenge, $currentRound); $response = $this->prepareChallengeResponse($userId, $challenge, $currentRound, true);
return new JsonContent($response); return new JsonContent($response);
} }
public function guess(): IContent public function guess(): IContent
{ {
// testing
$testPlace = $this->placeRepository->getByIdWithMap(5);
$mapId = (int) $this->request->query('mapId'); $mapId = (int) $this->request->query('mapId');
$session = $this->request->session(); $session = $this->request->session();
@ -306,7 +327,7 @@ class GameFlowController
$session = $this->request->session(); $session = $this->request->session();
$userId = $session->get('userId'); $userId = $session->get('userId');
$challengeToken_str = $this->request->query('challengeToken'); $challengeToken_str = $this->request->query('challengeToken');
$userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str); $userInChallenge = $this->userInChallengeRepository->getByUserIdAndToken($userId, $challengeToken_str, [Challenge::class]);
if (!isset($userInChallenge)) { if (!isset($userInChallenge)) {
return new JsonContent(['error' => 'game_not_found']); return new JsonContent(['error' => 'game_not_found']);
@ -314,7 +335,7 @@ class GameFlowController
$challenge = $userInChallenge->getChallenge(); $challenge = $userInChallenge->getChallenge();
$currentRound = $userInChallenge->getCurrentRound(); $currentRound = $userInChallenge->getCurrentRound();
$currentPlaceInChallenge = $this->placeInChallengeRepository->getByRoundInChallenge($currentRound, $challenge); $currentPlaceInChallenge = $this->placeInChallengeRepository->getByRoundInChallenge($currentRound, $challenge, [Place::class, Map::class]);
$currentPlace = $currentPlaceInChallenge->getPlace(); $currentPlace = $currentPlaceInChallenge->getPlace();
$map = $currentPlace->getMap(); $map = $currentPlace->getMap();

View File

@ -5,11 +5,16 @@ use MapGuesser\Interfaces\Authentication\IUser;
use MapGuesser\Interfaces\Authorization\ISecured; use MapGuesser\Interfaces\Authorization\ISecured;
use MapGuesser\Interfaces\Request\IRequest; use MapGuesser\Interfaces\Request\IRequest;
use MapGuesser\Interfaces\Response\IContent; use MapGuesser\Interfaces\Response\IContent;
use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Map; use MapGuesser\PersistentData\Model\Map;
use MapGuesser\PersistentData\Model\Place; use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\PersistentDataManager; use MapGuesser\PersistentData\PersistentDataManager;
use MapGuesser\Repository\ChallengeRepository;
use MapGuesser\Repository\GuessRepository;
use MapGuesser\Repository\MapRepository; use MapGuesser\Repository\MapRepository;
use MapGuesser\Repository\PlaceInChallengeRepository;
use MapGuesser\Repository\PlaceRepository; use MapGuesser\Repository\PlaceRepository;
use MapGuesser\Repository\UserInChallengeRepository;
use MapGuesser\Repository\UserPlayedPlaceRepository; use MapGuesser\Repository\UserPlayedPlaceRepository;
use MapGuesser\Response\HtmlContent; use MapGuesser\Response\HtmlContent;
use MapGuesser\Response\JsonContent; use MapGuesser\Response\JsonContent;
@ -30,6 +35,14 @@ class MapAdminController implements ISecured
private UserPlayedPlaceRepository $userPlayedPlaceRepository; private UserPlayedPlaceRepository $userPlayedPlaceRepository;
private ChallengeRepository $challengeRepository;
private GuessRepository $guessRepository;
private PlaceInChallengeRepository $placeInChallengeRepository;
private UserInChallengeRepository $userInChallengeRepository;
public function __construct(IRequest $request) public function __construct(IRequest $request)
{ {
$this->request = $request; $this->request = $request;
@ -37,6 +50,10 @@ class MapAdminController implements ISecured
$this->mapRepository = new MapRepository(); $this->mapRepository = new MapRepository();
$this->placeRepository = new PlaceRepository(); $this->placeRepository = new PlaceRepository();
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository(); $this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
$this->challengeRepository = new ChallengeRepository();
$this->guessRepository = new GuessRepository();
$this->placeInChallengeRepository = new PlaceInChallengeRepository();
$this->userInChallengeRepository = new UserInChallengeRepository();
} }
public function authorize(): bool public function authorize(): bool
@ -188,6 +205,10 @@ class MapAdminController implements ISecured
$this->pdm->deleteFromDb($userPlayedPlace); $this->pdm->deleteFromDb($userPlayedPlace);
} }
foreach ($this->challengeRepository->getAllByPlace($place) as $challenge) {
$this->deleteChallenge($challenge);
}
$this->pdm->deleteFromDb($place); $this->pdm->deleteFromDb($place);
} }
@ -198,6 +219,23 @@ class MapAdminController implements ISecured
} }
} }
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 private function calculateMapBounds(Map $map): Bounds
{ {
$bounds = new Bounds(); $bounds = new Bounds();

View File

@ -48,6 +48,7 @@ class MapsController
$user = $this->request->user(); $user = $this->request->user();
return new HtmlContent('maps', [ return new HtmlContent('maps', [
'maps' => $maps, 'maps' => $maps,
'isLoggedIn' => $user !== null,
'isAdmin' => $user !== null && $user->hasPermission(IUser::PERMISSION_ADMIN) 'isAdmin' => $user !== null && $user->hasPermission(IUser::PERMISSION_ADMIN)
]); ]);
} }

View File

@ -9,7 +9,10 @@ use MapGuesser\Interfaces\Response\IRedirect;
use MapGuesser\OAuth\GoogleOAuth; use MapGuesser\OAuth\GoogleOAuth;
use MapGuesser\PersistentData\PersistentDataManager; use MapGuesser\PersistentData\PersistentDataManager;
use MapGuesser\PersistentData\Model\User; use MapGuesser\PersistentData\Model\User;
use MapGuesser\PersistentData\Model\UserInChallenge;
use MapGuesser\Repository\GuessRepository;
use MapGuesser\Repository\UserConfirmationRepository; use MapGuesser\Repository\UserConfirmationRepository;
use MapGuesser\Repository\UserInChallengeRepository;
use MapGuesser\Repository\UserPasswordResetterRepository; use MapGuesser\Repository\UserPasswordResetterRepository;
use MapGuesser\Repository\UserPlayedPlaceRepository; use MapGuesser\Repository\UserPlayedPlaceRepository;
use MapGuesser\Response\HtmlContent; use MapGuesser\Response\HtmlContent;
@ -29,6 +32,10 @@ class UserController implements ISecured
private UserPlayedPlaceRepository $userPlayedPlaceRepository; private UserPlayedPlaceRepository $userPlayedPlaceRepository;
private UserInChallengeRepository $userInChallengeRepository;
private GuessRepository $guessRepository;
public function __construct(IRequest $request) public function __construct(IRequest $request)
{ {
$this->request = $request; $this->request = $request;
@ -36,6 +43,8 @@ class UserController implements ISecured
$this->userConfirmationRepository = new UserConfirmationRepository(); $this->userConfirmationRepository = new UserConfirmationRepository();
$this->userPasswordResetterRepository = new UserPasswordResetterRepository(); $this->userPasswordResetterRepository = new UserPasswordResetterRepository();
$this->userPlayedPlaceRepository = new UserPlayedPlaceRepository(); $this->userPlayedPlaceRepository = new UserPlayedPlaceRepository();
$this->userInChallengeRepository = new UserInChallengeRepository();
$this->guessRepository = new GuessRepository();
} }
public function authorize(): bool public function authorize(): bool
@ -209,6 +218,14 @@ class UserController implements ISecured
$this->pdm->deleteFromDb($userPlayedPlace); $this->pdm->deleteFromDb($userPlayedPlace);
} }
foreach ($this->userInChallengeRepository->getAllByUser($user) as $userInChallenge) {
$this->pdm->deleteFromDb($userInChallenge);
}
foreach ($this->guessRepository->getAllByUser($user) as $guess) {
$this->pdm->deleteFromDb($guess);
}
$this->pdm->deleteFromDb($user); $this->pdm->deleteFromDb($user);
\Container::$dbConnection->commit(); \Container::$dbConnection->commit();

View File

@ -6,7 +6,7 @@ class Challenge extends Model
{ {
protected static string $table = 'challenges'; protected static string $table = 'challenges';
protected static array $fields = ['token', 'time_limit', 'no_move', 'no_pan', 'no_zoom', 'created']; protected static array $fields = ['token', 'time_limit', 'time_limit_type', 'no_move', 'no_pan', 'no_zoom', 'created'];
protected static array $relations = []; protected static array $relations = [];
@ -14,6 +14,10 @@ class Challenge extends Model
private ?int $timeLimit = null; private ?int $timeLimit = null;
private static array $timeLimitTypes = ['game', 'round'];
private string $timeLimitType = 'game';
private bool $noMove = false; private bool $noMove = false;
private bool $noPan = false; private bool $noPan = false;
@ -34,19 +38,26 @@ class Challenge extends Model
} }
} }
public function setTimeLimitType(string $timeLimitType): void
{
if (in_array($timeLimitType, self::$timeLimitTypes)) {
$this->timeLimitType = $timeLimitType;
}
}
public function setNoMove(bool $noMove): void public function setNoMove(bool $noMove): void
{ {
$this->$noMove = $noMove; $this->noMove = $noMove;
} }
public function setNoPan(bool $noPan): void public function setNoPan(bool $noPan): void
{ {
$this->$noPan = $noPan; $this->noPan = $noPan;
} }
public function setNoZoom(bool $noZoom): void public function setNoZoom(bool $noZoom): void
{ {
$this->$noZoom = $noZoom; $this->noZoom = $noZoom;
} }
public function setCreatedDate(DateTime $created): void public function setCreatedDate(DateTime $created): void
@ -69,6 +80,11 @@ class Challenge extends Model
return $this->timeLimit; return $this->timeLimit;
} }
public function getTimeLimitType(): string
{
return $this->timeLimitType;
}
public function getNoMove(): bool public function getNoMove(): bool
{ {
return $this->noMove; return $this->noMove;

View File

@ -8,9 +8,9 @@ use MapGuesser\PersistentData\Model\Model;
class PersistentDataManager class PersistentDataManager
{ {
public function selectFromDb(Select $select, string $type, bool $withRelations = false) public function selectFromDb(Select $select, string $type, bool $useRelations = false, array $withRelations = [])
{ {
$select = $this->createSelect($select, $type, $withRelations); $select = $this->createSelect($select, $type, $useRelations, $withRelations);
$data = $select->execute()->fetch(IResultSet::FETCH_ASSOC); $data = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
@ -19,36 +19,38 @@ class PersistentDataManager
} }
$model = new $type(); $model = new $type();
$this->fillWithData($data, $model); $this->fillWithData($data, $model, $withRelations);
return $model; return $model;
} }
public function selectMultipleFromDb(Select $select, string $type, bool $withRelations = false): Generator public function selectMultipleFromDb(Select $select, string $type, bool $useRelations = false, array $withRelations = []): Generator
{ {
$select = $this->createSelect($select, $type, $withRelations); $select = $this->createSelect($select, $type, $useRelations, $withRelations);
$result = $select->execute(); $result = $select->execute();
while ($data = $result->fetch(IResultSet::FETCH_ASSOC)) { while ($data = $result->fetch(IResultSet::FETCH_ASSOC)) {
$model = new $type(); $model = new $type();
$this->fillWithData($data, $model); $this->fillWithData($data, $model, $withRelations);
yield $model; yield $model;
} }
} }
public function selectFromDbById($id, string $type, bool $withRelations = false) public function selectFromDbById($id, string $type, bool $useRelations = false)
{ {
$select = new Select(\Container::$dbConnection); $select = new Select(\Container::$dbConnection);
$select->whereId($id); $select->whereId($id);
return $this->selectFromDb($select, $type, $withRelations); return $this->selectFromDb($select, $type, $useRelations);
} }
public function fillWithData(array &$data, Model $model, ?string $modelKey = null): void public function fillWithData(array &$data, Model $model, array $withRelations = [], ?string $modelKey = null): void
{ {
$relations = $model::getRelations(); $relations = $model::getRelations();
$relationData = []; if (count($withRelations)) {
$relations = array_intersect($relations, $withRelations);
}
while (key($data)) { while (key($data)) {
$key = key($data); $key = key($data);
@ -58,7 +60,7 @@ class PersistentDataManager
if (strpos($key, '__') == false) { if (strpos($key, '__') == false) {
$method = 'set' . str_replace('_', '', ucwords($key, '_')); $method = 'set' . str_replace('_', '', ucwords($key, '_'));
if (method_exists($model, $method)) { if (method_exists($model, $method) && isset($value)) {
$model->$method($value); $model->$method($value);
} }
@ -68,16 +70,15 @@ class PersistentDataManager
$method = 'set' . str_replace('_', '', ucwords($key, '_')); $method = 'set' . str_replace('_', '', ucwords($key, '_'));
if (method_exists($model, $method)) { if (method_exists($model, $method) && isset($value)) {
$model->$method($value); $model->$method($value);
} }
next($data); next($data);
} else if (substr($key, 0, strlen($relation . '__')) === $relation . '__') { } else if (substr($key, 0, strlen($relation . '__')) === $relation . '__') {
// $relation = current($relations);
$relationType = current($relations); $relationType = current($relations);
$relationModel = new $relationType(); $relationModel = new $relationType();
$this->fillWithData($data, $relationModel, $relation); $this->fillWithData($data, $relationModel, $withRelations, $relation);
$method = 'set' . str_replace('_', '', ucwords($relation, '_')); $method = 'set' . str_replace('_', '', ucwords($relation, '_'));
$model->$method($relationModel); $model->$method($relationModel);
@ -88,20 +89,6 @@ class PersistentDataManager
} }
} }
// 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(); $model->saveSnapshot();
} }
@ -166,15 +153,11 @@ class PersistentDataManager
$model->resetSnapshot(); $model->resetSnapshot();
} }
private function createSelect(Select $select, string $type, bool $withRelations = false): Select private function createSelect(Select $select, string $type, bool $useRelations = false, array $withRelations = []): Select
{ {
$table = call_user_func([$type, 'getTable']); $table = call_user_func([$type, 'getTable']);
$fields = call_user_func([$type, 'getFields']); $fields = call_user_func([$type, 'getFields']);
// array_walk($fields, function (&$value, $key, $table) {
// $value = [$table, $value];
// }, $table);
$columns = []; $columns = [];
foreach ($fields as $field) { foreach ($fields as $field) {
@ -183,29 +166,24 @@ class PersistentDataManager
$select->from($table); $select->from($table);
//TODO: only with some relations? if ($useRelations) {
if ($withRelations) {
$relations = call_user_func([$type, 'getRelations']); $relations = call_user_func([$type, 'getRelations']);
if (count($withRelations)) {
$relations = array_intersect($relations, $withRelations);
}
// $columns = []; $columns = array_merge($columns, $this->getRelationColumns($relations, $withRelations));
// foreach ($fields as $field) { $this->leftJoinRelations($select, $table, $relations, $withRelations);
// $columns[] = [$table, $field];
// }
$columns = array_merge($columns, $this->getRelationColumns($relations));
$this->leftJoinRelations($select, $table, $relations);
$select->columns($columns); $select->columns($columns);
} else { } else {
// $select->columns($fields);
$select->columns($columns); $select->columns($columns);
} }
return $select; return $select;
} }
private function getRelationColumns(array $relations): array private function getRelationColumns(array $relations, array $withRelations): array
{ {
$columns = []; $columns = [];
@ -216,50 +194,26 @@ class PersistentDataManager
} }
$nextOrderRelations = call_user_func([$relationType, 'getRelations']); $nextOrderRelations = call_user_func([$relationType, 'getRelations']);
$columns = array_merge($columns, $this->getRelationColumns($nextOrderRelations)); if (count($withRelations)) {
$nextOrderRelations = array_intersect($nextOrderRelations, $withRelations);
}
$columns = array_merge($columns, $this->getRelationColumns($nextOrderRelations, $withRelations));
} }
return $columns; return $columns;
} }
private function leftJoinRelations(Select $select, string $table, array $relations): void private function leftJoinRelations(Select $select, string $table, array $relations, array $withRelations): void
{ {
foreach ($relations as $relation => $relationType) { foreach ($relations as $relation => $relationType) {
$relationTable = call_user_func([$relationType, 'getTable']); $relationTable = call_user_func([$relationType, 'getTable']);
$select->leftJoin($relationTable, [$relationTable, 'id'], '=', [$table, $relation . '_id']); $select->leftJoin($relationTable, [$relationTable, 'id'], '=', [$table, $relation . '_id']);
$nextOrderRelations = call_user_func([$relationType, 'getRelations']); $nextOrderRelations = call_user_func([$relationType, 'getRelations']);
$this->leftJoinRelations($select, $relationTable, $nextOrderRelations); if (count($withRelations)) {
} $nextOrderRelations = array_intersect($nextOrderRelations, $withRelations);
}
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);
} }
$this->leftJoinRelations($select, $relationTable, $nextOrderRelations, $withRelations);
} }
} }

View File

@ -3,6 +3,7 @@
use Generator; use Generator;
use MapGuesser\Database\Query\Select; use MapGuesser\Database\Query\Select;
use MapGuesser\PersistentData\Model\Challenge; use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\Model\User; use MapGuesser\PersistentData\Model\User;
use MapGuesser\PersistentData\PersistentDataManager; use MapGuesser\PersistentData\PersistentDataManager;
@ -55,4 +56,13 @@ class ChallengeRepository
yield from $this->pdm->selectMultipleFromDb($select, Challenge::class); yield from $this->pdm->selectMultipleFromDb($select, Challenge::class);
} }
public function getAllByPlace(Place $place): Generator
{
$select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['challenges', 'id'], '=', ['place_in_challenge', 'challenge_id']);
$select->where('place_id', '=', $place->getId());
yield from $this->pdm->selectMultipleFromDb($select, Challenge::class);
}
} }

View File

@ -7,6 +7,7 @@ use MapGuesser\PersistentData\Model\Guess;
use MapGuesser\PersistentData\Model\User; use MapGuesser\PersistentData\Model\User;
use MapGuesser\PersistentData\Model\UserInChallenge; use MapGuesser\PersistentData\Model\UserInChallenge;
use MapGuesser\PersistentData\Model\Place; use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\Model\PlaceInChallenge;
use MapGuesser\PersistentData\PersistentDataManager; use MapGuesser\PersistentData\PersistentDataManager;
class GuessRepository class GuessRepository
@ -18,7 +19,15 @@ class GuessRepository
$this->pdm = new PersistentDataManager(); $this->pdm = new PersistentDataManager();
} }
public function getAllByUserAndChallenge(User $user, Challenge $challenge) : Generator public function getAllByUser(User $user): Generator
{
$select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $user->getId());
yield from $this->pdm->selectMultipleFromDb($select, Guess::class);
}
public function getAllByUserAndChallenge(User $user, Challenge $challenge): Generator
{ {
$select = new Select(\Container::$dbConnection); $select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']); $select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
@ -28,7 +37,7 @@ class GuessRepository
yield from $this->pdm->selectMultipleFromDb($select, Guess::class); yield from $this->pdm->selectMultipleFromDb($select, Guess::class);
} }
public function getByUserAndPlaceInChallenge(User $user, Challenge $challenge, Place $place) : ?Guess public function getByUserAndPlaceInChallenge(User $user, Challenge $challenge, Place $place): ?Guess
{ {
$select = new Select(\Container::$dbConnection); $select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']); $select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
@ -50,23 +59,40 @@ class GuessRepository
yield from $this->pdm->selectMultipleFromDb($select, Guess::class); yield from $this->pdm->selectMultipleFromDb($select, Guess::class);
} }
public function getAllInChallenge(Challenge $challenge): Generator public function getAllInChallenge(Challenge $challenge, array $withRelations = []): Generator
{ {
if (count($withRelations)) {
$necessaryRelations = [PlaceInChallenge::class];
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
}
$select = new Select(\Container::$dbConnection); $select = new Select(\Container::$dbConnection);
// $select->innerJoin('place_in_challenge', ['guesses', 'place_in_challenge_id'], '=', ['place_in_challenge', 'id']);
$select->where('challenge_id', '=', $challenge->getId()); $select->where('challenge_id', '=', $challenge->getId());
$select->orderBy('round'); $select->orderBy('round');
yield from $this->pdm->selectMultipleFromDb($select, Guess::class, true); yield from $this->pdm->selectMultipleFromDb($select, Guess::class, true, $withRelations);
} }
public function getAllInChallengeByRound(int $round, Challenge $challenge): Generator public function getAllInChallengeByRound(int $round, Challenge $challenge, array $withRelations = []): Generator
{ {
if (count($withRelations)) {
$necessaryRelations = [PlaceInChallenge::class];
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
}
$select = new Select(\Container::$dbConnection); $select = new Select(\Container::$dbConnection);
// $select->innerJoin('place_in_challenge', ['guesses', 'place_in_challenge_id'], '=', ['place_in_challenge', 'id']);
$select->where('challenge_id', '=', $challenge->getId()); $select->where('challenge_id', '=', $challenge->getId());
$select->where('round', '=', $round); $select->where('round', '=', $round);
yield from $this->pdm->selectMultipleFromDb($select, Guess::class, true); yield from $this->pdm->selectMultipleFromDb($select, Guess::class, true, $withRelations);
}
public function getAllByPlace(Place $place): Generator
{
$select = new Select(\Container::$dbConnection);
$select->innerJoin('place_in_challenge', ['place_in_challenge', 'id'], '=', ['guesses', 'place_in_challenge_id']);
$select->where('place_id', '=', $place->getId());
yield from $this->pdm->selectMultipleFromDb($select, Guess::class);
} }
} }

View File

@ -3,6 +3,7 @@
use Generator; use Generator;
use MapGuesser\Database\Query\Select; use MapGuesser\Database\Query\Select;
use MapGuesser\PersistentData\Model\Challenge; use MapGuesser\PersistentData\Model\Challenge;
use MapGuesser\PersistentData\Model\Map;
use MapGuesser\PersistentData\Model\Place; use MapGuesser\PersistentData\Model\Place;
use MapGuesser\PersistentData\Model\PlaceInChallenge; use MapGuesser\PersistentData\Model\PlaceInChallenge;
use MapGuesser\PersistentData\PersistentDataManager; use MapGuesser\PersistentData\PersistentDataManager;
@ -16,12 +17,12 @@ class PlaceInChallengeRepository
$this->pdm = new PersistentDataManager(); $this->pdm = new PersistentDataManager();
} }
public function getAllByPlace(Place $place) : Generator public function getAllByPlace(Place $place, array $withRelations = []) : Generator
{ {
$select = new Select(\Container::$dbConnection); $select = new Select(\Container::$dbConnection);
$select->where('place_id', '=', $place->getId()); $select->where('place_id', '=', $place->getId());
yield from $this->pdm->selectMultipleFromDb($select, PlaceInChallenge::class); yield from $this->pdm->selectMultipleFromDb($select, PlaceInChallenge::class, true, $withRelations);
} }
public function getAllByChallenge(Challenge $challenge) : Generator public function getAllByChallenge(Challenge $challenge) : Generator
@ -41,13 +42,13 @@ class PlaceInChallengeRepository
return $this->pdm->selectFromDb($select, PlaceInChallenge::class); return $this->pdm->selectFromDb($select, PlaceInChallenge::class);
} }
public function getByRoundInChallenge(int $round, Challenge $challenge): ?PlaceInChallenge public function getByRoundInChallenge(int $round, Challenge $challenge, array $withRelations = []): ?PlaceInChallenge
{ {
$select = new Select(\Container::$dbConnection); $select = new Select(\Container::$dbConnection);
$select->where('challenge_id', '=', $challenge->getId()); $select->where('challenge_id', '=', $challenge->getId());
$select->orderBy('round'); $select->orderBy('round');
$select->limit(1, $round); $select->limit(1, $round);
return $this->pdm->selectFromDb($select, PlaceInChallenge::class, true); return $this->pdm->selectFromDb($select, PlaceInChallenge::class, true, $withRelations);
} }
} }

View File

@ -198,14 +198,5 @@ class PlaceRepository
yield from $this->pdm->selectMultipleFromDb($select, Place::class); yield from $this->pdm->selectMultipleFromDb($select, Place::class);
} }
public function getByIdWithMap(int $placeId): ?Place
{
$select = new Select(\Container::$dbConnection);
// $select->innerJoin('maps', ['maps', 'id'], '=', ['places', 'map_id']);
$select->where(['places', 'id'], '=', $placeId);
return $this->pdm->selectFromDb($select, Place::class, true);
}
} }

View File

@ -41,15 +41,20 @@ class UserInChallengeRepository
return $this->pdm->selectFromDb($select, UserInChallenge::class); return $this->pdm->selectFromDb($select, UserInChallenge::class);
} }
public function getByUserIdAndToken(int $userId, string $token_str): ?UserInChallenge public function getByUserIdAndToken(int $userId, string $token_str, array $withRelations = []): ?UserInChallenge
{ {
if (count($withRelations)) {
$necessaryRelations = [Challenge::class];
$withRelations = array_unique(array_merge($withRelations, $necessaryRelations));
}
$token = hexdec($token_str); $token = hexdec($token_str);
$select = new Select(\Container::$dbConnection); $select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $userId); $select->where('user_id', '=', $userId);
$select->where('token', '=', $token); $select->where('token', '=', $token);
return $this->pdm->selectFromDb($select, UserInChallenge::class, true); return $this->pdm->selectFromDb($select, UserInChallenge::class, true, $withRelations);
} }
public function isUserParticipatingInChallenge(int $userId, Challenge $challenge): bool public function isUserParticipatingInChallenge(int $userId, Challenge $challenge): bool

View File

@ -38,7 +38,7 @@ class UserPlayedPlaceRepository
$select = new Select(\Container::$dbConnection); $select = new Select(\Container::$dbConnection);
$select->where('user_id', '=', $user->getId()); $select->where('user_id', '=', $user->getId());
yield from $this->pdm->selectMultipleFromDb($select, UserPlayedPlace::class, true); yield from $this->pdm->selectMultipleFromDb($select, UserPlayedPlace::class);
} }
public function getByUserIdAndPlaceId(int $userId, int $placeId) : ?UserPlayedPlace public function getByUserIdAndPlaceId(int $userId, int $placeId) : ?UserPlayedPlace

View File

@ -25,6 +25,7 @@
<p id="countdownTime" class="mono bold"></p> <p id="countdownTime" class="mono bold"></p>
</div> </div>
<div id="panoCover"></div> <div id="panoCover"></div>
<div id="panningBlockerCover"></div>
<div id="panorama"></div> <div id="panorama"></div>
<div id="showGuessButtonContainer"> <div id="showGuessButtonContainer">
<button id="showGuessButton" class="fullWidth">Show guess map</button> <button id="showGuessButton" class="fullWidth">Show guess map</button>
@ -57,6 +58,7 @@
<button id="continueButton" class="fullWidth">Continue</button> <button id="continueButton" class="fullWidth">Continue</button>
<button id="showSummaryButton" class="fullWidth">Show summary</button> <button id="showSummaryButton" class="fullWidth">Show summary</button>
<button id="startNewGameButton" class="fullWidth">Play this map again</button> <button id="startNewGameButton" class="fullWidth">Play this map again</button>
<a href="/" id="goToStart"><button class="fullWidth">Go back to the menu</button></a>
</div> </div>
</div> </div>
<div id="navigation" class="circleControl"> <div id="navigation" class="circleControl">

View File

@ -11,8 +11,10 @@ TODO: condition!
<a id="singleButton" class="button fullWidth marginTop" href="" title="Single player">Single player</a> <a id="singleButton" class="button fullWidth marginTop" href="" title="Single player">Single player</a>
<p class="bold center marginTop marginBottom">OR</p> <p class="bold center marginTop marginBottom">OR</p>
<button id="multiButton" class="fullWidth green" data-map-id="">Multiplayer (beta)</button> <button id="multiButton" class="fullWidth green" data-map-id="">Multiplayer (beta)</button>
<p class="bold center marginTop marginBottom">OR</p> <?php if ($isLoggedIn): ?>
<button id="challengeButton" class="fullWidth yellow" data-map-id="" data-timer="">Challenge (gamma)</button> <p class="bold center marginTop marginBottom">OR</p>
<button id="challengeButton" class="fullWidth yellow" data-map-id="" data-timer="">Challenge (gamma)</button>
<?php endif; ?>
<div class="right"> <div class="right">
<button id="closePlayModeButton" class="gray marginTop" type="button">Close</button> <button id="closePlayModeButton" class="gray marginTop" type="button">Close</button>
</div> </div>
@ -51,19 +53,26 @@ TODO: condition!
<div> <div>
<input type="range" id="timeLimit" name="timeLimit" min="10" max="600" value="120" /> <input type="range" id="timeLimit" name="timeLimit" min="10" max="600" value="120" />
</div> </div>
<div id="timeLimitType">
Time limit
<input type="radio" id="timeLimitTypeGame" name="timeLimitType" value="game" checked />
<label for="timeLimitTypeGame">for the whole game</label>
<input type="radio" id="timeLimitTypeRound" name="timeLimitType" value="round" />
<label for="timeLimitTypeRound">per round</label>
</div>
</div> </div>
<div> <div>
<input type="checkbox" id="noMove" name="noMove" value="noMove" /> <input type="checkbox" id="noMove" name="noMove" value="noMove" />
<label for="noMove">No movement allowed</label> <label for="noMove">No movement allowed</label>
</div> </div>
<div>
<input type="checkbox" id="noPan" name="noPan" value="noPan" />
<label for="noPan">No camera rotation allowed</label>
</div>
<div> <div>
<input type="checkbox" id="noZoom" name="noZoom" value="noZoom" /> <input type="checkbox" id="noZoom" name="noZoom" value="noZoom" />
<label for="noMove">No zoom allowed</label> <label for="noMove">No zoom allowed</label>
</div> </div>
<div>
<input type="checkbox" id="noPan" name="noPan" value="noPan" />
<label for="noPan">No camera change allowed</label>
</div>
<input type="hidden" name="mapId" id="challengeMapId" /> <input type="hidden" name="mapId" id="challengeMapId" />
</div> </div>
<button id="createNewChallengeButton" type="submit" class="button fullWidth green" href="" title="Create new challenge">Create new challenge</button> <button id="createNewChallengeButton" type="submit" class="button fullWidth green" href="" title="Create new challenge">Create new challenge</button>