Files
cwsvJudo/homepage/participo/lib/participoLib/shiai.php
2024-01-07 18:36:43 +01:00

314 lines
9.0 KiB
PHP

<?php
require_once 'participoLib/participo.php';
/** frame for a shiai
*/
class Shiai
{
private $id = null; //< unique id
private $date = null; //< date of the shiai
private $name = null; //< name of the shiai as string
private $ageclasses = null; //< age classes as space separated 'Uxy' in a string
private $place = null; //< place of the shiai as string
private $announcementUrl = null; //< url to the announcement
private $routeUrl = null; //< url to a routing planner
private $galleryUrl = null; //< url of the gallery to a gallery of the shiai
private $promoImgUrl = null; //< promotional image for the shiai (as url)
/** name of the table in the db holding the Shiai-s
*
* @var string
*/
private static $tableName = "wettkampfkalender";
public function __construct($id, $date, $name, $ageclasses, $place, $announcementUrl, $routeUrl, $galleryUrl=null, $promoImgUrl=null)
{
//! @todo input validation and sanitation
$this->id = filterId($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 static function fromArray(array $shiai){
$id = $shiai['id'] ?? null;
$date = $shiai['date'] ?? null;
$name = $shiai['name'] ?? null;
$ageclasses = $shiai['ageclasses'] ?? null;
$place = $shiai['place'] ?? null;
$announcementUrl = $shiai['announcementUrl'] ?? null;
$routeUrl = $shiai['routeUrl'] ?? null;
// gallery stuff removed for now
return new Shiai($id, $date, $name, $ageclasses, $place, $announcementUrl, $routeUrl);
}
public function asArray(){
return [
'id'=>$this->id,
'date'=>$this->date->format('Y-m-d'),
'name'=>$this->name,
// @todo at least in theory this should again hold age categories
'ageclasses'=>implode(" ", $this->ageclasses),
'place'=>$this->place,
'announcementUrl'=>$this->announcementUrl,
'routeUrl'=>$this->announcementUrl
];
}
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, '&shy;' . $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 function getAnnouncementUrl()
{
return $this->announcementUrl;
}
public function getRouteUrl()
{
return $this->routeUrl;
}
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]);
}
/** select shiai from the database
*
* - by default, only coming events will be returned
*/
public static function dbSelect(){
$query = "SELECT `".self::$tableName."`.* FROM `".self::$tableName."` WHERE `Datum` >= CURDATE();";
$response = dbConnector::query($query);
return $response;
}
public static function fromDbArray($member)
{
return new shiai(
$member['lfdeNr'] ?? null,
$member['Datum'] ?? null,
$member['Veranstaltung'] ?? '<fehlender Name>',
$member['Altersklassen'] ?? null,
$member['Ort'] ?? '<fehlender 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 =
'<div>' .
'<h3><a href="' . $this->announcementUrl . '">' . $this->getHtmlName() . '</a></h3>' .
'<dl>' .
'<dt>Datum</dt><dd>' . $this->getHtmlDate() . '</dd>' .
'<dt>Altersklassen</dt><dd>' . $this->getHtmlDescriptiveAgeClasses() . '</dd>' .
'<dt>Ort</dt><dd><a href="' . $this->routeUrl . '">' . $this->getPlace() . '</a></dd>' .
'</dl>' .
'</div>';
return $retHtml;
}
public function getHtmlDetails()
{
return
'<dl>'
. '<dt>Name</dt><dd><a href="' . $this->announcementUrl . '">' . $this->getHtmlName() . '</a></dd>'
. '<dt>Datum</dt><dd>' . $this->getHtmlDate() . '</dd>'
. '<dt>Altersklassen</dt><dd>' . $this->getHtmlDescriptiveAgeClasses() . '</dd>'
. '<dt>Ort</dt><dd><a href="' . $this->routeUrl . '">' . $this->getPlace() . '</a></dd>' .
'</dl>'
;
}
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], ['<=', '&le;', '&#x2264;', '&#8804;', '≤'])) {
$ret[1] = $year;
}
return $ret;
}
}
// Case Jg.x-y
$akUmatchString = "/Jg\.(.*)\-{1,2}(.*)/";
$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 userId=>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;
$grouping[$startersAgeClass][$starter->getId()] = $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