%PDF- %PDF-
Direktori : /home/nginx/.vscode-server/data/User/History/-5b5ca2a2/ |
Current File : //home/nginx/.vscode-server/data/User/History/-5b5ca2a2/SPj7.php |
<?php namespace App\Workers; use App\Models\Contest; use App\Models\ContestDivision; use App\Models\Registration; use App\Models\ShooterStage; use App\Models\ShooterStageTarget; use App\Models\ShooterStageTime; use App\Models\Stage; use App\Models\User; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; use PhpOffice\PhpSpreadsheet\Reader\Xls; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; use Ramsey\Uuid\Uuid; use stdClass; use ZipArchive; class ContestImporter { public array $errors = array(); public array $warnings = array(); function __construct(Contest $contest, string $filename, string $extension) { switch ($extension){ case 'xls': $this->importExcel($contest, $filename); break; case 'xlsx': $this->importExcel($contest, $filename, true); break; case 'psc': $this->importPractiScore($contest, $filename); break; } } protected function importExcel(Contest $contest, string $filename, bool $isXlsx = false) { $numStages = $contest->stages; $tmpName = tempnam(sys_get_temp_dir(), 'practiscore.xls'); file_put_contents($tmpName, Storage::disk('contests')->get($filename)); $reader = $isXlsx ? new Xlsx() : new Xls(); $spreadsheet = $reader->load($tmpName); $ss = $spreadsheet->setActiveSheetIndex(0); // Delete old data before import DB::statement("DELETE FROM shooter_stage_times WHERE shooter_stage_id in (SELECT id FROM shooter_stages where stage_id in (SELECT id FROM stages WHERE contest_id = ?))", [$contest->id]); DB::statement("DELETE FROM shooter_stage_targets WHERE shooter_stage_id in (SELECT id FROM shooter_stages where stage_id in (SELECT id FROM stages WHERE contest_id = ?))", [$contest->id]); DB::statement("DELETE FROM shooter_stages WHERE stage_id in (SELECT id FROM stages WHERE contest_id = ?)", [$contest->id]); DB::statement("DELETE FROM stages WHERE contest_id = ?", [$contest->id]); // Create stages $stageIds = array(); for($i = 0; $i < $numStages; $i++) { $st = new Stage([ 'contest_id' => $contest->id, 'name' => "Stage " . ($i + 1), 'order' => $i + 1, 'strings' => 1 ]); $st->save(); $stageIds[$i] = $st->id; } foreach (ExcelHelper::$divisionDefaultStartPosition as $division => $position) { // Prepare division ID $divisionId = ContestDivision::where(DB::raw('UPPER(bgdivision)'), $division)->first()->id; // Get mail and alias, if empty, go to another division while($mailalias = trim($ss->getCell("B" . $position)->getValue())) { list($email, $alias) = explode("/", $mailalias); $alias = strtoupper($alias); $notCompeting = strtoupper(rim($ss->getCell("B" . $position)->getValue())) == "MZ"; list($firstName, $lastName) = explode(" ", $ss->getCell("C" . $position)->getValue()); $user = $this->getOrCreateUserByAlias($alias, $email, $firstName, $lastName); $registration = new Registration([ 'contest_id' => $contest->id, 'user_id' => $user->id, 'contest_division_id' => $divisionId, 'squad' => 1, 'notcomp' => $notCompeting ? 1 : 0 ]); $registration->canceltoken = Str::orderedUuid(); $registration->save(); // Get stage data $col = 4; for ($i = 0; $i < $numStages; $i++) { $shooterStage = new ShooterStage([ 'registration_id' => $registration->id, 'stage_id' => $stageIds[$i], 'proc' => $ss->getCell([$col + 8, $position])->getValue() ?? 0, 'noshoot' => $ss->getCell([$col + 7, $position])->getValue() ?? 0 ]); $shooterStage->save(); $shooterStageTime = new ShooterStageTime([ 'shooter_stage_id' => $shooterStage->id, 'time' => $ss->getCell([$col, $position])->getValue(), 'order' => 1 ]); $shooterStageTime->save(); $shooterStageTarget = new ShooterStageTarget([ 'shooter_stage_id' => $shooterStage->id, 'order' => 1, 'popper' => $ss->getCell([$col + 1, $position])->getValue() ?? 0, 'alpha' => $ss->getCell([$col + 2, $position])->getValue() ?? 0, 'charlie' => $ss->getCell([$col + 3, $position])->getValue() ?? 0, 'delta' => $ss->getCell([$col + 4, $position])->getValue() ?? 0, 'miss' => $ss->getCell([$col + 5, $position])->getValue() ?? 0, 'misspopper' => $ss->getCell([$col + 6, $position])->getValue() ?? 0, ]); $shooterStageTarget->save(); $col += 10; } $position++; } } } protected function importPractiScore(Contest $contest, string $filename) { $tmpName = tempnam(sys_get_temp_dir(), 'practiscore.zip'); file_put_contents($tmpName, Storage::disk('contests')->get($filename)); $zip = new ZipArchive; $res = $zip->open($tmpName); $txt = $zip->getFromName('match_def.json'); $matchDef = json_decode($txt); $txt = $zip->getFromName('match_scores.json'); $scores = json_decode($txt); unset($txt); $zip->close(); unlink($tmpName); // Prepare stages $stages = array(); $numStages = 0; foreach ($matchDef->match_stages as $match_stage) { $stage = new stdClass(); $stage->guid = $match_stage->stage_uuid; $stage->order = $match_stage->stage_number; $stage->name = $match_stage->stage_name; $stage->deleted = $match_stage->stage_deleted ?? false; $stage->strings = $match_stage->stage_strings; $stages[$stage->guid] = $stage; if(!$stage->deleted) $numStages++; } if($contest->stages != $numStages) { $this->errors[] = __('Contest has :cStages but imported PractiScore file contains :psStages stages', ['cStages' => $contest->stages, 'psStages' => $numStages]); return; } $shooters = $this->psProcessShooters($matchDef, $contest); DB::statement("DELETE FROM shooter_stage_times WHERE shooter_stage_id in (SELECT id FROM shooter_stages where stage_id in (SELECT id FROM stages WHERE contest_id = ?))", [$contest->id]); DB::statement("DELETE FROM shooter_stage_targets WHERE shooter_stage_id in (SELECT id FROM shooter_stages where stage_id in (SELECT id FROM stages WHERE contest_id = ?))", [$contest->id]); DB::statement("DELETE FROM shooter_stages WHERE stage_id in (SELECT id FROM stages WHERE contest_id = ?)", [$contest->id]); DB::statement("DELETE FROM stages WHERE contest_id = ?", [$contest->id]); // Process scores foreach ($scores->match_scores as $stage) { $defStage = $stages[$stage->stage_uuid]; if($defStage->deleted) continue; $st = new Stage([ 'contest_id' => $contest->id, 'name' => $defStage->name, 'order' => $defStage->order, 'strings' => $defStage->strings ]); $st->save(); $stageId = $st->id; foreach ($stage->stage_stagescores as $score) { if(!isset($shooters[$score->shtr])) continue; $shooterStage = new ShooterStage([ 'stage_id' => $stageId, 'registration_id' => $shooters[$score->shtr]->id, 'proc' => $score->proc ?? 0, 'noshoot' => 0 ]); $shooterStage->save(); $stageNo = $shooterStage->id; $noshoots = $score->popns ?? 0; // Proces times $order = 1; foreach ($score->str as $time) { $strings = null; // parse string splits if(isset($score->meta)) { foreach ($score->meta as $meta) { if(strstr($meta->k, "string" . ($order-1))) { $strings = array(); $times = explode(",", $meta->v); $curr = 0.0; foreach ($times as $t) { $strings[] = number_format((double)$t - $curr, 2, '.', ''); $curr = (double)$t; } } } } $shooterStageTime = new ShooterStageTime([ 'shooter_stage_id' => $stageNo, 'time' => $time, 'order' => $order++, 'string' => $strings != null ? implode(",", $strings) : null ]); $shooterStageTime->save(); } $dataTpl = array( "shooter_stage_id" => $stageNo, "alpha" => 0, "charlie" => 0, "delta" => 0, "miss" => 0, "popper" => 0, "misspopper" => 0 ); $order = 1; $data = $this->arrayCopy($dataTpl); if($score->popm > 0 || $score->poph > 0) { $data["order"] = $order++; $data["popper"] = $score->poph; $data["misspopper"] = $score->popm; $target = new ShooterStageTarget($data); $target->save(); $data = $this->arrayCopy($dataTpl); } if(isset($score->ts)) { foreach ($score->ts as $t) { $data["order"] = $order++; $data["alpha"] = ($t & 0xF); $data["charlie"] = ($t & 0xF00) >> 8; $data["delta"] = ($t & 0xF000) >> 12; $data["miss"] = ($t & 0xF00000) >> 20; $noshoots += ($t & 0xF0000) >> 16; $target = new ShooterStageTarget($data); $target->save(); $data = $this->arrayCopy($dataTpl); } } $shooterStage->noshoot = $noshoots; $shooterStage->save(); } } } private function getUserByAlias(string $alias) { return User::where(DB::raw('UPPER(username)'), strtoupper($alias))->first(); } private function getUserByEmail(string $email) { return User::where(DB::raw('UPPER(email)'), strtoupper($email))->first(); } /** * @param mixed $matchDef * @param Contest $contest * @return void */ public function psProcessShooters(mixed $matchDef, Contest $contest): array { $shooters = array(); foreach ($matchDef->match_shooters as $match_shooter) { if ($match_shooter->sh_del || $match_shooter->sh_dq) continue; $shooter = new stdClass(); $shooter->id = null; $shooter->firstName = $match_shooter->sh_fn; $shooter->lastName = $match_shooter->sh_ln; $shooter->mail = (isset($match_shooter->sh_eml) && $match_shooter->sh_eml) ? $match_shooter->sh_eml : Uuid::uuid4() . "@test.com"; $shooter->uid = $match_shooter->sh_uid; $shooter->division = strtoupper($match_shooter->sh_dvp); $shooter->squad = $match_shooter->sh_sqd; $shooter->alias = (isset($match_shooter->sh_id) && $match_shooter->sh_id) ? strtoupper($match_shooter->sh_id) : (string)(Uuid::uuid4()); $shooter->notCompeting = isset($match_shooter->sh_chkins) && in_array("NotCompeting", $match_shooter->sh_chkins); $registration = $contest->registrations()->where('canceltoken', $shooter->uid)->first(); if (!$registration) { // try to create registration $user = $this->getOrCreateUserByAlias($shooter->alias, $shooter->mail, $shooter->firstName, $shooter->lastName); $registration = new Registration([ 'contest_id' => $contest->id, 'user_id' => $user->id, 'contest_division_id' => 1, 'squad' => $shooter->squad, 'notcomp' => $shooter->notCompeting ? 1 : 0 ]); $registration->canceltoken = $shooter->uid; $registration->save(); } if (strtoupper($registration->division->bgdivision) != $shooter->division) { // update division $registration->contest_division_id = ContestDivision::where(DB::raw('UPPER(bgdivision)'), $shooter->division)->first()->id; $registration->save(); } $shooter->id = $registration->id; $shooters[$shooter->uid] = $shooter; } return $shooters; } public function hasMessages() { return count($this->errors) > 0 || count($this->warnings) > 0; } private function arrayCopy($arr) { $newArray = array(); foreach($arr as $key => $value) { if(is_array($value)) $newArray[$key] = $this->arrayCopy($value); else if(is_object($value)) $newArray[$key] = clone $value; else $newArray[$key] = $value; } return $newArray; } /** * @param stdClass $shooter * @return User */ public function getOrCreateUserByAlias($alias, $email, $firstName, $lastName): User { $user = $this->getUserByAlias($alias); if (!$user) { // Create new user $this->warnings[] = __('User with name :name and alias :alias does not exist, creating new one', ['name' => $firstName . " " . $lastName, 'alias' => $alias]); $user = new User([ 'username' => $alias, 'firstname' => $firstName, 'lastname' => $lastName, 'email' => $email, 'password' => "" ]); $user->personaltoken = Str::orderedUuid(); $user->save(); } return $user; } }