GenerateRankingsCommand::execute()   D
last analyzed

Complexity

Conditions 11
Paths 336

Size

Total Lines 58
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 36
nc 336
nop 2
dl 0
loc 58
rs 4.7833
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace VideoGamesRecords\CoreBundle\Command;
6
7
use Symfony\Component\Console\Attribute\AsCommand;
8
use Symfony\Component\Console\Command\Command;
9
use Symfony\Component\Console\Input\InputArgument;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Input\InputOption;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Symfony\Component\Console\Style\SymfonyStyle;
14
use VideoGamesRecords\CoreBundle\Service\GameRankingService;
15
use VideoGamesRecords\CoreBundle\Service\PlayerRankingService;
16
17
#[AsCommand(
18
    name: 'vgr:rankings:generate',
19
    description: 'Generate rankings for specified type and period'
20
)]
21
class GenerateRankingsCommand extends Command
22
{
23
    public function __construct(
24
        private GameRankingService $gameRankingService,
25
        private PlayerRankingService $playerRankingService
26
    ) {
27
        parent::__construct();
28
    }
29
30
    protected function configure(): void
31
    {
32
        $this
33
            ->addArgument('type', InputArgument::REQUIRED, 'Ranking type (game, player)')
34
            ->addArgument('period', InputArgument::REQUIRED, 'Period type (week, month, year)')
35
            ->addOption('year', 'y', InputOption::VALUE_OPTIONAL, 'Specific year')
36
            ->addOption('month', 'm', InputOption::VALUE_OPTIONAL, 'Specific month (1-12)')
37
            ->addOption('week', 'w', InputOption::VALUE_OPTIONAL, 'Specific week (1-53)')
38
            ->addOption('clean', 'c', InputOption::VALUE_NONE, 'Clean old rankings after generation')
39
            ->setHelp('
40
This command generates rankings for the specified type and period.
41
42
Examples:
43
  # Generate current week game rankings
44
  php bin/console vgr:rankings:generate game week
45
  
46
  # Generate game rankings for specific week
47
  php bin/console vgr:rankings:generate game week --year=2025 --week=35
48
  
49
  # Generate current month player rankings
50
  php bin/console vgr:rankings:generate player month
51
  
52
  # Generate player rankings for specific month
53
  php bin/console vgr:rankings:generate player month --year=2025 --month=8
54
  
55
  # Generate current year game rankings and clean old data
56
  php bin/console vgr:rankings:generate game year --clean
57
            ');
58
    }
59
60
    protected function execute(InputInterface $input, OutputInterface $output): int
61
    {
62
        $io = new SymfonyStyle($input, $output);
63
        $type = $input->getArgument('type');
64
        $period = $input->getArgument('period');
65
        $year = $input->getOption('year') ? (int) $input->getOption('year') : null;
66
        $month = $input->getOption('month') ? (int) $input->getOption('month') : null;
67
        $week = $input->getOption('week') ? (int) $input->getOption('week') : null;
68
        $clean = $input->getOption('clean');
69
70
        $io->title('Video Games Records - Rankings Generator');
71
72
        // Validate type
73
        if (!in_array($type, ['game', 'player'])) {
74
            $io->error("Invalid type '{$type}'. Use: game or player");
75
            return Command::FAILURE;
76
        }
77
78
        // Validate period
79
        if (!in_array($period, ['week', 'month', 'year'])) {
80
            $io->error("Invalid period '{$period}'. Use: week, month, or year");
81
            return Command::FAILURE;
82
        }
83
84
        try {
85
            $rankings = [];
86
87
            if ($type === 'game') {
88
                $rankings = $this->generateGameRankings($io, $period, $year, $month, $week);
89
            } else {
90
                $rankings = $this->generatePlayerRankings($io, $period, $year, $month, $week);
91
            }
92
93
            $periodInfo = $this->getPeriodInfo($period, $year, $month, $week);
94
            $io->success("Generated " . count($rankings) . " {$type} rankings for {$periodInfo}");
95
96
            // Display top 10 rankings
97
            if (!empty($rankings)) {
98
                $this->displayTopRankings($io, $rankings, $type);
99
            }
100
101
            // Clean old rankings if requested
102
            if ($clean) {
103
                $io->section('Cleaning Old Rankings');
104
                if ($type === 'game') {
105
                    $this->gameRankingService->cleanOldRankings();
106
                } else {
107
                    $this->playerRankingService->cleanOldRankings();
108
                }
109
                $io->success('Old rankings cleaned successfully');
110
            }
111
        } catch (\Exception $e) {
112
            $io->error('Error generating rankings: ' . $e->getMessage());
113
            return Command::FAILURE;
114
        }
115
116
        $io->success('Rankings generation completed successfully!');
117
        return Command::SUCCESS;
118
    }
119
120
    private function generateGameRankings(SymfonyStyle $io, string $period, ?int $year, ?int $month, ?int $week): array
121
    {
122
        switch ($period) {
123
            case 'week':
124
                $io->section('Generating Weekly Game Rankings');
125
                if ($year && !$week) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $week of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $year of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
126
                    throw new \InvalidArgumentException('Week number is required when year is specified for weekly rankings');
127
                }
128
                return $this->gameRankingService->generateWeeklyRankings($year, $week);
129
130
            case 'month':
131
                $io->section('Generating Monthly Game Rankings');
132
                if ($year && !$month) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $month of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $year of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
133
                    throw new \InvalidArgumentException('Month number is required when year is specified for monthly rankings');
134
                }
135
                return $this->gameRankingService->generateMonthlyRankings($year, $month);
136
137
            case 'year':
138
                $io->section('Generating Yearly Game Rankings');
139
                return $this->gameRankingService->generateYearlyRankings($year);
140
141
            default:
142
                throw new \InvalidArgumentException("Invalid period '{$period}'");
143
        }
144
    }
145
146
    private function generatePlayerRankings(SymfonyStyle $io, string $period, ?int $year, ?int $month, ?int $week): array
147
    {
148
        switch ($period) {
149
            case 'week':
150
                $io->section('Generating Weekly Player Rankings');
151
                if ($year && !$week) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $year of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $week of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
152
                    throw new \InvalidArgumentException('Week number is required when year is specified for weekly rankings');
153
                }
154
                return $this->playerRankingService->generateWeeklyRankings($year, $week);
155
156
            case 'month':
157
                $io->section('Generating Monthly Player Rankings');
158
                if ($year && !$month) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $year of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $month of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
159
                    throw new \InvalidArgumentException('Month number is required when year is specified for monthly rankings');
160
                }
161
                return $this->playerRankingService->generateMonthlyRankings($year, $month);
162
163
            case 'year':
164
                $io->section('Generating Yearly Player Rankings');
165
                return $this->playerRankingService->generateYearlyRankings($year);
166
167
            default:
168
                throw new \InvalidArgumentException("Invalid period '{$period}'");
169
        }
170
    }
171
172
    private function getPeriodInfo(string $period, ?int $year, ?int $month, ?int $week): string
173
    {
174
        return match ($period) {
175
            'week' => $year && $week ? "Week {$week}/{$year}" : 'Current Week',
0 ignored issues
show
Bug Best Practice introduced by
The expression $week of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $year of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
176
            'month' => $year && $month ? "Month {$month}/{$year}" : 'Current Month',
0 ignored issues
show
Bug Best Practice introduced by
The expression $year of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $month of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
177
            'year' => $year ? "Year {$year}" : 'Current Year',
178
            default => 'Unknown Period'
179
        };
180
    }
181
182
    private function displayTopRankings(SymfonyStyle $io, array $rankings, string $type): void
183
    {
184
        $io->section("Top 10 {$type} Rankings");
185
        $tableData = [];
186
187
        foreach (array_slice($rankings, 0, 10) as $ranking) {
188
            $positionChange = $ranking->getPositionChange();
189
            $changeSymbol = match (true) {
190
                $positionChange === null => '🆕',
191
                $positionChange > 0 => '📈 +' . $positionChange,
192
                $positionChange < 0 => '📉 ' . $positionChange,
193
                default => '➡️ 0'
194
            };
195
196
            if ($type === 'game') {
197
                $name = $ranking->getGame()->getName() ?? 'N/A';
198
                $metric = $ranking->getNbPost();
199
                $metricLabel = 'Posts';
200
            } else {
201
                $name = $ranking->getPlayer()->getPseudo() ?? 'N/A';
202
                $metric = $ranking->getNbPost();
203
                $metricLabel = 'Posts';
204
            }
205
206
            $tableData[] = [
207
                $ranking->getRank(),
208
                $name,
209
                $metric,
210
                $changeSymbol
211
            ];
212
        }
213
214
        $io->table(
215
            ['Rank', ucfirst($type), $metricLabel, 'Change'],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $metricLabel seems to be defined by a foreach iteration on line 187. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
216
            $tableData
217
        );
218
    }
219
}
220