Passed
Push — master ( 795926...7012fc )
by Tomáš
11:11
created

WithTeams::getTeams()   B

Complexity

Conditions 10
Paths 48

Size

Total Lines 32
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 10

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 19
c 1
b 0
f 0
nc 48
nop 3
dl 0
loc 32
ccs 20
cts 20
cp 1
crap 10
rs 7.6666

How to fix   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
4
namespace TournamentGenerator\Traits;
5
6
use Exception;
7
use TournamentGenerator\Constants;
8
use TournamentGenerator\Group;
9
use TournamentGenerator\Helpers\Filter;
10
use TournamentGenerator\Helpers\Sorter\Teams;
11
use TournamentGenerator\Interfaces\WithCategories;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, TournamentGenerator\Traits\WithCategories. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
12
use TournamentGenerator\Interfaces\WithGroups;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, TournamentGenerator\Traits\WithGroups. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
13
use TournamentGenerator\Interfaces\WithRounds;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, TournamentGenerator\Traits\WithRounds. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
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 Team[] Teams in a object */
30
	protected array $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 null   $id   Id of the new team - if omitted -> it is generated automatically as unique string
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
37
	 *
38
	 * @return Team Newly created team
39
	 */
40 50
	public function team(string $name = '', $id = null) : Team {
41 50
		$t = new Team($name, $id);
42 50
		$this->teams[] = $t;
43 50
		return $t;
44
	}
45
46
	/**
47
	 * Split teams into its Groups
48
	 *
49
	 * @param Round ...$wheres
50
	 *
51
	 * @return $this
52
	 * @throws Exception
53
	 * @noinspection CallableParameterUseCaseInTypeContextInspection
54
	 */
55 29
	public function splitTeams(Round ...$wheres) : WithTeamsInterface {
56 29
		if (count($wheres) === 0) {
57 6
			$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

57
			/** @scrutinizer ignore-call */ 
58
   $wheres = $this->getRounds();
Loading history...
58
		}
59
60 29
		$teams = $this->getTeams();
61 29
		shuffle($teams);
62
63 29
		while (count($teams) > 0) {
64 29
			foreach ($wheres as $where) {
65 29
				if (count($teams) > 0) {
66 29
					$where->addTeam(array_shift($teams));
67
				}
68
			}
69
		}
70 29
		foreach ($wheres as $where) {
71 29
			$where->splitTeams();
72
		}
73 29
		return $this;
1 ignored issue
show
Bug Best Practice introduced by
The expression return $this returns the type TournamentGenerator\Traits\WithTeams which is incompatible with the type-hinted return TournamentGenerator\Interfaces\WithTeams.
Loading history...
74
	}
75
76
	/**
77
	 * Get all teams in the object
78
	 *
79
	 * @param bool                        $ordered  If true - order the teams by their score/points
80
	 * @param string|null                 $ordering What to order the teams by - Constants::POINTS, Constants::SCORE
81
	 * @param TeamFilter[]|TeamFilter[][] $filters  Filters to filter the returned teams (ex. if you only want to get the first 3 teams)
82
	 *
83
	 * @return Team[]
84
	 * @throws Exception
85
	 */
86 101
	public function getTeams(bool $ordered = false, ?string $ordering = Constants::POINTS, array $filters = []) : array {
87 101
		if (is_null($ordering)) {
88 25
			$ordering = Constants::POINTS;
89
		}
90 101
		$teams = [$this->teams];
91 101
		if ($this instanceof WithCategories) {
92 34
			foreach ($this->getCategories() as $category) {
93 5
				$teams[] = $category->getTeams();
94
			}
95
		}
96 101
		if ($this instanceof WithRounds) {
97 44
			foreach ($this->getRounds() as $round) {
98 38
				$teams[] = $round->getTeams();
99
			}
100
		}
101 95
		elseif ($this instanceof WithGroups) {
102 51
			foreach ($this->getGroups() as $group) {
103 47
				$teams[] = $group->getTeams();
104
			}
105
		}
106 101
		$this->teams = $this->uniqueTeams(array_merge(...$teams));
107 101
		$returnTeams = $this->teams;
108 101
		if ($ordered) {
109 9
			$returnTeams = $this->sortTeams($ordering);
110
		}
111
112
		// APPLY FILTERS
113 101
		if (count($filters) > 0) {
114 25
			$this->filterTeams($returnTeams, $filters);
115
		}
116
117 95
		return $returnTeams;
118
	}
119
120
	/**
121
	 * @param Team[] $teams
122
	 *
123
	 * @return Team[]
124
	 */
125 101
	protected function uniqueTeams(array $teams) : array {
126 101
		$ids = [];
127 101
		foreach ($teams as $key => $team) {
128 100
			if (in_array($team->getId(), $ids, true)) {
129 19
				unset($teams[$key]);
130 19
				continue;
131
			}
132 100
			$ids[] = $team->getId();
133
		}
134 101
		return array_values($teams);
135
	}
136
137
	/**
138
	 * Sort the teams by their score/points
139
	 *
140
	 * @param string|null                 $ordering What to order the teams by - Constants::POINTS, Constants::SCORE
141
	 * @param TeamFilter[]|TeamFilter[][] $filters  Filters to filter the returned teams (ex. if you only want to get the first 3 teams)
142
	 *
143
	 * @return Team[]
144
	 * @throws Exception
145
	 */
146 48
	public function sortTeams(?string $ordering = Constants::POINTS, array $filters = []) : array {
147 48
		if (is_null($ordering)) {
148 37
			$ordering = Constants::POINTS;
149
		}
150 48
		$teams = [];
151 48
		if ($this instanceof WithRounds) {
152 6
			$rounds = $this->getRounds();
153 6
			for ($i = count($rounds) - 1; $i >= 0; $i--) {
154 6
				foreach ($rounds[$i]->getTeams(true, $ordering) as $team) {
155 6
					if (!isset($teams[$team->getId()])) {
156 6
						$teams[$team->getId()] = $team;
157
					}
158
				}
159 6
				$this->teams = array_values($teams);
160
			}
161
		}
162 48
		elseif ($this instanceof WithGroups) {
163 9
			foreach ($this->getGroups() as $group) {
164 9
				$teams[] = $group->getTeams(true);
165
			}
166 9
			$this->teams = array_merge(...$teams);
167
		}
168
169 48
		if ($this instanceof Round) {
170 9
			$teams = Teams::sortRound($this->teams, $this, $ordering);
0 ignored issues
show
Bug introduced by
The property teams is declared protected in TournamentGenerator\Round and cannot be accessed from this context.
Loading history...
171
		}
172 48
		elseif ($this instanceof Group) {
173 48
			$teams = Teams::sortGroup($this->teams, $this, $ordering);
0 ignored issues
show
Bug introduced by
The property teams is declared protected in TournamentGenerator\Group and cannot be accessed from this context.
Loading history...
174
		}
175
		else {
176 6
			$teams = $this->teams;
177
		}
178 48
		$this->teams = $teams;
179
180
		// APPLY FILTERS
181 48
		if (count($filters) > 0) {
182 7
			$this->filterTeams($teams, $filters);
183
		}
184
185 48
		return $teams;
186
	}
187
188
	/**
189
	 * Filter teams using the specified filters
190
	 *
191
	 * @param array                       $teams   Teams to filter through
192
	 * @param TeamFilter[]|TeamFilter[][] $filters Filters to use
193
	 *
194
	 * @return array
195
	 * @throws Exception
196
	 */
197 29
	public function filterTeams(array &$teams, array $filters) : array {
198
		// APPLY FILTERS
199 29
		if ($this instanceof WithGroups) {
200 5
			$filter = new Filter($filters, $this->getGroups());
201 5
			$filter->filter($teams);
202
		}
203 27
		else if ($this instanceof Group) {
204 27
			$filter = new Filter($filters, [$this]);
205 27
			$filter->filter($teams);
206
		}
207 23
		return $teams;
208
	}
209
210
	/**
211
	 * Add one or more teams into the object.
212
	 *
213
	 * @param Team ...$teams Team objects
214
	 *
215
	 * @return WithTeamsInterface
216
	 */
217 34
	public function addTeam(Team ...$teams) : WithTeamsInterface {
218 34
		foreach ($teams as $team) {
219 34
			$this->teams[] = $team;
220
		}
221 34
		return $this;
1 ignored issue
show
Bug Best Practice introduced by
The expression return $this returns the type TournamentGenerator\Traits\WithTeams which is incompatible with the type-hinted return TournamentGenerator\Interfaces\WithTeams.
Loading history...
222
	}
223
224 1
	public function getRealTeamCount() : int {
225 1
		return count($this->teams);
226
	}
227
}