From a7cfc3c19f4c086414e3bada4000f0a1aa08aac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Vigh?= Date: Wed, 19 May 2021 13:06:46 +0200 Subject: [PATCH] MAPG-235 queries with selected relations enabled; reduced size of some of the queries --- src/Controller/GameFlowController.php | 20 ++-- src/PersistentData/PersistentDataManager.php | 106 +++++------------- src/Repository/GuessRepository.php | 19 +++- src/Repository/PlaceInChallengeRepository.php | 5 +- src/Repository/PlaceRepository.php | 9 -- src/Repository/UserInChallengeRepository.php | 9 +- src/Repository/UserPlayedPlaceRepository.php | 2 +- 7 files changed, 67 insertions(+), 103 deletions(-) diff --git a/src/Controller/GameFlowController.php b/src/Controller/GameFlowController.php index beab998..2e33820 100644 --- a/src/Controller/GameFlowController.php +++ b/src/Controller/GameFlowController.php @@ -6,9 +6,13 @@ use MapGuesser\Util\Geo\Position; use MapGuesser\Response\JsonContent; use MapGuesser\Interfaces\Response\IContent; use MapGuesser\Multi\MultiConnector; -use MapGuesser\PersistentData\Model\Challenge; use MapGuesser\PersistentData\PersistentDataManager; +use MapGuesser\PersistentData\Model\Challenge; 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\Repository\ChallengeRepository; use MapGuesser\Repository\GuessRepository; @@ -146,7 +150,8 @@ class GameFlowController $currentPlace = $this->placeRepository->getByRoundInChallenge($challenge, $currentRound); if (!isset($currentPlace) || $withHistory) { - foreach ($this->guessRepository->getAllInChallenge($challenge) as $guess) { + $withRelations = [User::class, PlaceInChallenge::class, Place::class]; + foreach ($this->guessRepository->getAllInChallenge($challenge, $withRelations) as $guess) { $round = $guess->getPlaceInChallenge()->getRound(); if ($guess->getUser()->getId() === $userId) { @@ -178,7 +183,7 @@ class GameFlowController $prevRound = $currentRound - 1; if ($prevRound >= 0) { - foreach ($this->guessRepository->getAllInChallengeByRound($prevRound, $challenge) as $guess) { + foreach ($this->guessRepository->getAllInChallengeByRound($prevRound, $challenge, [User::class]) as $guess) { if ($guess->getUser()->getId() != $userId) { $response['allResults'][] = [ 'userName' => $guess->getUser()->getDisplayName(), @@ -199,7 +204,7 @@ class GameFlowController $session = $this->request->session(); $userId = $session->get('userId'); $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)) { return new JsonContent(['error' => 'game_not_found']); @@ -215,9 +220,6 @@ class GameFlowController public function guess(): IContent { - // testing - $testPlace = $this->placeRepository->getByIdWithMap(5); - $mapId = (int) $this->request->query('mapId'); $session = $this->request->session(); @@ -318,7 +320,7 @@ class GameFlowController $session = $this->request->session(); $userId = $session->get('userId'); $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)) { return new JsonContent(['error' => 'game_not_found']); @@ -326,7 +328,7 @@ class GameFlowController $challenge = $userInChallenge->getChallenge(); $currentRound = $userInChallenge->getCurrentRound(); - $currentPlaceInChallenge = $this->placeInChallengeRepository->getByRoundInChallenge($currentRound, $challenge); + $currentPlaceInChallenge = $this->placeInChallengeRepository->getByRoundInChallenge($currentRound, $challenge, [Place::class, Map::class]); $currentPlace = $currentPlaceInChallenge->getPlace(); $map = $currentPlace->getMap(); diff --git a/src/PersistentData/PersistentDataManager.php b/src/PersistentData/PersistentDataManager.php index 56206d5..273eefc 100644 --- a/src/PersistentData/PersistentDataManager.php +++ b/src/PersistentData/PersistentDataManager.php @@ -8,9 +8,9 @@ use MapGuesser\PersistentData\Model\Model; 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); @@ -19,36 +19,38 @@ class PersistentDataManager } $model = new $type(); - $this->fillWithData($data, $model); + $this->fillWithData($data, $model, $withRelations); 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(); while ($data = $result->fetch(IResultSet::FETCH_ASSOC)) { $model = new $type(); - $this->fillWithData($data, $model); + $this->fillWithData($data, $model, $withRelations); 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->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(); - $relationData = []; + if (count($withRelations)) { + $relations = array_intersect($relations, $withRelations); + } while (key($data)) { $key = key($data); @@ -74,34 +76,19 @@ class PersistentDataManager next($data); } else if (substr($key, 0, strlen($relation . '__')) === $relation . '__') { - // $relation = current($relations); $relationType = current($relations); $relationModel = new $relationType(); - $this->fillWithData($data, $relationModel, $relation); + $this->fillWithData($data, $relationModel, $withRelations, $relation); $method = 'set' . str_replace('_', '', ucwords($relation, '_')); $model->$method($relationModel); next($relations); } else { - break; + return; } } - // 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(); } @@ -166,15 +153,11 @@ class PersistentDataManager $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']); $fields = call_user_func([$type, 'getFields']); - // array_walk($fields, function (&$value, $key, $table) { - // $value = [$table, $value]; - // }, $table); - $columns = []; foreach ($fields as $field) { @@ -183,29 +166,24 @@ class PersistentDataManager $select->from($table); - //TODO: only with some relations? - if ($withRelations) { + if ($useRelations) { $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) { - // $columns[] = [$table, $field]; - // } - - $columns = array_merge($columns, $this->getRelationColumns($relations)); - - $this->leftJoinRelations($select, $table, $relations); + $this->leftJoinRelations($select, $table, $relations, $withRelations); $select->columns($columns); } else { - // $select->columns($fields); $select->columns($columns); } return $select; } - private function getRelationColumns(array $relations): array + private function getRelationColumns(array $relations, array $withRelations): array { $columns = []; @@ -216,50 +194,26 @@ class PersistentDataManager } $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; } - 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) { $relationTable = call_user_func([$relationType, 'getTable']); $select->leftJoin($relationTable, [$relationTable, 'id'], '=', [$table, $relation . '_id']); $nextOrderRelations = call_user_func([$relationType, 'getRelations']); - $this->leftJoinRelations($select, $relationTable, $nextOrderRelations); - } - } - - 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); + if (count($withRelations)) { + $nextOrderRelations = array_intersect($nextOrderRelations, $withRelations); } + $this->leftJoinRelations($select, $relationTable, $nextOrderRelations, $withRelations); } } diff --git a/src/Repository/GuessRepository.php b/src/Repository/GuessRepository.php index 6eb0336..7c9b4df 100644 --- a/src/Repository/GuessRepository.php +++ b/src/Repository/GuessRepository.php @@ -7,6 +7,7 @@ use MapGuesser\PersistentData\Model\Guess; use MapGuesser\PersistentData\Model\User; use MapGuesser\PersistentData\Model\UserInChallenge; use MapGuesser\PersistentData\Model\Place; +use MapGuesser\PersistentData\Model\PlaceInChallenge; use MapGuesser\PersistentData\PersistentDataManager; class GuessRepository @@ -50,21 +51,31 @@ class GuessRepository 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->where('challenge_id', '=', $challenge->getId()); $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->where('challenge_id', '=', $challenge->getId()); $select->where('round', '=', $round); - yield from $this->pdm->selectMultipleFromDb($select, Guess::class, true); + yield from $this->pdm->selectMultipleFromDb($select, Guess::class, true, $withRelations); } } diff --git a/src/Repository/PlaceInChallengeRepository.php b/src/Repository/PlaceInChallengeRepository.php index c32c07e..63fd78f 100644 --- a/src/Repository/PlaceInChallengeRepository.php +++ b/src/Repository/PlaceInChallengeRepository.php @@ -3,6 +3,7 @@ use Generator; use MapGuesser\Database\Query\Select; use MapGuesser\PersistentData\Model\Challenge; +use MapGuesser\PersistentData\Model\Map; use MapGuesser\PersistentData\Model\Place; use MapGuesser\PersistentData\Model\PlaceInChallenge; use MapGuesser\PersistentData\PersistentDataManager; @@ -41,13 +42,13 @@ class PlaceInChallengeRepository 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->where('challenge_id', '=', $challenge->getId()); $select->orderBy('round'); $select->limit(1, $round); - return $this->pdm->selectFromDb($select, PlaceInChallenge::class, true); + return $this->pdm->selectFromDb($select, PlaceInChallenge::class, true, $withRelations); } } diff --git a/src/Repository/PlaceRepository.php b/src/Repository/PlaceRepository.php index aad8242..f676282 100644 --- a/src/Repository/PlaceRepository.php +++ b/src/Repository/PlaceRepository.php @@ -198,14 +198,5 @@ class PlaceRepository 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); - } } diff --git a/src/Repository/UserInChallengeRepository.php b/src/Repository/UserInChallengeRepository.php index 3ebdd23..a033589 100644 --- a/src/Repository/UserInChallengeRepository.php +++ b/src/Repository/UserInChallengeRepository.php @@ -41,15 +41,20 @@ class UserInChallengeRepository 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); $select = new Select(\Container::$dbConnection); $select->where('user_id', '=', $userId); $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 diff --git a/src/Repository/UserPlayedPlaceRepository.php b/src/Repository/UserPlayedPlaceRepository.php index 5daaaaa..9115af5 100644 --- a/src/Repository/UserPlayedPlaceRepository.php +++ b/src/Repository/UserPlayedPlaceRepository.php @@ -38,7 +38,7 @@ class UserPlayedPlaceRepository $select = new Select(\Container::$dbConnection); $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