the browser-facing portion of osu!
at master 3.3 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6namespace App\Console\Commands; 7 8use App\Models\Beatmap; 9use App\Models\Score\Best; 10use App\Models\UserStatistics; 11use Exception; 12use Illuminate\Console\Command; 13 14class UserRecalculateRankCounts extends Command 15{ 16 private ?int $from; 17 private ?int $until; 18 19 /** 20 * The name and signature of the console command. 21 * 22 * @var string 23 */ 24 protected $signature = 'user:recalculate-rank-counts {--from=} {--until=}'; 25 26 /** 27 * The console command description. 28 * 29 * @var string 30 */ 31 protected $description = 'Recalculate rank counts for user statistics.'; 32 33 /** 34 * Execute the console command. 35 * 36 * @return mixed 37 */ 38 public function handle() 39 { 40 $this->from = get_int($this->option('from')); 41 $this->until = get_int($this->option('until')); 42 43 $continue = $this->confirm('This will recalculate and update the rank counts for user statistics, continue?'); 44 45 if (!$continue) { 46 $this->error('User aborted!'); 47 return; 48 } 49 50 $start = time(); 51 52 foreach (Beatmap::MODES as $mode => $id) { 53 $this->processMode($mode); 54 } 55 56 $this->warn("\n".(time() - $start).'s taken.'); 57 } 58 59 private function processMode($mode) 60 { 61 $this->info("Recalculating {$mode}"); 62 $class = UserStatistics::class.'\\'.studly_case($mode); 63 $query = $class::query(); 64 if (present($this->from)) { 65 $query->where('user_id', '>=', $this->from); 66 } 67 68 if (present($this->until)) { 69 $query->where('user_id', '<=', $this->until); 70 } 71 72 $count = $query->count(); 73 $bar = $this->output->createProgressBar($count); 74 75 $query->chunkById(1000, function ($chunk) use ($bar) { 76 foreach ($chunk as $stats) { 77 try { 78 $counts = $this->getCountsWithStats($stats); 79 $stats->update([ 80 'x_rank_count' => $counts['X'], 81 'xh_rank_count' => $counts['XH'], 82 's_rank_count' => $counts['S'], 83 'sh_rank_count' => $counts['SH'], 84 'a_rank_count' => $counts['A'], 85 ]); 86 87 $bar->advance(); 88 } catch (Exception $e) { 89 $this->error("Exception caught, user_id: {$stats->user_id}"); 90 $this->error($e->getMessage()); 91 } 92 } 93 }, 'user_id'); 94 95 $bar->finish(); 96 $this->info(''); 97 } 98 99 private function getCountsWithStats($stats) 100 { 101 $class = Best::class.'\\'.get_class_basename(get_class($stats)); 102 $counts = $class::where('user_id', '=', $stats->user_id) 103 ->accurateRankCounts()[$stats->user_id] ?? []; 104 105 return $this->map($counts); 106 } 107 108 private function map($values) 109 { 110 return [ 111 'XH' => $values['XH'] ?? 0, 112 'SH' => $values['SH'] ?? 0, 113 'X' => $values['X'] ?? 0, 114 'S' => $values['S'] ?? 0, 115 'A' => $values['A'] ?? 0, 116 ]; 117 } 118}