WithTeams::isSeeded()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 4
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 7
ccs 5
cts 5
cp 1
crap 3
rs 10
1
<?php
2
3
4
namespace TournamentGenerator\Traits;
5
6
use Exception;
7
use TournamentGenerator\Constants;
8
use TournamentGenerator\Containers\TeamContainer;
9
use TournamentGenerator\Group;
10
use TournamentGenerator\Helpers\Filter;
11
use TournamentGenerator\Helpers\Functions;
12
use TournamentGenerator\Helpers\Sorter\TeamSorter;
13
use TournamentGenerator\Interfaces\WithGroups as WithGroupsInterface;
14
use TournamentGenerator\Interfaces\WithTeams as WithTeamsInterface;
15
use TournamentGenerator\Round;
16
use TournamentGenerator\Team;
17
use TournamentGenerator\TeamFilter;
18
19
/**
20
 * Trait WithTeams
21
 *
22
 * @package TournamentGenerator\Traits
23
 * @author  Tomáš Vojík <[email protected]>
24
 * @since   0.4
25
 */
26
trait WithTeams
27
{
28
29
	/** @var TeamContainer Teams in a object */
30
	protected TeamContainer $teams;
31
32
	/**
33
	 * Create a new team and add it into the object
34
	 *
35
	 * @param string          $name Name of the new team
36
	 * @param string|int|null $id   Id of the new team - if omitted -> it is generated automatically as unique string
37
	 *
38
	 * @return Team Newly created team
39
	 * @throws Exception
40
	 */
41 137
	public function team(string $name = '', $id = null) : Team {
42 137
		$t = new Team($name, $id);
43 137
		$this->teams->insert($t);
44 137
		return $t;
45
	}
46
47
	/**
48
	 * Split teams into its Groups
49
	 *
50
	 * @param Round ...$wheres
51
	 *
52
	 * @return $this
53
	 * @throws Exception
54
	 * @noinspection CallableParameterUseCaseInTypeContextInspection
55
	 */
56 37
	public function splitTeams(Round ...$wheres) : WithTeamsInterface {
57 37
		if (count($wheres) === 0) {
58 14
			$wheres = $this->getRounds();
0 ignored issues
show
Bug introduced by
It seems like getRounds() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

58
			/** @scrutinizer ignore-call */ 
59
   $wheres = $this->getRounds();
Loading history...
59
		}
60
61 37
		$teams = $this->getTeams(true, Constants::SEED);
62 37
		if ($this::isSeeded($teams)) {
63 2
			Functions::sortAlternate($teams);
64
		}
65
		else {
66 35
			shuffle($teams);
67
		}
68
69 37
		$split = ceil(count($teams) / count($wheres));
70 37
		foreach ($wheres as $where) {
71 37
			if (count($teams) > 0) {
72 37
				$where->addTeam(...array_splice($teams, 0, $split));
0 ignored issues
show
Bug introduced by
$split of type double is incompatible with the type integer|null expected by parameter $length of array_splice(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

72
				$where->addTeam(...array_splice($teams, 0, /** @scrutinizer ignore-type */ $split));
Loading history...
73
			}
74
		}
75 37
		foreach ($wheres as $where) {
76 37
			$where->splitTeams();
77
		}
78 37
		return $this;
79
	}
80
81
	/**
82
	 * Split teams into its Groups
83
	 *
84
	 * @param Round ...$wheres
85
	 *
86
	 * @return $this
87
	 * @throws Exception
88
	 * @noinspection CallableParameterUseCaseInTypeContextInspection
89
	 */
90 14
	public function splitTeamsEvenly(Round ...$wheres) : WithTeamsInterface {
91 14
		if (count($wheres) === 0) {
92 14
			$wheres = $this->getRounds();
93
		}
94
95 14
		$teams = $this->getTeams(true, Constants::SEED);
96 14
		if ($this::isSeeded($teams)) {
97
			Functions::sortAlternate($teams);
98
		}
99
		else {
100 14
			shuffle($teams);
101
		}
102
103 14
		while (count($teams) > 0) {
104 14
			foreach ($wheres as $where) {
105 14
				if (count($teams) > 0) {
106 14
					$where->addTeam(array_pop($teams));
107
				}
108
			}
109
		}
110 14
		foreach ($wheres as $where) {
111 14
			$where->splitTeamsEvenly();
112
		}
113 14
		return $this;
114
	}
115
116
	/**
117
	 * Get all teams in the object
118
	 *
119
	 * @param bool                        $ordered  If true - order the teams by their score/points
120
	 * @param string|null                 $ordering What to order the teams by - Constants::POINTS, Constants::SCORE
121
	 * @param TeamFilter[]|TeamFilter[][] $filters  Filters to filter the returned teams (ex. if you only want to get the first 3 teams)
122
	 *
123
	 * @return Team[]
124
	 * @throws Exception
125
	 */
126 142
	public function getTeams(bool $ordered = false, ?string $ordering = Constants::POINTS, array $filters = []) : array {
127 142
		if (is_null($ordering)) {
128 25
			$ordering = Constants::POINTS;
129
		}
130 142
		if ($ordered) {
131 60
			$returnTeams = $this->sortTeams($ordering);
132
		}
133
		else {
134 141
			$returnTeams = $this->teams->unique()->get();
135
		}
136
137
		// APPLY FILTERS
138 142
		if (count($filters) > 0) {
139 25
			$this->filterTeams($returnTeams, $filters);
140
		}
141
142 136
		return $returnTeams;
143
	}
144
145
	/**
146
	 * Sort the teams by their score/points
147
	 *
148
	 * @param string|null                 $ordering What to order the teams by - Constants::POINTS, Constants::SCORE
149
	 * @param TeamFilter[]|TeamFilter[][] $filters  Filters to filter the returned teams (ex. if you only want to get the first 3 teams)
150
	 *
151
	 * @return Team[]
152
	 * @throws Exception
153
	 */
154 78
	public function sortTeams(?string $ordering = Constants::POINTS, array $filters = []) : array {
155 78
		if (is_null($ordering)) {
156 57
			$ordering = Constants::POINTS;
157
		}
158 78
		$sorter = new TeamSorter($this->getContainer(), $ordering);
159 78
		$teams = $this->teams->addSorter($sorter)->unique()->get();
160
161
		// APPLY FILTERS
162 78
		if (count($filters) > 0) {
163 19
			$this->filterTeams($teams, $filters);
164
		}
165
166 78
		return $teams;
167
	}
168
169
	/**
170
	 * Filter teams using the specified filters
171
	 *
172
	 * @param array                       $teams   Teams to filter through
173
	 * @param TeamFilter[]|TeamFilter[][] $filters Filters to use
174
	 *
175
	 * @return array
176
	 * @throws Exception
177
	 */
178 41
	public function filterTeams(array &$teams, array $filters) : array {
179
		// APPLY FILTERS
180 41
		if ($this instanceof WithGroupsInterface) {
181 5
			$filter = new Filter($filters, $this->getGroups());
182 5
			$filter->filter($teams);
183
		}
184 39
		else if ($this instanceof Group) {
185 39
			$filter = new Filter($filters, [$this]);
186 39
			$filter->filter($teams);
187
		}
188 35
		return $teams;
189
	}
190
191
	/**
192
	 * @param Team[] $teams
193
	 *
194
	 * @return bool
195
	 */
196 57
	public static function isSeeded(array $teams) : bool {
197 57
		foreach ($teams as $team) {
198 57
			if ($team->getSeed() > 0) {
199 2
				return true;
200
			}
201
		}
202 55
		return false;
203
	}
204
205
	/**
206
	 * Add one or more teams into the object.
207
	 *
208
	 * @param Team ...$teams Team objects
209
	 *
210
	 * @return WithTeamsInterface
211
	 * @throws Exception
212
	 */
213 65
	public function addTeam(Team ...$teams) : WithTeamsInterface {
214 65
		foreach ($teams as $team) {
215 65
			$this->teams->insert($team);
216
		}
217 65
		return $this;
218
	}
219
220
	/**
221
	 * Get the container for games
222
	 *
223
	 * @return TeamContainer
224
	 */
225 182
	public function getTeamContainer() : TeamContainer {
226 182
		return $this->teams;
227
	}
228
229
	/**
230
	 * Add a child container for games
231
	 *
232
	 * @param TeamContainer $container
233
	 *
234
	 * @return WithTeamsInterface
235
	 * @throws Exception
236
	 */
237 178
	public function addTeamContainer(TeamContainer $container) : WithTeamsInterface {
238 178
		$this->teams->addChild($container);
239 178
		return $this;
240
	}
241
}