1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
use Symfony\Component\HttpFoundation\Request; |
4
|
|
|
|
5
|
|
|
class SeasonController extends HTMLController |
6
|
|
|
{ |
7
|
|
|
/** |
8
|
|
|
* @param Request $request |
9
|
|
|
* @param string $period The season's period: winter, spring, summer, fall |
10
|
|
|
* @param int $year The season's year |
11
|
|
|
* |
12
|
|
|
* @throws Exception When a database instance is not configured for the current environment |
13
|
|
|
* @throws NotFoundException When an invalid season is given |
14
|
|
|
* |
15
|
|
|
* @return array |
16
|
|
|
*/ |
17
|
|
|
public function showAction(Request $request, $period, $year) |
|
|
|
|
18
|
|
|
{ |
19
|
|
|
$this->parseSeason($period, $year); |
20
|
|
|
|
21
|
|
|
// Because this query can't be created efficiently using our QueryBuilder, let's do things manually |
22
|
|
|
$db = Database::getInstance(); |
23
|
|
|
$seasonQuery = sprintf(" |
24
|
|
|
SELECT %s, e.elo_new AS elo FROM players p |
25
|
|
|
INNER JOIN player_elo e ON e.user_id = p.id |
26
|
|
|
INNER JOIN ( |
27
|
|
|
SELECT |
28
|
|
|
user_id, |
29
|
|
|
MAX(match_id) AS last_match |
30
|
|
|
FROM |
31
|
|
|
player_elo |
32
|
|
|
WHERE |
33
|
|
|
season_period = ? AND season_year = ? |
34
|
|
|
GROUP BY |
35
|
|
|
user_id |
36
|
|
|
) i ON i.user_id = p.id AND i.last_match = e.match_id |
37
|
|
|
WHERE p.status = 'active' |
38
|
|
|
ORDER BY elo DESC, p.username ASC LIMIT 10; |
39
|
|
|
", Player::getEagerColumns('p')); |
40
|
|
|
$results = $db->query($seasonQuery, [$period, $year]); |
41
|
|
|
$players_w_elos = Player::createFromDatabaseResults($results); |
42
|
|
|
|
43
|
|
|
$seasonRange = Season::getCurrentSeasonRange($period); |
44
|
|
|
$matchQuery = Match::getQueryBuilder(); |
45
|
|
|
$matchQuery |
46
|
|
|
->active() |
47
|
|
|
->where('time')->isAfter($seasonRange->getStartOfRange($year), true) |
48
|
|
|
->where('time')->isBefore($seasonRange->getEndOfRange($year), true) |
49
|
|
|
; |
50
|
|
|
|
51
|
|
|
$fmQuery = clone $matchQuery; |
52
|
|
|
$offiQuery = clone $matchQuery; |
53
|
|
|
|
54
|
|
|
$fmCount = $fmQuery->where('type')->equals(Match::FUN)->count(); |
55
|
|
|
$offiCount = $offiQuery->where('type')->equals(Match::OFFICIAL)->count(); |
56
|
|
|
|
57
|
|
|
Map::getQueryBuilder()->addToCache(); |
58
|
|
|
$mapQuery = ' |
59
|
|
|
SELECT |
60
|
|
|
map AS map_id, |
61
|
|
|
COUNT(*) AS match_count |
62
|
|
|
FROM |
63
|
|
|
matches |
64
|
|
|
WHERE |
65
|
|
|
timestamp >= ? AND timestamp <= ? AND map IS NOT NULL |
66
|
|
|
GROUP BY |
67
|
|
|
map |
68
|
|
|
HAVING |
69
|
|
|
match_count > 0 |
70
|
|
|
ORDER BY |
71
|
|
|
match_count DESC |
72
|
|
|
'; |
73
|
|
|
$results = $db->query($mapQuery, [ |
74
|
|
|
$seasonRange->getStartOfRange($year), |
75
|
|
|
$seasonRange->getEndOfRange($year), |
76
|
|
|
]); |
77
|
|
|
|
78
|
|
|
$mapIDs = array_column($results, 'map_id'); |
79
|
|
|
$maps = Map::arrayIdToModel($mapIDs); |
80
|
|
|
$mapCount = array_combine($mapIDs, $results); |
81
|
|
|
|
82
|
|
|
$matchCount = " |
83
|
|
|
SELECT |
84
|
|
|
p.user_id, |
85
|
|
|
SUM(m.match_type = ?) AS match_count |
86
|
|
|
FROM |
87
|
|
|
match_participation p |
88
|
|
|
INNER JOIN |
89
|
|
|
matches m ON m.id = p.match_id |
90
|
|
|
WHERE |
91
|
|
|
m.timestamp >= ? AND m.timestamp < ? |
92
|
|
|
GROUP BY |
93
|
|
|
p.user_id |
94
|
|
|
ORDER BY |
95
|
|
|
match_count DESC |
96
|
|
|
LIMIT 10 |
97
|
|
|
"; |
98
|
|
|
$fmResults = $db->query($matchCount, [ |
99
|
|
|
'fm', |
100
|
|
|
$seasonRange->getStartOfRange($year), |
101
|
|
|
$seasonRange->getEndOfRange($year), |
102
|
|
|
]); |
103
|
|
|
$offiResults = $db->query($matchCount, [ |
104
|
|
|
'official', |
105
|
|
|
$seasonRange->getStartOfRange($year), |
106
|
|
|
$seasonRange->getEndOfRange($year), |
107
|
|
|
]); |
108
|
|
|
|
109
|
|
|
return [ |
110
|
|
|
'season' => ucfirst($period), |
111
|
|
|
'year' => $year, |
112
|
|
|
'players' => $players_w_elos, |
113
|
|
|
'fmCount' => $fmCount, |
114
|
|
|
'offiCount' => $offiCount, |
115
|
|
|
'maps' => $maps, |
116
|
|
|
'mapCount' => $mapCount, |
117
|
|
|
'player_matches' => [ |
118
|
|
|
'fm' => [ |
119
|
|
|
'players' => Player::arrayIdToModel(array_column($fmResults, 'user_id')), |
120
|
|
|
'count' => array_column($fmResults, 'match_count'), |
121
|
|
|
], |
122
|
|
|
'official' => [ |
123
|
|
|
'players' => Player::arrayIdToModel(array_column($offiResults, 'user_id')), |
124
|
|
|
'count' => array_column($offiResults, 'match_count'), |
125
|
|
|
], |
126
|
|
|
], |
127
|
|
|
]; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* Default to current season or ensure the given season is valid. |
132
|
|
|
* |
133
|
|
|
* @param string $period |
134
|
|
|
* @param int $year |
135
|
|
|
* |
136
|
|
|
* @throws NotFoundException When an invalid season is found |
137
|
|
|
*/ |
138
|
|
|
private function parseSeason(&$period, &$year) |
139
|
|
|
{ |
140
|
|
|
if (!$this->isValidSeason($period, $year)) { |
141
|
|
|
throw new NotFoundException('The specified season does not seem to exist.'); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
if ($period === 'current') { |
145
|
|
|
$period = Season::getCurrentSeason(); |
146
|
|
|
$year = TimeDate::now()->year; |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Check that a given season is valid. |
152
|
|
|
* |
153
|
|
|
* @param string $period |
154
|
|
|
* @param int $seasonYear |
155
|
|
|
* |
156
|
|
|
* @return bool |
157
|
|
|
*/ |
158
|
|
|
private function isValidSeason($period, $seasonYear) |
159
|
|
|
{ |
160
|
|
|
$currentYear = TimeDate::now()->year; |
161
|
|
|
|
162
|
|
|
// The season's in the future |
163
|
|
|
if ($seasonYear > $currentYear) { |
164
|
|
|
return false; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
// If the year's the same, we need to make sure the season's not in the future; e.g. Fall 2017 shouldn't be |
168
|
|
|
// valid when it's only July 2017 |
169
|
|
|
if ($seasonYear == $currentYear && |
170
|
|
|
Season::toInt($period) > Season::toInt(Season::getCurrentSeason()) |
171
|
|
|
) { |
172
|
|
|
return false; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
return true; |
176
|
|
|
} |
177
|
|
|
} |
178
|
|
|
|
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.