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); } //// // html code injection /// /** Echo the fighterInputForm */ public function htmlFighterInputForm(){ echo($this->getFighterInputForm($this->trainees)); } /** Echo the fighterTable */ public function htmlFighterTable(){ echo($this->getFighterTable($this->fighters, $this->rankings)); } /** Echo logOutput */ public function htmlLogOutput(){ echo($this->getLogOutput($this->log)); } //// // saving and loading //// /** load all active trainees into a id=>User assoc array */ static private 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 */ static private function loadRankings() { return json_decode(file_get_contents(self::$pmeloJson)); } /** save a ranking to json file */ static private function saveRankings(array $rankings) { file_put_contents(self::$pmeloJson, json_encode($rankings)); } //// // member functions //// /** create the ranking for the current session * * - load saved ranking from file * - remove old trainees * - add new trainees */ private function createRankings() { // load the last state of the ranking $loadedRanking = self::loadRankings(); // check if the ranked trainees still are in training $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; } /** promote a fighter * * Promotion means two fighter switch places * * $promoteeId (int>0) id to promote * $promopteeRank (int>0) current rank of the one to be promoted * $degradeeId (int>0) id to demote * $degradeeRank (int>0) new rank of the promotee */ 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; } } } // save the updated ranking $this->saveRankings($this->rankings); } //// // helper for output generation //// /** Assemble the Input form for the fighter selection * * $trainees (array(participo::user)) list of trainees that can be selected for fighting * * return fighterInputForm as html code */ static private function getFighterInputForm(array $trainees){ $style = [ 'classes'=>[ 'input-field' => "input-field col s12" ] ]; $retHtml = '
' // selects have to be wrapped into an .input-field, limitation of materializeCss .'
' .''. ''. ''. '
'. '
'; return $retHtml; } /** Assemble the ranking table of the fighters * * $fighters (array(id=>participo::User)) list of fighters in the active round * $ranking (array(rank=>id)) ranking of the current selected fighters * * return fighter ranking table as html code */ static private function getFighterTable(array $fighters, array $rankings){ $retHtml = ''. ''. ''; if (!empty($fighters)) { // cache the predecessor in the ranking for the promoting form $lastOne = null; foreach ($rankings as $rank => $id) { if (array_key_exists($id, $fighters)) { $fighter = $fighters[$id]; $retHtml .= ''. ''. ''; if (!is_null($lastOne)){ $retHtml .= ''; } $retHtml .= ''; $lastOne = ["id" => $fighter->getId(), "rank" => $rank]; } } } $retHtml .= ''. '
PlatzNameAufstieg
'.$rank.''.join(' ', [$fighter->getFirstName(), $fighter->getName()]).''.self::getPromoteButton( $fighter->getId(),$rank, $lastOne["id"],$lastOne["rank"] ).'
'; return $retHtml; } /** Assemble a Promote button * * $promoteeId (int>0) id to promote * $promoteeRank (int>0) current rank of the promotee * $degradeeId (int>0) id to demote * $degradeeRank (int>0) rank of the to be demoted */ static private function getPromoteButton( int $promoteeId, int $promoteeRank, int $degradeeId, int $degradeeRank ) { return "
" . "" . "" . "" . "" . "". "
"; } /** Assemble the log Output * * $log (array logLevel=>array(messages)) lists of log messages per logLevel * * return logOutput as html code */ private static function getLogOutput(array $log){ $retHtml = '