This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | declare(strict_types=1); |
||
3 | /** |
||
4 | * Created by PhpStorm. |
||
5 | * User: benedikt |
||
6 | * Date: 3/7/17 |
||
7 | * Time: 4:31 PM |
||
8 | */ |
||
9 | |||
10 | namespace Tfboe\FmLib\Service\RankingSystem; |
||
11 | |||
12 | use Doctrine\Common\Collections\Collection; |
||
13 | use Tfboe\FmLib\Entity\GameInterface; |
||
14 | use Tfboe\FmLib\Entity\Helpers\Result; |
||
15 | use Tfboe\FmLib\Entity\Helpers\TournamentHierarchyEntity; |
||
16 | use Tfboe\FmLib\Entity\PlayerInterface; |
||
17 | use Tfboe\FmLib\Entity\RankingSystemChangeInterface; |
||
18 | use Tfboe\FmLib\Entity\RankingSystemInterface; |
||
0 ignored issues
–
show
|
|||
19 | use Tfboe\FmLib\Entity\RankingSystemListEntryInterface; |
||
20 | use Tfboe\FmLib\Entity\RankingSystemListInterface; |
||
21 | |||
22 | /** |
||
23 | * Class EloRanking |
||
24 | * @package Tfboe\FmLib\Service\TournamentRanking |
||
25 | */ |
||
26 | class EloRanking extends GameRankingSystemService implements EloRankingInterface |
||
27 | { |
||
28 | //<editor-fold desc="Fields"> |
||
29 | const EXP_DIFF = 400; |
||
30 | const K = 20; |
||
31 | const MAX_DIFF_TO_OPPONENT_FOR_PROVISORY = 400; |
||
32 | const NO_NEG = true; |
||
33 | const NUM_PROVISORY_GAMES = 20; |
||
34 | const PROVISORY_PARTNER_FACTOR = 0.5; |
||
35 | const START = 1200.0; |
||
36 | //</editor-fold desc="Fields"> |
||
37 | |||
38 | //<editor-fold desc="Protected Methods"> |
||
39 | /** |
||
40 | * Gets additional fields for this ranking type |
||
41 | * @return string[] list of additional fields |
||
42 | */ |
||
43 | protected function getAdditionalFields(): array |
||
44 | { |
||
45 | return ['playedGames' => 0, 'ratedGames' => 0, 'provisoryRanking' => self::START]; |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * @inheritDoc |
||
50 | */ |
||
51 | protected function getChanges(TournamentHierarchyEntity $entity, RankingSystemListInterface $list): array |
||
52 | { |
||
53 | /** @var GameInterface $game */ |
||
54 | $game = $entity; |
||
55 | $changes = []; |
||
56 | |||
57 | if (!$game->isPlayed() || $game->getResult() === Result::NOT_YET_FINISHED || |
||
58 | $game->getResult() === Result::NULLED) { |
||
59 | //game gets not elo rated |
||
60 | $this->addNotRatedChanges($changes, $game->getPlayersA(), $entity, $list->getRankingSystem()); |
||
0 ignored issues
–
show
It seems like
$game->getPlayersA() targeting Tfboe\FmLib\Entity\GameInterface::getPlayersA() can also be of type array<integer,object<Tfb...ntity\PlayerInterface>> ; however, Tfboe\FmLib\Service\Rank...g::addNotRatedChanges() does only seem to accept object<Doctrine\Common\Collections\Collection> , maybe add an additional type check?
This check looks at variables that are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
61 | $this->addNotRatedChanges($changes, $game->getPlayersB(), $entity, $list->getRankingSystem()); |
||
0 ignored issues
–
show
It seems like
$game->getPlayersB() targeting Tfboe\FmLib\Entity\GameInterface::getPlayersB() can also be of type array<integer,object<Tfb...ntity\PlayerInterface>> ; however, Tfboe\FmLib\Service\Rank...g::addNotRatedChanges() does only seem to accept object<Doctrine\Common\Collections\Collection> , maybe add an additional type check?
This check looks at variables that are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
62 | return $changes; |
||
63 | } |
||
64 | |||
65 | $entriesA = $this->getEntriesOfPlayers($game->getPlayersA(), $list); |
||
0 ignored issues
–
show
It seems like
$game->getPlayersA() targeting Tfboe\FmLib\Entity\GameInterface::getPlayersA() can also be of type array<integer,object<Tfb...ntity\PlayerInterface>> ; however, Tfboe\FmLib\Service\Rank...::getEntriesOfPlayers() does only seem to accept object<Doctrine\Common\Collections\Collection> , maybe add an additional type check?
This check looks at variables that are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
66 | $entriesB = $this->getEntriesOfPlayers($game->getPlayersB(), $list); |
||
0 ignored issues
–
show
It seems like
$game->getPlayersB() targeting Tfboe\FmLib\Entity\GameInterface::getPlayersB() can also be of type array<integer,object<Tfb...ntity\PlayerInterface>> ; however, Tfboe\FmLib\Service\Rank...::getEntriesOfPlayers() does only seem to accept object<Doctrine\Common\Collections\Collection> , maybe add an additional type check?
This check looks at variables that are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
67 | |||
68 | $isAProvisory = $this->hasProvisoryEntry($entriesA); |
||
69 | $isBProvisory = $this->hasProvisoryEntry($entriesB); |
||
70 | |||
71 | $averageA = $this->getEloAverage($entriesA); |
||
72 | $averageB = $this->getEloAverage($entriesB); |
||
73 | |||
74 | $expectationA = 1 / (1 + 10 ** (($averageB - $averageA) / self::EXP_DIFF)); |
||
75 | $expectationB = 1 - $expectationA; |
||
76 | |||
77 | $resultA = 0.0; |
||
78 | |||
79 | switch ($game->getResult()) { |
||
80 | case Result::TEAM_A_WINS: |
||
81 | $resultA = 1.0; |
||
82 | break; |
||
83 | case Result::DRAW: |
||
84 | $resultA = 0.5; |
||
85 | break; |
||
86 | } |
||
87 | $resultB = 1 - $resultA; |
||
88 | |||
89 | $expectationDiffA = $resultA - $expectationA; |
||
90 | $expectationDiffB = $resultB - $expectationB; |
||
91 | |||
92 | |||
93 | $this->computeChanges($changes, $entriesA, $resultA, $expectationDiffA, $game, $averageA, $averageB, |
||
94 | $isAProvisory, $isBProvisory); |
||
95 | $this->computeChanges($changes, $entriesB, $resultB, $expectationDiffB, $game, $averageB, $averageA, |
||
96 | $isBProvisory, $isAProvisory); |
||
97 | return $changes; |
||
98 | } |
||
99 | |||
100 | /** @noinspection PhpMissingParentCallCommonInspection */ |
||
101 | /** |
||
102 | * @inheritDoc |
||
103 | */ |
||
104 | protected function startPoints(): float |
||
105 | { |
||
106 | return 0.0; |
||
107 | } |
||
108 | //</editor-fold desc="Protected Methods"> |
||
109 | |||
110 | |||
111 | //<editor-fold desc="Private Methods"> |
||
112 | /** |
||
113 | * @param RankingSystemChangeInterface[] $changes |
||
114 | * @param Collection|PlayerInterface[] $players |
||
115 | * @param TournamentHierarchyEntity $entity |
||
116 | * @param RankingSystemInterface $ranking |
||
117 | */ |
||
118 | private function addNotRatedChanges(array &$changes, Collection $players, TournamentHierarchyEntity $entity, |
||
119 | RankingSystemInterface $ranking) |
||
120 | { |
||
121 | foreach ($players as $player) { |
||
122 | $change = $this->getOrCreateChange($entity, $ranking, $player); |
||
123 | $change->setTeamElo(0.0); |
||
0 ignored issues
–
show
The method
setTeamElo() does not seem to exist on object<Tfboe\FmLib\Entit...gSystemChangeInterface> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
124 | $change->setOpponentElo(0.0); |
||
0 ignored issues
–
show
The method
setOpponentElo() does not seem to exist on object<Tfboe\FmLib\Entit...gSystemChangeInterface> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
125 | $change->setPointsChange(0.0); |
||
126 | $change->setPlayedGames(0); |
||
127 | $change->setRatedGames(0); |
||
128 | $change->setProvisoryRanking(0.0); |
||
129 | $changes[] = $change; |
||
130 | } |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * @inheritDoc |
||
135 | */ |
||
136 | protected function getAdditionalChangeFields(): array |
||
137 | { |
||
138 | return ['teamElo', 'opponentElo']; |
||
139 | } |
||
140 | |||
141 | /** @noinspection PhpTooManyParametersInspection */ //TODO refactor this method |
||
142 | /** |
||
143 | * @param array $changes |
||
144 | * @param RankingSystemListEntryInterface[] $entries |
||
145 | * @param float $result |
||
146 | * @param float $expectationDiff |
||
147 | * @param GameInterface $game |
||
148 | * @param float $teamAverage |
||
149 | * @param float $opponentAverage |
||
150 | * @param bool $teamHasProvisory |
||
151 | * @param bool $opponentHasProvisory |
||
152 | */ |
||
153 | private function computeChanges(array &$changes, array $entries, float $result, float $expectationDiff, |
||
154 | GameInterface $game, float $teamAverage, float $opponentAverage, |
||
155 | bool $teamHasProvisory, bool $opponentHasProvisory) |
||
156 | { |
||
157 | foreach ($entries as $entry) { |
||
158 | $change = $this->getOrCreateChange($game, $entry->getRankingSystemList()->getRankingSystem(), |
||
159 | $entry->getPlayer()); |
||
160 | $change->setPlayedGames(1); |
||
161 | $change->setTeamElo($teamHasProvisory ? 0.0 : $teamAverage); |
||
0 ignored issues
–
show
The method
setTeamElo() does not seem to exist on object<Tfboe\FmLib\Entit...gSystemChangeInterface> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
162 | $change->setOpponentElo($opponentHasProvisory ? 0.0 : $opponentAverage); |
||
0 ignored issues
–
show
The method
setOpponentElo() does not seem to exist on object<Tfboe\FmLib\Entit...gSystemChangeInterface> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||
163 | $factor = 2 * $result - 1; |
||
164 | if ($entry->getPlayedGames() < self::NUM_PROVISORY_GAMES) { |
||
165 | //provisory entry => recalculate |
||
166 | if (count($entries) > 1) { |
||
167 | $teamMatesAverage = ($teamAverage * count($entries) - $entry->getProvisoryRanking()) / |
||
168 | (count($entries) - 1); |
||
169 | if ($teamMatesAverage > $opponentAverage + self::MAX_DIFF_TO_OPPONENT_FOR_PROVISORY) { |
||
170 | $teamMatesAverage = $opponentAverage + self::MAX_DIFF_TO_OPPONENT_FOR_PROVISORY; |
||
171 | } |
||
172 | if ($teamMatesAverage < $opponentAverage - self::MAX_DIFF_TO_OPPONENT_FOR_PROVISORY) { |
||
173 | $teamMatesAverage = $opponentAverage - self::MAX_DIFF_TO_OPPONENT_FOR_PROVISORY; |
||
174 | } |
||
175 | $performance = $opponentAverage * (1 + self::PROVISORY_PARTNER_FACTOR) - |
||
176 | $teamMatesAverage * self::PROVISORY_PARTNER_FACTOR; |
||
177 | } else { |
||
178 | $performance = $opponentAverage; |
||
179 | } |
||
180 | if ($performance < self::START) { |
||
181 | $performance = self::START; |
||
182 | } |
||
183 | $performance += self::EXP_DIFF * $factor; |
||
184 | //old average performance = $entry->getProvisoryRating() |
||
185 | //=> new average performance = ($entry->getProvisoryRating() * $entry->getRatedGames() + $performance) / |
||
186 | // ($entry->getRatedGames() + 1) |
||
187 | //=> performance change = ($entry->getProvisoryRating() * $entry->getRatedGames() + $performance) / |
||
188 | // ($entry->getRatedGames() + 1) - $entry->getProvisoryRating() |
||
189 | // = ($performance - $entry->getProvisoryRating()) / ($entry->getRatedGames() + 1) |
||
190 | $change->setProvisoryRanking(($performance - $entry->getProvisoryRanking()) / ($entry->getRatedGames() + 1)); |
||
191 | $change->setPointsChange(0.0); |
||
192 | $change->setRatedGames(1); |
||
193 | if ($entry->getPlayedGames() == self::NUM_PROVISORY_GAMES - 1) { |
||
194 | $change->setPointsChange(max(self::START, $entry->getProvisoryRanking() + $change->getProvisoryRanking()) |
||
195 | - $entry->getPoints()); |
||
196 | } |
||
197 | } else if (!$teamHasProvisory && !$opponentHasProvisory) { |
||
198 | //real elo ranking |
||
199 | $change->setProvisoryRanking(0.0); |
||
200 | $change->setPointsChange(max(self::K * $expectationDiff, self::START - $entry->getPoints())); |
||
201 | $change->setRatedGames(1); |
||
202 | |||
203 | } else { |
||
204 | //does not get rated |
||
205 | $change->setProvisoryRanking(0.0); |
||
206 | $change->setPointsChange(0.0); |
||
207 | $change->setRatedGames(0); |
||
208 | } |
||
209 | $changes[] = $change; |
||
210 | } |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * Computes the average rating of the given entries |
||
215 | * @param RankingSystemListEntryInterface[] $entries must be nonempty |
||
216 | * @return float |
||
217 | */ |
||
218 | private function getEloAverage(array $entries): float |
||
219 | { |
||
220 | $sum = 0; |
||
221 | foreach ($entries as $entry) { |
||
222 | $sum += $entry->getRatedGames() < self::NUM_PROVISORY_GAMES ? $entry->getProvisoryRanking() : $entry->getPoints(); |
||
223 | } |
||
224 | return $sum / count($entries); |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * Checks if the given list of entries has at least one provisory entry |
||
229 | * @param RankingSystemListEntryInterface[] $entries |
||
230 | * @return bool |
||
231 | */ |
||
232 | private function hasProvisoryEntry(array $entries): bool |
||
233 | { |
||
234 | foreach ($entries as $entry) { |
||
235 | if ($entry->getPlayedGames() < self::NUM_PROVISORY_GAMES) { |
||
236 | return true; |
||
237 | } |
||
238 | } |
||
239 | return false; |
||
240 | } |
||
241 | //</editor-fold desc="Private Methods"> |
||
242 | } |
Let’s assume that you have a directory layout like this:
and let’s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/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 beforeOtherDir/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: