log["info"][] = "Couldn't find `" . self::$pmeloJson . "`. Create a new one!"; file_put_contents(self::$pmeloJson, json_encode([])); } // init members $this->trainees = self::getTrainees(); $this->rankings = $this->createRankings(); $this->fighters = []; foreach ($_SESSION["pmelo"]["fighterIds"] as $id) { $this->fighters[$id] = $this->trainees[$id]; } // @todo Can be split. Some actions need the members to be already filled, some could be done earlier. // check for action in post data if (array_key_exists("pmelo", $_POST)) { // setting the current fighters // - meaning: fighter list is automatically updated by posted fighters if (array_key_exists("fighterIds", $_POST["pmelo"])) { $_SESSION["pmelo"]["fighterIds"] = $_POST["pmelo"]["fighterIds"]; header("Location: pmelo"); } if (array_key_exists("promote", $_POST["pmelo"])) { $promote = $_POST["pmelo"]["promote"]; $this->promote( $promote["promoteeId"], $promote["promoteeRank"], $promote["degradeeId"], $promote["degradeeRank"] ); header("Location: pmelo"); } } // save the updated ranking // @todo should be in destructor self::saveRankings($this->rankings); } function __destruct() { // sad, the destructor is not allowed to use file_put_contents } // load all active trainees into a id=>User assoc array public static function getTrainees() { $traineeList = array_map( "User::fromDbArray", User::dbSelectWithAttribute(4) ); $traineeAssocArray = []; foreach ($traineeList as $trainee) { $traineeAssocArray[$trainee->getId()] = $trainee; } return $traineeAssocArray; } // load ranking from json file public static function loadRankings() { return json_decode(file_get_contents(self::$pmeloJson)); } // save a ranking to json file public static function saveRankings(array $rankings) { file_put_contents(self::$pmeloJson, json_encode($rankings)); } // simple logger to a logging buffer function var_log( $variable, string $prefix = null, string $logChannel = "info" ) { if (!in_array($logChannel, ["info", "warning", "error"])) { $logChannel = "info"; } $prefix = !empty($prefix) ? $prefix . ": " : ""; $this->log[$logChannel][] = $prefix . var_export($variable, true); } // create the ranking for the current session (load saved ranking from file, remove old trainees, add new trainees) public function createRankings() { // load the last state of the ranking $loadedRanking = self::loadRankings(); // check if the ranked trainees still are in training // - the ranking with $cleanRanking = []; // - trainees that aren't currently in the ranking for later inserting $toBeInsertedTrainees = $this->trainees; foreach ($loadedRanking as $id) { if (array_key_exists($id, $this->trainees)) { // userId is still in training, so append it to the cleaned up ranking $cleanRanking[] = $id; // trainees already in the ranking we won't have to insert manual unset($toBeInsertedTrainees[$id]); } } // get the ids of the to be inserted trainees sorted by the birthday $newTraineesIds = array_map(function ($u) { return $u->getId(); }, $toBeInsertedTrainees); usort($newTraineesIds, function ($lhs, $rhs) { return $this->trainees[$lhs]->getStrBirthday() < $this->trainees[$rhs]->getStrBirthday() ? -1 : ($this->trainees[$lhs]->getStrBirthday() > $this->trainees[$rhs]->getStrBirthday() ? 1 : 0); }); // now we do a mergesort (step) $updatedRanking = []; $idxNewTrainees = count($newTraineesIds) - 1; $idxRanking = count($cleanRanking) - 1; // - while we can merge, we merge while ($idxRanking >= 0 && $idxNewTrainees >= 0) { if ( $this->trainees[$cleanRanking[$idxRanking]]->getDateOfBirth() > $this->trainees[ $newTraineesIds[$idxNewTrainees] ]->getDateOfBirth() ) { array_unshift($updatedRanking, $cleanRanking[$idxRanking]); $idxRanking -= 1; } else { array_unshift( $updatedRanking, $newTraineesIds[$idxNewTrainees] ); $idxNewTrainees -= 1; } } while ($idxRanking >= 0) { array_unshift($updatedRanking, $cleanRanking[$idxRanking]); $idxRanking -= 1; } while ($idxNewTrainees >= 0) { array_unshift($updatedRanking, $newTraineesIds[$idxNewTrainees]); $idxNewTrainees -= 1; } return $updatedRanking; } private function promote( int $promoteeId, int $promoteeRank, int $degradeeId, int $degradeeRank ) { // input sanitation filterId($promoteeId); filterId($promoteeRank); filterId($degradeeId); filterId($degradeeRank); // check if both id are in the current fighter list if ( array_key_exists($promoteeId, $this->fighters) && array_key_exists($degradeeId, $this->fighters) ) { // check their current rank if ( $this->rankings[$promoteeRank] == $promoteeId && $this->rankings[$degradeeRank] == $degradeeId ) { // @todo check if they are rank neighbors in the fighter list if (true) { // do the actual switch $this->rankings[$promoteeRank] = $degradeeId; $this->rankings[$degradeeRank] = $promoteeId; $this->saveRankings($this->rankings); } } } // save the updated ranking $this->saveRankings($this->rankings); } // promotion means switching the position with another user // id-s would already be sufficient, rank is just for controlling public static function htmlPromoteButton( int $promoteeId, int $promoteeRank, int $degradeeId, int $degradeeRank ) { return "
" . "" . "" . "" . "" . "". "
"; } public $log = ["error" => [], "warning" => [], "info" => []]; public $fighters = null; public $trainees = null; // list of id-s in the order of the current ranking public $rankings = null; static $pmeloJson = "./pmeloRanking.json"; }