Completed
Push — master ( 4554c8...3722a4 )
by Dan
02:38
created

Round::playerChecks()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Cysha\Casino\Holdem\Game;
4
5
use Cysha\Casino\Cards\Contracts\CardResults;
6
use Cysha\Casino\Game\Chips;
7
use Cysha\Casino\Game\ChipStackCollection;
8
use Cysha\Casino\Game\Contracts\Dealer as DealerContract;
9
use Cysha\Casino\Game\Contracts\GameParameters;
10
use Cysha\Casino\Game\Contracts\Player as PlayerContract;
11
use Cysha\Casino\Game\PlayerCollection;
12
use Cysha\Casino\Holdem\Exceptions\RoundException;
13
use Cysha\Casino\Holdem\Game\LeftToAct;
14
use Ramsey\Uuid\Uuid;
15
16
class Round
17
{
18
    /**
19
     * @var Uuid
20
     */
21
    private $id;
22
23
    /**
24
     * @var Table
25
     */
26
    private $table;
27
28
    /**
29
     * @var ChipStackCollection
30
     */
31
    private $betStacks;
32
33
    /**
34
     * @var PlayerCollection
35
     */
36
    private $foldedPlayers;
37
38
    /**
39
     * @var ChipPotCollection
40
     */
41
    private $chipPots;
42
43
    /**
44
     * @var ChipPot
45
     */
46
    private $currentPot;
47
48
    /**
49
     * @var ActionCollection
50
     */
51
    private $actions;
52
53
    /**
54
     * @var PlayerCollection
55
     */
56
    private $leftToAct;
57
58
    /**
59
     * @var GameParameters
60
     */
61
    private $gameRules;
62
63
    /**
64
     * Round constructor.
65
     *
66
     * @param Uuid $id
67
     * @param Table $table
68
     * @param GameParameters $gameRules
69
     */
70
    private function __construct(Uuid $id, Table $table, GameParameters $gameRules)
71
    {
72
        $this->id = $id;
73
        $this->table = $table;
74
        $this->chipPots = ChipPotCollection::make();
75
        $this->currentPot = ChipPot::create();
76
        $this->betStacks = ChipStackCollection::make();
77 50
        $this->foldedPlayers = PlayerCollection::make();
78
        $this->actions = ActionCollection::make();
79 50
        $this->leftToAct = LeftToAct::make();
80 50
        $this->gameRules = $gameRules;
81 50
82 50
        // shuffle the deck ready
83 50
        $this->dealer()->shuffleDeck();
84 50
85 50
        // add the default pot to the chipPots
86 50
        $this->chipPots->push($this->currentPot);
87 50
88 50
        // init the betStacks and actions for each player
89
        $this->resetBetStacks();
90
        $this->setupLeftToAct();
91 50
    }
92
93
    /**
94 50
     * Start a Round of poker.
95
     *
96
     * @param Uuid $id
97 50
     * @param Table $table
98 50
     * @param GameParameters $gameRules
99 50
     *
100
     * @return Round
101
     */
102
    public static function start(Uuid $id, Table $table, GameParameters $gameRules): Round
103
    {
104
        return new static($id, $table, $gameRules);
105
    }
106
107
    /**
108 50
     * Run the cleanup procedure for an end of Round.
109
     */
110 50
    public function end()
111
    {
112
        $this->dealer()->checkCommunityCards();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method checkCommunityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
113
114
        $this->collectChipTotal();
115
116 11
        $this->distributeWinnings();
117
118
        $this->table()->moveButton();
119
    }
120 11
121
    /**
122 11
     * @return Uuid
123
     */
124 11
    public function id(): Uuid
125 11
    {
126
        return $this->id;
127
    }
128
129
    /**
130 50
     * @return DealerContract
131
     */
132 50
    public function dealer(): DealerContract
133
    {
134
        return $this->table->dealer();
135
    }
136
137
    /**
138 3
     * @return PlayerCollection
139
     */
140 3
    public function players(): PlayerCollection
141
    {
142
        return $this->table->players();
143
    }
144
145
    /**
146 12
     * @return PlayerCollection
147
     */
148 12
    public function playersStillIn(): PlayerCollection
149
    {
150
        return $this->table->playersSatDown()->diff($this->foldedPlayers());
151
    }
152
153
    /**
154 19
     * @return PlayerCollection
155
     */
156 19
    public function foldedPlayers(): PlayerCollection
157
    {
158
        return $this->foldedPlayers;
159
    }
160
161
    /**
162 1
     * @return ActionCollection
163
     */
164 1
    public function actions(): ActionCollection
165
    {
166
        return $this->actions;
167
    }
168
169
    /**
170 35
     * @return LeftToAct
171
     */
172 35
    public function leftToAct(): LeftToAct
173
    {
174
        return $this->leftToAct;
175
    }
176
177
    /**
178 36
     * @return Table
179
     */
180 36
    public function table(): Table
181
    {
182
        return $this->table;
183
    }
184
185
    /**
186 50
     * @return ChipStackCollection
187
     */
188 50
    public function betStacks(): ChipStackCollection
189
    {
190
        return $this->betStacks;
191
    }
192
193
    /**
194 13
     * @return GameParameters
195
     */
196 13
    public function gameRules(): GameParameters
197
    {
198
        return $this->gameRules;
199
    }
200
201
    /**
202 29
     * @return int
203
     */
204 29
    public function betStacksTotal(): int
205
    {
206
        return $this->betStacks()->total()->amount();
207
    }
208
209
    public function dealHands()
210 22
    {
211
        $players = $this->table()
212 22
            ->playersSatDown()
213 22
            ->resetPlayerListFromSeat($this->table()->button() + 1);
214
215
        $this->dealer()->dealHands($players);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method dealHands() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
216
    }
217
218 2
    /**
219
     * Runs over each chipPot and assigns the chips to the winning player.
220 2
     */
221
    private function distributeWinnings()
222
    {
223
        $this->chipPots()
224
            ->reverse()
225
            ->each(function (ChipPot $chipPot) {
226 11
                // if only 1 player participated to pot, he wins it no arguments
227
                if ($chipPot->players()->count() === 1) {
228 11
                    $potTotal = $chipPot->chips()->total();
229 11
230
                    $chipPot->players()->first()->chipStack()->add($potTotal);
231
232 11
                    $this->chipPots()->remove($chipPot);
233 6
234
                    return;
235 6
                }
236
237 6
                $activePlayers = $chipPot->players()->diff($this->foldedPlayers());
238
239 6
                $playerHands = $this->dealer()->hands()->findByPlayers($activePlayers);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method hands() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
240
                $evaluate = $this->dealer()->evaluateHands($this->dealer()->communityCards(), $playerHands);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method communityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
241
242 11
                // if just 1, the player with that hand wins
243
                if ($evaluate->count() === 1) {
244 11
                    $player = $evaluate->first()->hand()->player();
245 11
                    $potTotal = $chipPot->chips()->total();
246
247
                    $player->chipStack()->add($potTotal);
248 11
249 11
                    $this->chipPots()->remove($chipPot);
250 11
                } else {
251
                    // if > 1 hand is evaluated as highest, split the pot evenly between the players
252 11
253
                    $potTotal = $chipPot->chips()->total();
254 11
255
                    // split the pot between the number of players
256
                    $splitTotal = Chips::fromAmount(($potTotal->amount() / $evaluate->count()));
257
                    $evaluate->each(function (CardResults $result) use ($splitTotal) {
258
                        $result->hand()->player()->chipStack()->add($splitTotal);
259 1
                    });
260
261
                    $this->chipPots()->remove($chipPot);
262 1
                }
263
            })
264 1
        ;
265 1
    }
266
267 1
    /**
268
     * @param Player $actualPlayer
269 11
     *
270
     * @return bool
271 11
     */
272
    public function playerIsStillIn(PlayerContract $actualPlayer)
273
    {
274
        $playerCount = $this->playersStillIn()->filter->equals($actualPlayer)->count();
275
276
        return $playerCount === 1;
277
    }
278 1
279
    /**
280 1
     * @return PlayerContract
281
     */
282 1
    public function playerWithButton(): PlayerContract
283
    {
284
        return $this->table()->locatePlayerWithButton();
285
    }
286
287
    /**
288 7
     * @return PlayerContract
289
     */
290 7
    public function playerWithSmallBlind(): PlayerContract
291
    {
292
        if ($this->table()->playersSatDown()->count() === 2) {
293
            return $this->table()->playersSatDown()->get(0);
294
        }
295
296 21
        return $this->table()->playersSatDown()->get($this->table()->button() + 1);
297
    }
298 21
299 5
    /**
300
     * @return PlayerContract
301
     */
302 16
    public function playerWithBigBlind(): PlayerContract
303
    {
304
        if ($this->table()->playersSatDown()->count() === 2) {
305
            return $this->table()->playersSatDown()->get(1);
306
        }
307
308 4
        return $this->table()->playersSatDown()->get($this->table()->button() + 2);
309
    }
310 4
311 1
    /**
312
     * @param PlayerContract $player
313
     */
314 3
    public function postSmallBlind(PlayerContract $player)
315
    {
316
        // Take chips from player
317
        $chips = $this->smallBlind();
318
319
        $this->postBlind($player, $chips);
320 34
321
        $this->actions()->push(new Action($player, Action::SMALL_BLIND, ['chips' => $this->smallBlind()]));
0 ignored issues
show
Documentation introduced by
$player is of type object<Cysha\Casino\Game\Contracts\Player>, but the function expects a object<Cysha\Casino\Game\Contracts\Name>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
322
        $this->leftToAct = $this->leftToAct()->playerHasActioned($player, LeftToAct::SMALL_BLIND);
323 34
    }
324
325 34
    /**
326
     * @param PlayerContract $player
327 34
     */
328 34
    public function postBigBlind(PlayerContract $player)
329 34
    {
330
        // Take chips from player
331
        $chips = $this->bigBlind();
332
333
        $this->postBlind($player, $chips);
334 34
335
        $this->actions()->push(new Action($player, Action::BIG_BLIND, ['chips' => $this->bigBlind()]));
0 ignored issues
show
Documentation introduced by
$player is of type object<Cysha\Casino\Game\Contracts\Player>, but the function expects a object<Cysha\Casino\Game\Contracts\Name>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
336
        $this->leftToAct = $this->leftToAct()->playerHasActioned($player, LeftToAct::BIG_BLIND);
337 34
    }
338
339 34
    /**
340
     * @return Chips
341 34
     */
342 34
    private function smallBlind(): Chips
343 34
    {
344
        return Chips::fromAmount($this->gameRules()->smallBlind()->amount());
345
    }
346
347
    /**
348 34
     * @return Chips
349
     */
350 34
    private function bigBlind(): Chips
351
    {
352
        return Chips::fromAmount($this->gameRules()->bigBlind()->amount());
353
    }
354
355
    /**
356 34
     * @return ChipPot
357
     */
358 34
    public function currentPot(): ChipPot
359
    {
360
        return $this->currentPot;
361
    }
362
363
    /**
364 14
     * @return ChipPotCollection
365
     */
366 14
    public function chipPots(): ChipPotCollection
367
    {
368
        return $this->chipPots;
369
    }
370
371
    /**
372 20
     * @param PlayerContract $player
373
     *
374 20
     * @return Chips
375
     */
376
    public function playerBetStack(PlayerContract $player): Chips
377
    {
378
        return $this->betStacks->findByPlayer($player);
379
    }
380
381
    /**
382 31
     * @param PlayerContract $player
383
     * @param Chips          $chips
384 31
     */
385
    private function postBlind(PlayerContract $player, $chips)
386
    {
387
        $player->chipStack()->subtract($chips);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Player as the method chipStack() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Player.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
388
389
        // Add chips to player's table stack
390
        $this->betStacks->put($player->name(), $chips);
391 34
    }
392
393 34
    /**
394
     * @return PlayerContract|false
395
     */
396 34
    public function whosTurnIsIt()
397 34
    {
398
        $nextPlayer = $this->leftToAct()->getNextPlayer();
399
        if ($nextPlayer === null) {
400
            return false;
401
        }
402
403
        return $this->players()
404 2
            ->filter(function (PlayerContract $player) use ($nextPlayer) {
405
                return $player->name() === $nextPlayer['player'];
406 2
            })
407
            ->first()
408 2
        ;
409 1
    }
410
411
    /**
412 1
     * @return ChipPotCollection
413
     */
414
    public function collectChipTotal(): ChipPotCollection
415
    {
416
        $allInActionsThisRound = $this->leftToAct()->filter(function (array $value) {
417
            return $value['action'] === LeftToAct::ALL_IN;
418 36
        });
419
420 36
        $orderedBetStacks = $this->betStacks()
421
            ->reject(function (Chips $chips, $playerName) {
422
                $foldedPlayer = $this->foldedPlayers()->findByName($playerName);
423 36
                if ($foldedPlayer) {
424 36
                    return true;
425
                }
426
427
                return false;
428
            })
429
            ->sortByChipAmount();
430 20
431
        if ($allInActionsThisRound->count() > 1 && $orderedBetStacks->unique()->count() > 1) {
432
            $orderedBetStacks->each(function (Chips $playerChips, $playerName) use ($orderedBetStacks) {
433 20
                $remainingStacks = $orderedBetStacks->filter(function (Chips $chips) {
434 20
                    return $chips->amount() !== 0;
435
                });
436 20
437 6
                $this->currentPot = ChipPot::create();
438
                $this->chipPots()->push($this->currentPot);
439 6
440 6
                $player = $this->players()->findByName($playerName);
441 5
                $allInAmount = Chips::fromAmount($orderedBetStacks->findByPlayer($player)->amount());
442
443
                $remainingStacks->each(function (Chips $chips, $playerName) use ($allInAmount, $orderedBetStacks) {
444 6
                    $player = $this->players()->findByName($playerName);
445 6
446 6
                    $stackChips = Chips::fromAmount($allInAmount->amount());
447
448
                    if (($chips->amount() - $stackChips->amount()) <= 0) {
449
                        $stackChips = Chips::fromAmount($chips->amount());
450 6
                    }
451 6
452
                    $chips->subtract($stackChips);
453 6
                    $this->currentPot->addChips($stackChips, $player);
0 ignored issues
show
Bug introduced by
It seems like $player defined by $this->players()->findByName($playerName) on line 444 can be null; however, Cysha\Casino\Holdem\Game\ChipPot::addChips() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
454 6
                    $orderedBetStacks->put($playerName, Chips::fromAmount($chips->amount()));
455
                });
456 6
            });
457 6
458
            // sort the pots so we get rid of any empty ones
459
            $this->chipPots = $this->chipPots
460 6
                ->filter(function (ChipPot $chipPot) {
461
                    return $chipPot->total()->amount() !== 0;
462 6
                })
463
                ->values();
464 6
465 6
            // grab anyone that folded
466
            $this->betStacks()
467
                ->filter(function (Chips $chips, $playerName) {
468 6
                    $foldedPlayer = $this->foldedPlayers()->findByName($playerName);
469 6
                    if ($foldedPlayer && $chips->amount() > 0) {
470 6
                        return true;
471 6
                    }
472 6
473
                    return false;
474
                })
475 6
                ->each(function (Chips $chips, $playerName) use ($orderedBetStacks) {
476
                    $player = $this->players()->findByName($playerName);
477 6
478 6
                    $stackChips = Chips::fromAmount($chips->amount());
479 6
480
                    $chips->subtract($stackChips);
481
                    $this->chipPots->get(0)->addChips($stackChips, $player);
482 6
                    $orderedBetStacks->put($playerName, Chips::fromAmount($chips->amount()));
483
                });
484 6
        } else {
485 6
            $this->betStacks()->each(function (Chips $chips, $playerName) {
486 5
                $this->currentPot()->addChips($chips, $this->players()->findByName($playerName));
0 ignored issues
show
Bug introduced by
It seems like $this->players()->findByName($playerName) can be null; however, addChips() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
487
            });
488
        }
489 6
490 6
        $this->resetBetStacks();
491
492
        return $this->chipPots();
493 5
    }
494
495 5
    /**
496
     * Deal the Flop.
497 5
     */
498 5
    public function dealFlop()
499 5
    {
500 6
        if ($this->dealer()->communityCards()->count() !== 0) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method communityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
501
            throw RoundException::flopHasBeenDealt();
502
        }
503 14
        if ($player = $this->whosTurnIsIt()) {
504 14
            throw RoundException::playerStillNeedsToAct($player);
505
        }
506
507 20
        $this->collectChipTotal();
508
509 20
        $seat = $this->table()->findSeat($this->playerWithSmallBlind());
510
        $this->resetPlayerList($seat);
511
512
        $this->dealer()->dealCommunityCards(3);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method dealCommunityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
513
        $this->actions()->push(new Action($this->dealer(), Action::DEALT_FLOP, [
0 ignored issues
show
Documentation introduced by
$this->dealer() is of type object<Cysha\Casino\Game\Contracts\Dealer>, but the function expects a object<Cysha\Casino\Game\Contracts\Name>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
514
            'communityCards' => $this->dealer()->communityCards()->only(range(0, 2)),
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method communityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
515 17
        ]));
516
    }
517 17
518 1
    /**
519
     * Deal the turn card.
520 17
     */
521 1
    public function dealTurn()
522
    {
523
        if ($this->dealer()->communityCards()->count() !== 3) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method communityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
524 16
            throw RoundException::turnHasBeenDealt();
525
        }
526 16
        if (($player = $this->whosTurnIsIt()) !== false) {
527 16
            throw RoundException::playerStillNeedsToAct($player);
528 16
        }
529 16
530 16
        $this->collectChipTotal();
531
532
        $seat = $this->table()->findSeat($this->playerWithSmallBlind());
533 16
        $this->resetPlayerList($seat);
534
535
        $this->dealer()->dealCommunityCards(1);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method dealCommunityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
536 16
        $this->actions()->push(new Action($this->dealer(), Action::DEALT_TURN, [
0 ignored issues
show
Documentation introduced by
$this->dealer() is of type object<Cysha\Casino\Game\Contracts\Dealer>, but the function expects a object<Cysha\Casino\Game\Contracts\Name>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
537 16
            'communityCards' => $this->dealer()->communityCards()->only(3),
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method communityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
538 16
        ]));
539 16
    }
540
541
    /**
542
     * Deal the river card.
543
     */
544 14
    public function dealRiver()
545
    {
546 14
        if ($this->dealer()->communityCards()->count() !== 4) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method communityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
547 2
            throw RoundException::riverHasBeenDealt();
548
        }
549 13
        if (($player = $this->whosTurnIsIt()) !== false) {
550 1
            throw RoundException::playerStillNeedsToAct($player);
551
        }
552
553 12
        $this->collectChipTotal();
554 12
555
        $seat = $this->table()->findSeat($this->playerWithSmallBlind());
556
        $this->resetPlayerList($seat);
557
558
        $this->dealer()->dealCommunityCards(1);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method dealCommunityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
559 11
        $this->actions()->push(new Action($this->dealer(), Action::DEALT_RIVER, [
0 ignored issues
show
Documentation introduced by
$this->dealer() is of type object<Cysha\Casino\Game\Contracts\Dealer>, but the function expects a object<Cysha\Casino\Game\Contracts\Name>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
560
            'communityCards' => $this->dealer()->communityCards()->only(4),
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Dealer as the method communityCards() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Dealer.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
561 11
        ]));
562 2
    }
563
564 10
    /**
565 1
     * @throws RoundException
566
     */
567
    public function checkPlayerTryingToAct(PlayerContract $player)
568 9
    {
569 9
        $actualPlayer = $this->whosTurnIsIt();
570
        if ($actualPlayer === false) {
571
            throw RoundException::noPlayerActionsNeeded();
572
        }
573
        if ($player !== $actualPlayer) {
574 12
            throw RoundException::playerTryingToActOutOfTurn($player, $actualPlayer);
575
        }
576 12
    }
577
578 12
    /**
579 12
     * @param PlayerContract $player
580 12
     *
581 12
     * @throws RoundException
582 12
     */
583
    public function playerCalls(PlayerContract $player)
584
    {
585 12
        $this->checkPlayerTryingToAct($player);
586
587
        $highestChipBet = $this->highestBet();
588 12
589 12
        // current highest bet - currentPlayersChipStack
590
        $amountLeftToBet = Chips::fromAmount($highestChipBet->amount() - $this->playerBetStack($player)->amount());
591
592
        $chipStackLeft = Chips::fromAmount($player->chipStack()->amount() - $amountLeftToBet->amount());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Player as the method chipStack() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Player.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
593
594 33
        if ($chipStackLeft->amount() <= 0) {
595
            $amountLeftToBet = Chips::fromAmount($player->chipStack()->amount());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Player as the method chipStack() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Player.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
596 33
            $chipStackLeft = Chips::zero();
597 33
        }
598 1
599
        $action = $chipStackLeft->amount() === 0 ? Action::ALLIN : Action::CALL;
600 33
        $this->actions->push(new Action($player, $action, ['chips' => $amountLeftToBet]));
0 ignored issues
show
Documentation introduced by
$player is of type object<Cysha\Casino\Game\Contracts\Player>, but the function expects a object<Cysha\Casino\Game\Contracts\Name>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
601 2
602
        $this->placeChipBet($player, $amountLeftToBet);
603 31
604
        $action = $chipStackLeft->amount() === 0 ? LeftToAct::ALL_IN : LeftToAct::ACTIONED;
605
        $this->leftToAct = $this->leftToAct()->playerHasActioned($player, $action);
606
    }
607
608
    /**
609
     * @param PlayerContract $player
610 22
     * @param Chips          $chips
611
     *
612 22
     * @throws RoundException
613
     */
614 22
    public function playerRaises(PlayerContract $player, Chips $chips)
615
    {
616
        $this->checkPlayerTryingToAct($player);
617 22
618
        $highestChipBet = $this->highestBet();
619 22
        if ($chips->amount() < $highestChipBet->amount()) {
620
            throw RoundException::raiseNotHighEnough($chips, $highestChipBet);
621 22
        }
622 22
623 22
        $chipStackLeft = Chips::fromAmount($player->chipStack()->amount() - $chips->amount());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Player as the method chipStack() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Player.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
624
625
        $action = $chipStackLeft->amount() === 0 ? Action::ALLIN : Action::RAISE;
626
        $this->actions->push(new Action($player, $action, ['chips' => $chips]));
0 ignored issues
show
Documentation introduced by
$player is of type object<Cysha\Casino\Game\Contracts\Player>, but the function expects a object<Cysha\Casino\Game\Contracts\Name>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
627
628
        $this->placeChipBet($player, $chips);
629
630
        $action = $chipStackLeft->amount() === 0 ? LeftToAct::ALL_IN : LeftToAct::AGGRESSIVELY_ACTIONED;
631 4
        $this->leftToAct = $this->leftToAct()->playerHasActioned($player, $action);
632
    }
633 4
634
    /**
635 4
     * @param PlayerContract $player
636
     *
637 4
     * @throws RoundException
638 3
     */
639 3
    public function playerFoldsHand(PlayerContract $player)
640
    {
641
        $this->checkPlayerTryingToAct($player);
642
643
        $this->actions()->push(new Action($player, Action::FOLD));
0 ignored issues
show
Documentation introduced by
$player is of type object<Cysha\Casino\Game\Contracts\Player>, but the function expects a object<Cysha\Casino\Game\Contracts\Name>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
644
645
        $this->foldedPlayers->push($player);
646 14
        $this->leftToAct = $this->leftToAct()->removePlayer($player);
647
    }
648 14
649
    /**
650 13
     * @param PlayerContract $player
651
     *
652 13
     * @throws RoundException
653 13
     */
654 13
    public function playerPushesAllIn(PlayerContract $player)
655
    {
656
        $this->checkPlayerTryingToAct($player);
657
658
        // got the players chipStack
659
        $chips = $player->chipStack();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Player as the method chipStack() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Player.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
660
661 14
        // gotta create a new chip obj here cause of PHPs /awesome/ objRef ability :D
662
        $this->actions()->push(new Action($player, Action::ALLIN, ['chips' => Chips::fromAmount($chips->amount())]));
0 ignored issues
show
Documentation introduced by
$player is of type object<Cysha\Casino\Game\Contracts\Player>, but the function expects a object<Cysha\Casino\Game\Contracts\Name>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
663 14
664
        $this->placeChipBet($player, $chips);
665
        $this->leftToAct = $this->leftToAct()->playerHasActioned($player, LeftToAct::ALL_IN);
666 14
    }
667
668
    /**
669 14
     * @param PlayerContract $player
670
     *
671 14
     * @throws RoundException
672 14
     */
673 14
    public function playerChecks(PlayerContract $player)
674
    {
675
        $this->checkPlayerTryingToAct($player);
676
677
        if ($this->playerBetStack($player)->amount() !== $this->betStacks()->max()->amount()) {
678
            throw RoundException::cantCheckWithBetActive();
679
        }
680 16
681
        $this->actions()->push(new Action($player, Action::CHECK));
0 ignored issues
show
Documentation introduced by
$player is of type object<Cysha\Casino\Game\Contracts\Player>, but the function expects a object<Cysha\Casino\Game\Contracts\Name>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
682 16
        $this->leftToAct = $this->leftToAct()->playerHasActioned($player, LeftToAct::ACTIONED);
683
    }
684 15
685 15
    /**
686 15
     * @return Chips
687
     */
688
    private function highestBet(): Chips
689
    {
690
        return Chips::fromAmount($this->betStacks()->max(function (Chips $chips) {
691 22
            return $chips->amount();
692
        }) ?? 0);
693
    }
694 22
695 22
    /**
696
     * @param PlayerContract $player
697
     * @param Chips          $chips
698
     */
699
    private function placeChipBet(PlayerContract $player, Chips $chips)
700
    {
701
        if ($player->chipStack()->amount() < $chips->amount()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Player as the method chipStack() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Player.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
702 30
            throw RoundException::notEnoughChipsInChipStack($player, $chips);
703
        }
704 30
705 1
        // add the chips to the players tableStack first
706
        $this->playerBetStack($player)->add($chips);
707
708
        // then remove it off their actual stack
709 30
        $player->bet($chips);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cysha\Casino\Game\Contracts\Player as the method bet() does only exist in the following implementations of said interface: Cysha\Casino\Holdem\Game\Player.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
710
    }
711
712 30
    /**
713 30
     * Reset the chip stack for all players.
714
     */
715
    private function resetBetStacks()
716
    {
717
        $this->players()->each(function (PlayerContract $player) {
718
            $this->betStacks->put($player->name(), Chips::zero());
719
        });
720 50
    }
721 50
722 50
    /**
723 50
     * Reset the leftToAct collection.
724
     */
725
    private function setupLeftToAct()
726
    {
727
        if ($this->players()->count() === 2) {
728 50
            $this->leftToAct = $this->leftToAct()->setup($this->players());
729
730 50
            return;
731 4
        }
732
733 4
        $this->leftToAct = $this->leftToAct
734
            ->setup($this->players())
735
            ->resetPlayerListFromSeat($this->table()->button() + 1);
736 46
    }
737 46
738 46
    /**
739 46
     * @param PlayerContract $player
740
     */
741
    public function sitPlayerOut(PlayerContract $player)
742
    {
743
        $this->table()->sitPlayerOut($player);
744 1
        $this->leftToAct = $this->leftToAct()->removePlayer($player);
745
    }
746 1
747 1
    /**
748 1
     * @var int
749
     */
750
    public function resetPlayerList(int $seat)
751
    {
752
        $this->leftToAct = $this->leftToAct
753
            ->resetActions()
754
            ->sortBySeats()
755
            ->resetPlayerListFromSeat($seat);
756
    }
757
}
758