%PDF- %PDF-
Direktori : /www/loslex/demo/app/Models/ |
Current File : /www/loslex/demo/app/Models/Contest.php |
<?php namespace App\Models; use App\Enums\ContestCategoryEnum; use App\Enums\ContestLevelEnum; use App\Enums\ContestPublicationStatusEnum; use App\Enums\ContestRegistrationEnum; use App\Models\ContestCategory; use App\Models\ContestDivision; use App\Models\ContestLevel; use App\Models\OrganizerGroup; use App\Models\Range; use App\Models\Registration; use App\Models\User; use App\Workers\AccountNote; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Http\Request; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Str; class Contest extends Model { use HasFactory; protected $fillable = [ 'published', 'contestname', 'range_id', 'organizer_group_id', 'date', 'contest_category_id', 'contest_level_id', 'registration_start', 'registration_end', 'registration_type', 'director_id', 'rangemaster_id', 'instructions', ]; protected $casts = [ 'settings' => 'array', 'date' => 'date', 'registration_type' => ContestRegistrationEnum::class, 'published' => ContestPublicationStatusEnum::class, ]; protected $locale; protected $now; public function __construct() { parent::__construct(); $this->locale = App::currentLocale(); $this->now = Carbon::now()->locale($this->locale); } /** Fill request values into JSON Settings field */ public function fillSettings(Request $request) { $fields = array( "presentation_start", "presentation_end", "contest_start", "contest_end", "stages", "squads", "capacity", "distribution", "feelex", "feeothers", "protestdeposit", "accountnumber","accvarsym", "accnote", "acccondition", "calibrationwpn","caliberlimit", "secretstages", "flashlight","canteen","toilet", "squadshootstyle", "offsiteregurl", "organizeremail", "restrictionstext","legend", "partners" ); $trimfields = array("presentation_start", "presentation_end", "contest_start", "contest_end"); $data = array(); foreach ($fields as $key) { if (empty($request->input($key))) { continue; } switch($key) { case "restrictionstext": case "legend": case "partners": $data[$key] = $this->normalizeInstructions($request->input($key)); break; default: $data[$key] = $request->input($key); break; } } // if squad shoots together no need to store separate times. // OTOH we need to store the null for [0] field to avoid array shifting when reading to use in contest if ($request->squadshootstyle == 'together') { foreach ($trimfields as $key) { $data[$key] = array_splice($data[$key], 0, 1); } } $this->settings = $data; } /** Normalize freetext instructions text - trims whitespaces, converts all linebreaks to \n and reduces extra newlines */ protected function normalizeInstructions(String $instructions) : String { $result = trim($instructions); // trim starting and ending whitespaces $result = str_replace(array("\r\n", "\r", "\n"), "\n", $result); // replace all wariants to single \n $result = preg_replace("/\n{3,}/", "\n\n", $result); // avoid extra whitespacing of the of the content return $result; } public function instructions(): Attribute { return Attribute::make( get: fn ($value) => $value, set: fn ($value) => $this->normalizeInstructions($value), ); } public function partnersArr(): Attribute { return Attribute::make( get: function () { $raw = $this->settings['partners'] ?? null; if (is_null($raw)) { return null; } $partnerlines = preg_split("/[\n;]/", $raw); foreach ($partnerlines as $partner) { if (preg_match("/\[(.*?)\]\((.*?)\)/", $partner, $matches)) { $partners[] = array('name' => $matches[1], 'url' => $matches[2]); } else { $partners[] = array('name' => $partner); } } return $partners; }, ); } /* ========== ========== Getters for reg_start/end ========== ========== */ public function registrationStart(): Attribute { return Attribute::make(get: fn($value) => is_null($value) ? null : new Carbon($value) ); } public function registrationEnd(): Attribute { return Attribute::make(get: fn($value) => is_null($value) ? null : new Carbon($value) ); } /* ========== ========== Custom settings attributes ========== ========== */ public function acccondition(): Attribute { return Attribute::make(get: fn () => $this->settings['acccondition'] ?? null); } public function accnote(): Attribute { return Attribute::make(get: fn () => $this->settings['accnote'] ?? null); } public function accountnumber(): Attribute { return Attribute::make(get: fn () => $this->settings['accountnumber'] ?? null); } public function accvarsym(): Attribute { return Attribute::make(get: fn () => $this->settings['accvarsym'] ?? null); } public function caliberlimit(): Attribute { return Attribute::make(get: fn () => $this->settings['caliberlimit'] ?? null); } public function calibrationwpn(): Attribute { return Attribute::make(get: fn () => $this->settings['calibrationwpn'] ?? null); } public function canteen(): Attribute { return Attribute::make(get: fn () => $this->settings['canteen'] ?? 0); } public function capacity(): Attribute { return Attribute::make(get: fn () => $this->settings['capacity'] ?? 0); } public function contestEnd(): Attribute { return Attribute::make(get: fn () => $this->settings['contest_end'] ?? null); } public function contestStart(): Attribute { return Attribute::make(get: fn () => $this->settings['contest_start'] ?? null); } public function distribution(): Attribute { return Attribute::make(get: fn () => $this->settings['distribution'] ?? null); } public function feelex(): Attribute { return Attribute::make(get: fn () => $this->settings['feelex'] ?? 0); } public function feeothers(): Attribute { return Attribute::make(get: fn () => $this->settings['feeothers'] ?? 0); } public function flashlight(): Attribute { return Attribute::make(get: fn () => $this->settings['flashlight'] ?? 0); } public function legend(): Attribute { return Attribute::make(get: fn () => $this->settings['legend'] ?? null); } public function offsiteregurl(): Attribute { return Attribute::make(get: fn () => $this->settings['offsiteregurl'] ?? ""); } public function organizerEmail(): Attribute { return Attribute::make(get: fn () => $this->settings['organizeremail'] ?? null); } public function partners(): Attribute { return Attribute::make(get: fn () => $this->settings['partners'] ?? null); } public function presentationEnd(): Attribute { return Attribute::make(get: fn () => $this->settings['presentation_end'] ?? null); } public function presentationStart(): Attribute { return Attribute::make(get: fn () => $this->settings['presentation_start'] ?? null); } public function protestdeposit(): Attribute { return Attribute::make(get: fn () => $this->settings['protestdeposit'] ?? 0); } public function restrictionstext(): Attribute { return Attribute::make(get: fn () => $this->settings['restrictionstext'] ?? null); } public function secretstages(): Attribute { return Attribute::make(get: fn () => $this->settings['secretstages'] ?? 0); } public function squads(): Attribute { return Attribute::make(get: fn () => $this->settings['squads'] ?? 0); } public function squadShootStyle(): Attribute { return Attribute::make(get: fn () => $this->settings['squadshootstyle'] ?? null); } public function stages(): Attribute { return Attribute::make(get: fn () => $this->settings['stages'] ?? 0); } public function toilet(): Attribute { return Attribute::make(get: fn () => $this->settings['toilet'] ?? 0); } public function paymentnote(): Attribute { return Attribute::make( get: function() { $paymentnote = new AccountNote($this->accnote, Auth::user()); return $paymentnote->getPaymentNote(); } ); } /* ========== ========== Other helpers ========== ========== */ /** Is registration active flag */ public function isRegActive(): Attribute { $result = $this->now->gte($this->registration_start) && $this->now->lte($this->registration_end); return Attribute::make( get: fn() => $result, ); } /** Waiting for registration to begin flag */ public function isBeforeReg(): Attribute { $regStart = Carbon::parse($this->registration_start)->locale($this->locale); return Attribute::make( get: fn () => $this->now->lt($regStart), ); } /** Registration ended flag */ public function isAfterReg(): Attribute { $regEnd = Carbon::parse($this->registration_end)->locale($this->locale); return Attribute::make( get: fn () => $this->now->gt($regEnd), ); } /** Returns true if "today" is after contest date */ public function isAfterContest(): Attribute { $today = Carbon::today()->locale($this->locale); return Attribute::make( get: fn() => $this->date->lt($today) ); } /** Contest date flag */ public function isContestDay(): Attribute { $today = Carbon::today()->locale($this->locale); return Attribute::make( get: fn() => $this->date->eq($today) ); } /** returns number of days related to "today" */ public function dayShift(): Attribute { $today = Carbon::today()->locale($this->locale); return Attribute::make( get: fn() => $today->diffInDays($this->date, false) ); } // /* Get the localized date formats */ public function dateDay(): Attribute { $this->date->settings(['formatFunction' => 'translatedFormat']); return Attribute::make(get: fn () => $this->date->format('d')); } public function dateMth(): Attribute { $dateval = Carbon::parse($this->date)->locale($this->locale); $dateval->settings(['formatFunction' => 'translatedFormat']); return Attribute::make(get: fn () => $dateval->format('M')); } public function dateDow(): Attribute { $dateval = Carbon::parse($this->date)->locale($this->locale); $dateval->settings(['formatFunction' => 'translatedFormat']); return Attribute::make(get: fn () => $dateval->format('l')); } /** Helper function to equally distribute capacity of the contest between squads */ public function squadSize(): Attribute { return Attribute::make( get: function() { $base = intdiv($this->capacity, $this->squads); $arr = array_fill(1, $this->squads, $base); $reduction = array_reduce($arr, function($res, $a) { return $res + $a; }, 0); if ($reduction == $this->capacity) { return $arr; } if ($this->distribution == "asc") { for ($i = 1; $i <= $this->squads; $i++) { $arr[$i]++; $reduction = array_reduce($arr, function($res, $a) { return $res + $a; }, 0); if ($reduction == $this->capacity) { return $arr; } } } else { for ($i = $this->squads; $i > 0; $i--) { $arr[$i]++; $reduction = array_reduce($arr, function($res, $a) { return $res + $a; }, 0); if ($reduction == $this->capacity) { return $arr; } } } } ); } /** Returns collection of divisions and count of registered */ public function divisionCounts(): Attribute { return Attribute::make( get: function() { return $this->registrations->groupBy(function(Registration $item) { return $item->division?->bgdivision; })->map->count(); } ); } /** Identifies whether the contest is LOSÃk */ public function isLosik(): bool { return $this->contest_level_id == ContestLevelEnum::LOSIK->value; } /** identifies whether the contest is classification for Voluntary State Reserves */ public function isSzsClassification(): bool { return $this->contest_level_id == ContestLevelEnum::SZSCLASSIFICATION->value; } public function getCacheKeyPrefix(string $use): string { return "contest/" . $this->id . "/" . $use . "/"; } /* ========== ========== Foreign keys ========== ========== */ /** Get the level of contest/event is placed * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function contest_level(): BelongsTo { return $this->belongsTo(ContestLevel::class); } /** Get the category of contest * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function contest_category(): BelongsTo { return $this->belongsTo(ContestCategory::class); } /** Get the range where contest is placed * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function range(): BelongsTo { return $this->belongsTo(Range::class); } /** Get the organizer that owns the Contest * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function organizer_group(): BelongsTo { return $this->belongsTo(OrganizerGroup::class); } /** Get the director of the Contest * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function director(): BelongsTo { return $this->belongsTo(User::class); } /** Get the range master of the Contest * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function rangemaster(): BelongsTo { return $this->belongsTo(User::class); } /** Registrations for the contest * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function registrations() : HasMany { return $this->hasMany(Registration::class); } }