id = (int) $id; $this->date = DateTime::createFromFormat('Y-m-d', $date); $this->name = $name; $this->ageclasses = $ageclasses ? self::akListString2jgArray($ageclasses) : null; $this->place = $place; $this->announcementUrl = $announcementUrl; $this->routeUrl = $routeUrl; $this->galleryUrl = $galleryUrl; $this->promoImgUrl = $promoImgUrl; } public function getId() { return $this->id; } public function getHtmlName() { $name = ($this->name != null ? $this->name : 'Wettkampf ohne Namen'); foreach (['meisterschaft', 'turnier', 'randori'] as $fragment) { $name = str_replace($fragment, '­' . $fragment, $name); } return $name; } public function getHtmlDate() { return ($this->date != null ? $this->date->format('Y-m-d') : 'fehlendes Datum'); } public function getAgeClasses() { return ($this->ageclasses != null ? $this->ageclasses : '-'); } public function getPlace() { return ($this->place != null ? $this->place : '-'); } public static function loadFromDb(int $id) { $id = filterId($id); $query = 'SELECT * FROM `cwsvjudo`.`wettkampfkalender` WHERE `lfdeNr` = :id;'; $params = [':id' => ['value' => $id, 'data_type' => PDO::PARAM_INT]]; $response = dbConnector::query($query, $params); // ids are considered unique. so every other count then 1 is treated as error to prevent unprivileged access if (count($response) != 1) { return null; } return self::fromDbArray($response[0]); } public static function fromDbArray($member) { return new shiai( $member['lfdeNr'] ?? null, $member['Datum'] ?? null, $member['Veranstaltung'] ?? '', $member['Altersklassen'] ?? null, $member['Ort'] ?? '', $member['Ausschreibung'] ?? null, $member['Routenplaner'] ?? null, $member['galleryLink'] ?? null, $member['promoPic'] ?? null ); } /** shiai event as html code for displaying * * @return html formatted string */ public function getHtml() { $retHtml = ''; $retHtml = '
' . '

' . $this->getHtmlName() . '

' . '
' . '
Datum
' . $this->getHtmlDate() . '
' . '
Altersklassen
' . $this->getHtmlDescriptiveAgeClasses() . '
' . '
Ort
' . $this->getPlace() . '
' . '
' . '
'; return $retHtml; } public function getHtmlDescriptiveAgeClasses() { $retList = []; foreach ($this->ageclasses as $ageclass => $years) { $htmlFragment = $ageclass; $years = $years[0]; if ($years[0] || $years[1]) { $htmlFragment .= '('; if ($years[1]) { $htmlFragment .= strval($years[0]) . '-' . strval($years[1]); } else { $htmlFragment .= '<=' . strval($years[0]); } $htmlFragment .= ')'; } $retList[] = $htmlFragment; } return implode(', ', $retList); } /** convert a list of age class formatted strings into a list of intervals of years * * @param string $akListString * @param int $year * @return list[array(int,int)] list of tupels with lower/upper bound in date year of the age classes */ private static function akListString2jgArray(string $akListString, int $year = null) { $year = filterPosInt($year) ?? filterPosInt((new DateTime)->format('Y')); $ret = []; foreach (explode(' ', $akListString) as $ak) { $ret[$ak] = self::akString2jgIntervall($ak, $year); } return $ret; } /** convert age class from formatted string to interval of years * * @param [string] $akString * @param [type] $year * @return array(int,int) [x,y] with x the lower bound and y the upper bound of the age class in years. Both bounds are still included in the interval. */ private static function akString2jgIntervall(string $akString, int $year /*= null*/) { // input sanitation $year = filterPosInt($year) ?? filterPosInt((new DateTime)->format('Y')); $ret = [null, null]; // Matching against the different age class formats // - ..Ux // - Jg.x-y // Case Ux $akUmatchString = '/(.*)U(.*)/'; $matches = []; preg_match($akUmatchString, $akString, $matches); // The found match should cover the whole string. Otherwise it isn't applicable. if ($matches[0] == $akString) { // The x in Ux should be a positive integer. $ageLimit = filterPosInt($matches[2]); if ($ageLimit) { $ret[0] = $year - $ageLimit + 1; // lowering the lower bound according to the modifiers if ($matches[1] == '') { $ret[1] = $year - $ageLimit + 2; } elseif ($matches[1] == '-') { $ret[1] = $year - $ageLimit + 3; } elseif ($matches[1] == '--') { $ret[1] = $year - $ageLimit + 4; } elseif (in_array($matches[1], ['<=', '≤', '≤', '≤', '≤'])) { $ret[1] = $year; } return $ret; } } // Case Jg.x-y $akUmatchString = "/Jg\.(.*)\-(.*)/"; $matches = []; preg_match($akUmatchString, $akString, $matches); // The found match should cover the whole string. Otherwise it isn't applicable. if ($matches[0] == $akString) { $ret[0] = filterPosInt($matches[1]); $ret[1] = filterPosInt($matches[2]); return $ret; } return $ret; } /** grouping users kids by ageGroups * * @return array(ageGroup => list(users in ageGroup)) */ public function ageGroups() { $kids = participo::getKids(); return self::ageClassGrouping($this->ageclasses, $kids); } /** grouping users by given age class * * @param array $ageClassList as array string representation of age class => [lower year bound, upper year bound] * @param array $starterList list of starter (User) * @return array of string representation of age class => array of user in this class */ private static function ageClassGrouping(array $ageClassList, array $starterList) { $grouping = []; foreach ($ageClassList as $ageClass => $yearBoundaries) { $grouping[$ageClass] = []; } $grouping[null] = []; foreach ($starterList as $starter) { $startersAgeClass = $starter->yearOfBirth() ? self::getAgeClassFromYear($starter->yearOfBirth(), $ageClassList) : null; array_push($grouping[$startersAgeClass], $starter); } return $grouping; } private static function getAgeClassFromYear(int $year, array $ageClassList) { foreach ($ageClassList as $ageClass => $yearBoundaries) { if (($yearBoundaries[0] <= $year) && ($year <= $yearBoundaries[1])) { return $ageClass; } } return null; } } // end class shiai