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
6declare(strict_types=1);
7
8namespace App\Console\Commands;
9
10use App\Models\DailyChallengeUserStats;
11use Illuminate\Console\Command;
12
13class DailyChallengeUserStatsRecalculate extends Command
14{
15 protected $signature = 'daily-challenge:user-stats-recalculate {--all} {id?*}';
16
17 protected $description = 'Recalculate user daily challenge stats';
18
19 public function handle(): int
20 {
21 $isAll = $this->option('all');
22 $userIds = $this->argument('id');
23
24 if (count($userIds) > 0 && $isAll) {
25 $this->error("can't specify both user ids and all option");
26
27 return 1;
28 }
29
30 if (count($userIds) === 0 && !$isAll) {
31 $this->error('either user ids or all option is required');
32
33 return 1;
34 }
35
36 if ($isAll) {
37 DailyChallengeUserStats::chunkById(100, function ($statsArray) {
38 $this->process($statsArray->keyBy('user_id')->all(), true);
39 });
40 } else {
41 $statsByUserId = DailyChallengeUserStats::find($userIds)->keyBy('user_id');
42 $statsArray = [];
43 foreach ($userIds as $userId) {
44 $statsArray[$userId] = $statsByUserId[$userId] ?? null;
45 }
46
47 $this->process($statsArray, false);
48 }
49
50 return 0;
51 }
52
53 private function process(array $statsArray, bool $isAll): void
54 {
55 $verbose = $this->option('verbose') || !$isAll;
56
57 foreach ($statsArray as $userId => $stats) {
58 if ($stats === null) {
59 if ($verbose) {
60 $this->info("User {$userId}: no stats");
61 }
62 continue;
63 }
64
65 $origAttributes = $stats->getAttributes();
66 $stats->fix();
67
68 if ($origAttributes === $stats->getAttributes()) {
69 if ($verbose) {
70 $this->info("User {$userId}: no change");
71 }
72 } else {
73 $this->info("User {$userId}: updated");
74 }
75 }
76 }
77}