Completed
Push — master ( c3f0f6...0c6e4d )
by Tomáš
02:30
created

Game   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 338
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 44
eloc 138
c 0
b 0
f 0
dl 0
loc 338
ccs 145
cts 145
cp 1
rs 8.8798

18 Methods

Rating   Name   Duplication   Size   Complexity  
A getGroup() 0 2 1
A __construct() 0 3 1
B setResults() 0 32 8
A addTeam() 0 15 4
A getTeamsIds() 0 4 1
A getResults() 0 3 1
A getTeams() 0 2 1
A setResults2() 0 19 3
A getSecond() 0 2 1
A getWin() 0 2 1
A getTeam() 0 5 2
A getLoss() 0 2 1
A isPlayed() 0 2 1
A getDraw() 0 2 1
A setResults3() 0 19 4
A getThird() 0 2 1
B resetResults() 0 25 7
A setResults4() 0 24 5

How to fix   Complexity   

Complex Class

Complex classes like Game often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Game, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace TournamentGenerator;
4
5
use Exception;
6
use TypeError;
7
8
/**
9
 * Class Game
10
 *
11
 * @package TournamentGenerator
12
 * @author  Tomáš Vojík <[email protected]>
13
 * @since   0.1
14
 */
15
class Game
16
{
17
18
	/** @var Team[] Teams playing this game */
19
	protected array $teams;
20
	/** @var array[] List of scores - [teamId => [score => value, type => win|loss|draw|second|third]] pairs */
21
	protected array $results = [];
22
	/** @var Group Group that the game belongs to */
23
	protected Group $group;
24
	/** @var int|string Id of the winning team */
25
	protected $winId;
26
	/** @var int|string Id of the losing team */
27
	protected $lossId;
28
	/** @var int|string Id of the second team */
29
	private $secondId;
30
	/** @var int|string Id of the third team */
31
	private $thirdId;
32
	/** @var int[]|string[] Ids of the teams that have drawn */
33
	private array $drawIds = [];
34
35
	/**
36
	 * Game constructor.
37
	 *
38
	 * @param Team[] $teams Teams that play in this game
39
	 * @param Group  $group Group that this game belongs to
40
	 */
41 101
	public function __construct(array $teams, Group $group) {
42 101
		$this->group = $group;
43 101
		$this->addTeam(...$teams);
44 100
	}
45
46
	/**
47
	 * Add teams to this game
48
	 *
49
	 * @param Team[] $teams
50
	 *
51
	 * @return $this
52
	 */
53 100
	public function addTeam(Team ...$teams) : Game {
54 100
		foreach ($teams as $team) {
55 100
			$this->teams[] = $team;
56 100
			$team->addGame($this);
57
58
			// Log games with this added teams to all teams added before
59 100
			foreach ($this->teams as $team2) {
60 100
				if ($team === $team2) {
61 100
					continue;
62
				}
63 100
				$team->addGameWith($team2, $this->group);
64 100
				$team2->addGameWith($team, $this->group);
65
			}
66
		}
67 100
		return $this;
68
	}
69
70
	/**
71
	 * Get the parent group object
72
	 *
73
	 * @return Group
74
	 */
75 100
	public function getGroup() : Group {
76 100
		return $this->group;
77
	}
78
79
	/**
80
	 * Get all teams from the game
81
	 *
82
	 * @return Team[]
83
	 */
84 32
	public function getTeams() : array {
85 32
		return $this->teams;
86
	}
87
88
	/**
89
	 * Get all team ids from this game
90
	 *
91
	 * @return string[]|int[]
92
	 */
93 6
	public function getTeamsIds() : array {
94 6
		return array_map(static function($a) {
95 6
			return $a->getId();
96 6
		}, $this->teams);
97
	}
98
99
	/**
100
	 * Get results
101
	 *
102
	 * @return array[]
103
	 */
104 6
	public function getResults() : array {
105 6
		ksort($this->results);
106 6
		return $this->results;
107
	}
108
109
	/**
110
	 * Set the game's results
111
	 *
112
	 * Results is an array of [teamId => teamScore] key-value pairs.
113
	 *
114
	 * @param int[] $results array of [teamId => teamScore] key-value pairs
115
	 *
116
	 * @return $this
117
	 * @throws Exception
118
	 */
119 75
	public function setResults(array $results = []) : Game {
120 75
		if (count($this->results) === 0) {
121 75
			$this->resetResults();
122
		}
123 75
		arsort($results);
124 75
		$inGame = $this->group->getInGame();
125 75
		$i = 1;
126 75
		foreach ($results as $id => $score) {
127 75
			if (!is_numeric($score)) {
128 1
				throw new TypeError('Score passed to TournamentGenerator\Game::setResults() must be of the type numeric, '.gettype($score).' given');
129
			}
130 74
			$team = $this->getTeam($id);
131 74
			if (!isset($team)) {
132 1
				throw new Exception('Couldn\'t find team with id of "'.$id.'"');
133
			}
134 73
			$this->results[$team->getId()] = ['score' => $score];
135 73
			$team->addScore($score);
136
			switch ($inGame) {
137 73
				case 2:
138 63
					$this->setResults2($i, $score, $results, $team);
139 63
					break;
140 10
				case 3:
141 1
					$this->setResults3($i, $team);
142 1
					break;
143 9
				case 4:
144 9
					$this->setResults4($i, $team);
145 9
					break;
146
			}
147 73
			$team->groupResults[$this->group->getId()]['score'] += $score;
148 73
			$i++;
149
		}
150 73
		return $this;
151
	}
152
153
	/**
154
	 * Reset the game's results
155
	 *
156
	 * @post Scores are removed
157
	 * @post Team points are subtracted
158
	 *
159
	 * @return $this
160
	 * @throws Exception
161
	 * @noinspection NullPointerExceptionInspection
162
	 */
163 75
	public function resetResults() : Game {
164 75
		foreach ($this->results as $teamId => $score) {
165 20
			$team = $this->getTeam($teamId);
166 20
			$team->groupResults[$this->group->getId()]['score'] -= $score['score'];
167 20
			$team->removeScore($score['score']);
168 20
			switch ($score['type']) {
169 20
				case 'win':
170 19
					$team->removeWin($this->group->getId());
171 19
					break;
172 20
				case 'draw':
173 1
					$team->removeDraw($this->group->getId());
174 1
					break;
175 19
				case 'loss':
176 19
					$team->removeLoss($this->group->getId());
177 19
					break;
178 2
				case 'second':
179 2
					$team->removeSecond($this->group->getId());
180 2
					break;
181 1
				case 'third':
182 1
					$team->removeThird($this->group->getId());
183 1
					break;
184
			}
185
		}
186 75
		$this->results = [];
187 75
		return $this;
188
	}
189
190
	/**
191
	 * Get team by ID
192
	 *
193
	 * @param string|int $id Team ID
194
	 *
195
	 * @return Team|null
196
	 */
197 76
	public function getTeam($id) : ?Team {
198 76
		$key = array_search($id, array_map(static function($a) {
199 76
			return $a->getId();
200 76
		}, $this->teams), true);
201 76
		return ($key !== false ? $this->teams[$key] : null);
202
	}
203
204
	/**
205
	 * Set results for 2 team game
206
	 *
207
	 * @param int   $teamPosition Team's position (first = 1, second = 2)
208
	 * @param int   $score        Team's score
209
	 * @param int[] $results      Results array (for draw checking)
210
	 * @param Team  $team         Team object
211
	 *
212
	 * @return $this
213
	 * @throws Exception
214
	 */
215 63
	protected function setResults2(int $teamPosition, int $score, array $results, Team $team) : Game {
216 63
		if (count(array_filter($results, static function($a) use ($score) {
217 63
				return $a === $score;
218 63
			})) > 1) {
219 13
			$this->drawIds[] = $team->getId();
220 13
			$team->addDraw($this->group->getId());
221 13
			$this->results[$team->getId()] += ['points' => $this->group->getDrawPoints(), 'type' => 'draw'];
222
		}
223 61
		elseif ($teamPosition === 1) {
224 61
			$this->winId = $team->getId();
225 61
			$team->addWin($this->group->getId());
226 61
			$this->results[$team->getId()] += ['points' => $this->group->getWinPoints(), 'type' => 'win'];
227
		}
228
		else {
229 61
			$this->lossId = $team->getId();
230 61
			$team->addLoss($this->group->getId());
231 61
			$this->results[$team->getId()] += ['points' => $this->group->getLostPoints(), 'type' => 'loss'];
232
		}
233 63
		return $this;
234
	}
235
236
	/**
237
	 * Set results for 3 team game
238
	 *
239
	 * @param int  $teamPosition Team's position (first = 1, second = 2, third = 3)
240
	 * @param Team $team         Team object
241
	 *
242
	 * @return $this
243
	 * @throws Exception
244
	 */
245 1
	protected function setResults3(int $teamPosition, Team $team) : Game {
246
		switch ($teamPosition) {
247 1
			case 1:
248 1
				$this->winId = $team->getId();
249 1
				$team->addWin($this->group->getId());
250 1
				$this->results[$team->getId()] += ['points' => $this->group->getWinPoints(), 'type' => 'win'];
251 1
				break;
252 1
			case 2:
253 1
				$this->secondId = $team->getId();
254 1
				$team->addSecond($this->group->getId());
255 1
				$this->results[$team->getId()] += ['points' => $this->group->getSecondPoints(), 'type' => 'second'];
256 1
				break;
257 1
			case 3:
258 1
				$this->lossId = $team->getId();
259 1
				$team->addLoss($this->group->getId());
260 1
				$this->results[$team->getId()] += ['points' => $this->group->getLostPoints(), 'type' => 'loss'];
261 1
				break;
262
		}
263 1
		return $this;
264
	}
265
266
	/**
267
	 * Set results for 4 team game
268
	 *
269
	 * @param int  $teamPosition Team's position (first = 1, second = 2, third = 3, fourth = 4)
270
	 * @param Team $team         Team object
271
	 *
272
	 * @return Game
273
	 * @throws Exception
274
	 */
275 9
	protected function setResults4(int $teamPosition, Team $team) : Game {
276
		switch ($teamPosition) {
277 9
			case 1:
278 9
				$this->winId = $team->getId();
279 9
				$team->addWin($this->group->getId());
280 9
				$this->results[$team->getId()] += ['points' => $this->group->getWinPoints(), 'type' => 'win'];
281 9
				break;
282 9
			case 2:
283 9
				$this->secondId = $team->getId();
284 9
				$team->addSecond($this->group->getId());
285 9
				$this->results[$team->getId()] += ['points' => $this->group->getSecondPoints(), 'type' => 'second'];
286 9
				break;
287 9
			case 3:
288 9
				$this->thirdId = $team->getId();
289 9
				$team->addThird($this->group->getId());
290 9
				$this->results[$team->getId()] += ['points' => $this->group->getThirdPoints(), 'type' => 'third'];
291 9
				break;
292 9
			case 4:
293 9
				$this->lossId = $team->getId();
294 9
				$team->addLoss($this->group->getId());
295 9
				$this->results[$team->getId()] += ['points' => $this->group->getLostPoints(), 'type' => 'loss'];
296 9
				break;
297
		}
298 9
		return $this;
299
	}
300
301
	/**
302
	 * Get the winning team's id
303
	 *
304
	 * @return int|string
305
	 */
306 2
	public function getWin() {
307 2
		return $this->winId;
308
	}
309
310
	/**
311
	 * Get the losing team's id
312
	 *
313
	 * @return int|string
314
	 */
315 2
	public function getLoss() {
316 2
		return $this->lossId;
317
	}
318
319
	/**
320
	 * Get the second team's id
321
	 *
322
	 * @return int|string
323
	 */
324 1
	public function getSecond() {
325 1
		return $this->secondId;
326
	}
327
328
	/**
329
	 * Get the third team's id
330
	 *
331
	 * @return int|string
332
	 */
333 1
	public function getThird() {
334 1
		return $this->thirdId;
335
	}
336
337
	/**
338
	 * Get the draws teams' id
339
	 *
340
	 * @return int[]|string[]
341
	 */
342 1
	public function getDraw() : array {
343 1
		return $this->drawIds;
344
	}
345
346
	/**
347
	 * Check if the game has been played
348
	 *
349
	 * @return bool
350
	 */
351 28
	public function isPlayed() : bool {
352 28
		return count($this->results) > 0;
353
	}
354
}
355