var_log($_SESSION, "session"); // starting/continuing a session session_start(); // create 'pmelo' section in the sessions data if (!array_key_exists("pmelo", $_SESSION)) { $_SESSION["pmelo"] = []; } // - data storage for id-s of chosen fighters if (!array_key_exists("fighterIds", $_SESSION["pmelo"])) { $_SESSION["pmelo"]["fighterIds"] = []; } // load/recreate ranking data if (!is_file(self::$pmeloJson)) { $this->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->var_log( array_map(function ($user) { return $user->getFirstName(); }, $this->trainees), "trainees from db" ); $this->rankings = $this->createRankings(); $this->var_log( array_map(function ($id) { return $this->trainees[$id]->getFirstName(); }, $this->rankings), "current ranking" ); $this->fighters = []; foreach ($_SESSION["pmelo"]["fighterIds"] as $id) { $this->fighters[$id] = $this->trainees[$id]; } $this->var_log( array_map(function ($user) { return $user->getFirstName(); }, $this->fighters), "fighters" ); // @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: ."); } if (array_key_exist("promote", $_POST["pmelo"])) { $promote = $_POST["pmelo"]["promote"]; $this->promote( $promote["promoteeId"], $promote["promoteeRank"], $promote["degradeeId"], $promote["degradeeRank"] ); header("Location: ."); } // $this->var_log($_SESSION, "session"); } // 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(); $this->var_log( array_map(function ($id) { $user = $this->trainees[$id]; return $user->getFirstName(); }, $loadedRanking), "loaded ranking" ); // 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); }); // $this->var_log( // array_map( // function($id){return $this->trainees[$id]->getStrBirthday()." ".$this->trainees[$id]->getFirstName();} // , $newTraineesIds // ) // , "newTraineesBy B-Day" // ); // 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) { // $this->var_log( [$idxRanking.", ".$idxNewTrainees=>$updatedRanking] ); // $this->var_log( // [$this->trainees[$cleanRanking[$idxRanking]]->getStrBirthday(), $this->trainees[$newTraineesIds[$idxRanking]]->getStrBirthday()] // ); if ( $this->trainees[$cleanRanking[$idxRanking]]->getDateOfBirth() > $this->trainees[ $newTraineesIds[$idxNewTrainees] ]->getDateOfBirth() ) { // $this->var_log( $this->trainees[$cleanRanking[$idxRanking]]->getFirstName(), "merge ranking insert" ); array_unshift($updatedRanking, $cleanRanking[$idxRanking]); $idxRanking -= 1; } else { // $this->var_log( $this->trainees[$newTraineesIds[$idxNewTrainees]]->getFirstName(), "merge trainees insert" ); array_unshift( $updatedRanking, $newTraineesIds[$idxNewTrainees] ); $idxNewTrainees -= 1; } } // $this->var_log( // ["idxR ".$idxRanking." idxNT ".$idxNewTrainees=>[$cleanRanking, $newTraineesIds]] // , "after merge" // ); while ($idxRanking >= 0) { // $this->var_log( $this->trainees[$cleanRanking[$idxRanking]]->getFirstName(), "rest ranking insert" ); array_unshift($updatedRanking, $cleanRanking[$idxRanking]); $idxRanking -= 1; } while ($idxNewTrainees >= 0) { // $this->var_log( $this->trainees[$newTraineesIds[$idxNewTrainees]]->getFirstName(), "rest newTrainees insert" ); 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(); } } } // save the updated ranking } // promotion means switching the position with another user // id-s would already be sufficient, rank is just for controlling function htmlPromoteButton( int $promoteeId, int $promoteeRank, int $degradeeId, int $degradeeRank ) { } 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"; }