Files
cwsvJudo/homepage/machs/lib/machs/achievementGroup.php
marko 0e6512e759 - added ranking of top achievers
- some minor layout adjustments
2021-01-02 16:02:54 +01:00

423 lines
15 KiB
PHP

<?php
require_once('./lib/db.php');
// A series of achievements
class achievementGroup{
// data from the achievements group table
// id of the group
private $id;
// name of the group
private $name;
// Achievement, that unlocks the group
private $unlockingAchievementId;
// an image for the group
private $imageUrl;
// flag, if the group can has records
private $canHaveRecords;
// achievements, that belong to this group
private $achievements;
// pointer to the db that shall be used for queries
private static $db=null;
// name of the table
// private static $tableName = "`cwsvjudo`.`machs_achievementGroups`";
// set the dbConnection (just setting, no establishing)
public static function setDbConnection($dbConnection){
if($dbConnection instanceof PDO)
self::$db = $dbConnection;
else
self::$db = null;
return;
}
// get the db pointer
public static function getDbConnection(){
return self::$db;
}
/// Returns an array of all Achievementgroups
static function getAllAchievementGroups(){
$query = <<<SQL
SELECT * FROM `cwsvjudo`.`machs_achievementGroups`;
SQL;
$result = dbQuery(self::$db, $query);
$groups = [];
foreach($result as $r){
$gid = (int)$r['id'];
$groups[$gid] = new achievementGroup;
$groups[$gid]->setAchievementGroupData(
$r['id'],
$r['name'],
$r['unlockingAchievementId'],
$r['imageUrl'],
$r['canHaveRecords']
);
$groups[$gid]->getAchievements(['force'=>true]);
}
return $groups;
}
//getter functions for the (primitive) member variables
function getId(){return $this->id;}
function getName(){return $this->name;}
function getUnlockingAchievementId(){return $this->unlockingAchievementId;}
function getImageUrl(){return $this->imageUrl;}
function canHaveRecords(){return $this->canHaveRecords;}
/// returns list of achievements
/// - returns the previously loaded achievements
/// - reloads them if null or forced
function getAchievements($options=[]){
// standards for Options:
$force = $options['force']??false; // load the achievements from the db even if ther already are some in the group->achievements member
if(($this->achievements == null) or ($force)){
$query = <<<SQL
SELECT * FROM `achievements`
WHERE `achievementGroupId`=:groupId;
SQL;
$params = [':groupId'=>['value'=>$this->id, 'data_type'=>PDO::PARAM_INT]];
$this->achievements = dbQuery(self::$db, $query, $params);
}
return $this->achievements;
} // end getAchievements
/// Load the achievementgroup $id from the db (into this)
function loadAchievementGroupFromDb($id){
$query = <<<SQL
SELECT * FROM `cwsvjudo`.`machs_achievementGroups` WHERE `id` = :id;
SQL;
$params = [':id'=>['value'=>$id, 'data_type'=>PDO::PARAM_INT]];
$result = dbQuery(self::$db, $query, $params);
$this->setAchievementGroupData(
$result[0]['id'],
$result[0]['name'],
$result[0]['unlockingAchievementId'],
$result[0]['imageUrl'],
$result[0]['canHaveRecords']
);
$this->getAchievements(['force'=>true]);
}
/// Set the member data of the group
function setAchievementGroupData($id, $name, $unlockingAchievementId=null, $imageUrl=null, $canHaveRecords=null){
$this->id = (int)$id;
$this->name = $name;
$this->unlockingAchievementId = ($unlockingAchievementId == null ? null : (int)$unlockingAchievementId);
$this->imageUrl = $imageUrl;
$this->canHaveRecords = (bool)$canHaveRecords;
# echo("bool(".$canHaveRecords.")=".$this->canHaveRecords."\n");
# var_dump($canHaveRecords, $this->canHaveRecords);
}
/// get the next achievement, the user has to accomplish in that group
function getUsersNextAchievement($userId){
$groupsAchievements = $this->getAchievements();
if(count($this->getAchievements()) < 1)
return null;
$usersAchievementsIds = collectKeysValues(
$this->getUsersAchievements($userId),
'achievementId'
);
$usersNextAchievement = null;
foreach($groupsAchievements as $ga){
if(!in_array($ga['id'], $usersAchievementsIds)){
if($usersNextAchievement == null){
$usersNextAchievement = $ga;
continue;
}
if( $usersNextAchievement['level'] > $ga['level'] ){
$usersNextAchievement = $ga;
};
}
}
return $usersNextAchievement;
}
/// get all achievements, that unlock something
static function getUnlockingAchievements(){
// get all achievements
}
/// gets all achievements a user reached in that group as Array
function getUsersAchievements($userId, $options=[]){
$getAll = $options['getAll']??false; // ignore restriction to this group
$query = <<<SQL
SELECT *, `cwsvjudo`.`achievements`.`name` AS `achievementName` FROM `cwsvjudo`.`achievements<=>user`
JOIN `cwsvjudo`.`achievements`
ON `cwsvjudo`.`achievements<=>user`.`achievementId` = `cwsvjudo`.`achievements`.`id`
JOIN `cwsvjudo`.`machs_achievementGroups`
ON `cwsvjudo`.`achievements`.`achievementGroupId` = `cwsvjudo`.`machs_achievementGroups`.`id`
WHERE `cwsvjudo`.`achievements<=>user`.`userid` = :userId
SQL;
if(!$getAll){
$query.=" AND `cwsvjudo`.`machs_achievementGroups`.`id` = :achievementGroupId ";
$query.="ORDER BY `cwsvjudo`.`achievements`.`level` DESC";
}
$query.=";";
$params[':userId'] = array('value'=>$userId, 'data_type'=>PDO::PARAM_INT);
if(!$getAll)
$params[':achievementGroupId'] = array('value'=>$this->getId(), 'data_type'=>PDO::PARAM_INT);
$result = dbQuery($this->getDbConnection(), $query, $params);
# var_dump($query);
# var_dump($result);
return $result;
}
/// returns the materialize card html code of the Achievementgroup
///
/// @param $uId id of the user the achievements should be
function asHtmlCard($uId, $options=[]){
// Setting standard options
$noForm = $options['noForm']??true; // for deactivating the give achievement form
$retHtml = "";
$userData = record::getUserData($uId);
$usersAchievements = $this->getUsersAchievements( $uId, ['getAll'=>true] );
$usersAchievementIds=[null];
foreach($usersAchievements as $a){
$usersAchievementIds[]=(int)$a['achievementId'];
}
// If the user hasn't have the needed Achievement
if(!in_array($this->getUnlockingAchievementId(), $usersAchievementIds))
return "";
$records = record::getGroupsRecords(
$this->getId(),
record::birthday2ageClass($userData[0]['gebDatum'])
);
$achievements = $this->getAchievements();
$retHtml .= "<div class=\"col s12 m6 l4 xl3\">";/// @todo gehört eigentlich nicht mit zur karte
$retHtml .= "<div class=\"card\">";
// image + title
if($this->imageUrl != null){
$retHtml .= "<div class=\"card-image\"><img src=\"".$this->imageUrl."\">";
$retHtml .= "<span class=\"card-title\">".$this->name."</span>";
$retHtml .= "</div>";
}
else
$retHtml .= "<span style=\"padding-left: 1vw;\" class=\"card-title\">".$this->name."</span>";
// content
$retHtml .= "<div class=\"card-content\">";
// - das nächste achievement
// - als collapsible (list): des users erreichte achievements
$usersAchievements = $this->getUsersAchievements($uId);
$usersNextAchievement = $this->getUsersNextAchievement($uId);
$retHtml .= "<div style=\"font-size:1.5rem; font-weight:200%\">Nächstes Achievement</div>";
$retHtml .= "<ul class=\"collapsible\"><li>";
$retHtml .= "<div class=\"collapsible-header\" >";
if(count($usersAchievements)>0)
$retHtml .= "&#xfe40; ";
$retHtml .= $usersNextAchievement['name'].": ".$usersNextAchievement['description']."</div>";
if(count($usersAchievements)>0){
$retHtml .= "<ul class=\"collapsible-body\" style=\"color:gray\">";
foreach($this->getUsersAchievements($uId) as $a)
$retHtml .= "<li >&#10003; ".$a['achievementName'].": ".$a['description']."</li>";
$retHtml .= "</ul>";// end body
}
$retHtml .= "</li></ul>";// end collapsible
// show the current record
if($this->canHaveRecords()){
$retHtml .= "<div style=\"font-size:1.5rem; font-weight:200%\">Aktueller Rekord</div>";
if( validateDate($userData[0]['gebDatum'])){
$retHtml.=record::arrayRecord2collapsible($records[0], $userData[0], $this->getId(), $noForm);
}
else{
$retHtml.="<div>Rekorde können erst angezeigt werden, wenn das <a href=./setUserData.php>Geburtsdatum korrekt gesetzt</a> wurde!</div>";
}
}
$retHtml .= $this->listUnlockableGroups();
$retHtml .= "</div>";// end card-content
if(!$noForm){
$retHtml .= "<div class=\"card-action\">";
$retHtml .= "<form action=\".\" method=\"POST\">";
$retHtml .= "<input name=\"action\" value=\"giveUserAnAchievement\" type=\"hidden\" />";
$retHtml .= "<input name=\"redirectLocation\" value=\"./#achievementList-".$uId."\" type=\"hidden\" />";
$retHtml .= "<input name=\"userId\" value=\"".$uId."\" type=\"hidden\" />";
$retHtml .= "<input name=\"achievementId\" value=\"".$usersNextAchievement['id']."\" type=\"hidden\" />";
if( canUserGetAchievementToday( $this->getDbConnection(), $uId) or isUserAdmin($this->getDbConnection(), $_SESSION['user']['userId']) ){
// $retHtml .= "<button style=\"width:100%\" class=\"btn\" name=\"submit\" type=\"submit\" >Achievement ".$usersNextAchievement['name']." geben</button>";
$retHtml .= "<button style=\"width:100%\" class=\"btn\" name=\"submit\" type=\"submit\" >Achievement geben</button>";
}
else{
$retHtml .= "<button disabled style=\"width:100%\" class=\"btn\" name=\"submit\" type=\"submit\" >Heute wurde schon ein Achievement erreicht!</button>";
}
$retHtml .= "</form>";
$retHtml .= "</div>";// end card-action
}
$retHtml .= "</div>";// end card
$retHtml .= "</div>";// end col
return $retHtml;
}// end asHtmlCard
/// create html code for a for to add an achievementGroup
static function htmlAddAchievementGroupForm(){
$html = "";
$html .= "<form action=\".\" method=\"POST\">";
$html .= "<input name=\"action\" type=\"hidden\" value=\"addAchievementGroup\" />";
$html .= "<input name=\"redirectLocation\" type=\"hidden\" value=\"achievementBuilder.php\" />";
$html .= "<input name=\"name\" type=\"text\" placeholder=\"name\"/>";
$html .= "<input name=\"unlockingAchievementId\" type=\"text\" placeholder=\"unlockingAchievementId\"/>";
$html .= "<input name=\"imageUrl\" type=\"text\" placeholder=\"imageUrl\"/>";
$html .= "<input type=\"submit\"/>";
$html .= "</form>";
return $html;
}
/// create html code for a for to edit an achievementGroup
function htmlEditAchievementGroupForm(){
$html = "";
$html .= "Edit ".$this->getName();
$html .= "<form action=\".\" method=\"POST\">";
$html .= "<input name=\"action\" type=\"hidden\" value=\"editAchievementGroup\" />";
$html .= "<input name=\"redirectLocation\" type=\"hidden\" value=\"achievementBuilder.php\" />";
$html .= "<input name=\"id\" type=\"hidden\" value=\"".$this->getId()."\"/>";
$html .= "<label for\"name\">name</label>";
$html .= "<input name=\"name\" type=\"text\" value=\"".$this->getName()."\"/>";
$html .= "<label for\"name\">unlockingAchievementId</label>";
$html .= "<input name=\"unlockingAchievementId\" type=\"text\" value=\"".$this->getUnlockingAchievementId()."\"/>";
$html .= "<label for\"name\">imageUrl</label>";
$html .= "<input name=\"imageUrl\" type=\"text\" value=\"".$this->getImageUrl()."\"/>";
$html .= "<input type=\"submit\"/>";
$html .= "</form>";
return $html;
}
static function htmlAutoAddAchievementsForm($achievementGroupId, $messageTemplate=null, $from=null, $to=null, $step=null){
$html = "";
$html .= "<form action=\".\" method=\"POST\">";
$html .= "<input name=\"action\" type=\"hidden\" value=\"autoAddAchievements\" />";
$html .= "<input name=\"redirectLocation\" type=\"hidden\" value=\"achievementBuilder.php\" />";
$html .= "<input name=\"achievementGroupId\" type=\"hidden\" value=\"".$achievementGroupId."\"/>";
$html .= "<label for=\"messageTemplate\">messageTemplate ('%value%' is Placeholder for the value that goes from fromValue to toValue in step)</label>";
$html .= "<input style=\"width:100%;display:block;\" name=\"messageTemplate\" type=\"textarea\" value=\"".$messageTemplate."\"/>";
$html .= "<label for\"from\">fromValue</label>";
$html .= "<input name=\"from\" type=\"text\" value=\"".$from."\"/>";
$html .= "<label for\"to\">toValue</label>";
$html .= "<input name=\"to\" type=\"text\" value=\"".$to."\"/>";
$html .= "<label for\"step\">step</label>";
$html .= "<input name=\"step\" type=\"text\" value=\"".$step."\"/>";
$html .= "<input type=\"submit\" value=\"Auto Add Achievements\" />";
$html .= "</form>";
return $html;
}
/// auto generate the achievements for this group
/// @todo only for empty groups?
function autoAddAchievements($messageTemplate, $from, $to, $step){
if(count($this->getAchievements()) > 0){
echo("Won't auto-add Achievements to non-empty AchievementGroup!");
var_dump($this->getAchievements());
return;
}
$level = 1;
if($step > 0){
for ($value = (int)$from; $value <= (int)$to; $value+=(int)$step) {
$name = $this->getName()." ".intToRomanRepresentation($level++);
$description = str_replace("%value%", (string)$value, $messageTemplate);
$this->addAchievement($name, $description, $level);
}
}
else{
for ($value = (int)$from; $value >= (int)$to; $value+=(int)$step) {
$name = $this->getName()." ".intToRomanRepresentation($level++);
$description = str_replace("%value%", (string)$value, $messageTemplate);
$this->addAchievement($name, $description, $level);
}
}
}
// adds an achievement to the group (in the db!)
function addAchievement($name, $description, $level, $rootId=null){
addAchievement(
$this->getDbConnection(),
$name,
$rootId,
$this->getId(),
$level,
$description,
null
);
}
function usersAchievementList($uId){
$usersAchievements = $this->getUsersAchievements($userId);
$retHtml .= "<ul class=\"collapsible\">";
$retHtml .= "<li>";
$body = "<ul class=\"collapsible-body\">";
foreach($achievements as $a){
if(in_array((int)$a['id'], $usersAchievementIds)){
$body .= "<li >&#10003; ".$a['name'].": ".$a['description'];
$body .= "</li>";
}
else{
$body .= "</ul>";
break;
}
}
$header = "<div class=\"collapsible-header\" style=\"color:gray\">".$a['name'].": ".$a['description']."</div>";
$retHtml .= $header.$body;
$retHtml .= "</li>";
$retHtml .= "</ul>";// end collapsible
}
function listUnlockableGroups(){
$achievementGroups = achievementGroup::getAllAchievementGroups();
$achievements = [];
foreach($this->getAchievements() as $a)
$achievements[(int)$a['id']] = $a;
$retHtml ="<div>";
foreach($achievementGroups as $g){
if(array_key_exists( $g->getUnlockingAchievementId(), $achievements)){
$retHtml .= "<div>Mit Level ".intToRomanRepresentation($achievements[(int)$g->getUnlockingAchievementId()]['level'])." wird ".$g->getName()." freigeschaltet!</div>";
}
}
$retHtml .= "</div>";
return $retHtml;
}
}
/// convert an int number to roman representation
/// @param int $number
/// @return string
function intToRomanRepresentation($number){
$map = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1);
$returnValue = '';
while ($number > 0) {
foreach ($map as $roman => $int) {
if($number >= $int) {
$number -= $int;
$returnValue .= $roman;
break;
}
}
}
return $returnValue;
}
/// in an array of arrays collect all values with specific key
function collectKeysValues($array, $key){
$values = [];
foreach($array as $a)
$values[]=$a[$key];
return $values;
}
?>