Completed
Push — master ( 4632b0...98cfe8 )
by Guillermo
36:11
created

SecretSanta::combinePlayers()   C

Complexity

Conditions 11
Paths 13

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 5.2653
c 0
b 0
f 0
cc 11
eloc 18
nc 13
nop 0

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
namespace SecretSanta;
4
5
use SecretSanta\Exceptions\SecretSantaException;
6
7
/**
8
 * Class SecretSanta
9
 * @package SecretSanta
10
 */
11
class SecretSanta
12
{
13
    /** @var PlayersCollection */
14
    private $players;
15
    /** @var  array */
16
    private $combination;
17
18
    /**
19
     * SecretSanta constructor.
20
     */
21
    public function __construct()
22
    {
23
        $this->players = new PlayersCollection();
24
    }
25
26
    /**
27
     * @param string $name
28
     * @param string $email
29
     * @return SecretSanta
30
     */
31
    public function addPlayer($name, $email)
32
    {
33
        $this->players->addPlayer(Player::create($name, $email));
34
35
        return $this;
36
    }
37
38
    /**
39
     * @param string $name
40
     * @param string $email
41
     * @param string $coupleName
42
     * @param string $coupleEmail
43
     * @return SecretSanta
44
     */
45
    public function addCouple($name, $email, $coupleName, $coupleEmail)
46
    {
47
        $this->players->addCouple(
48
            Player::create($name, $email),
49
            Player::create($coupleName, $coupleEmail)
50
        );
51
52
        return $this;
53
    }
54
55
    /**
56
     * @return PlayersCollection
57
     * @throws SecretSantaException
58
     */
59
    public function play()
60
    {
61
        try {
62
            $this->combinePlayers();
63
64
            return $this->players;
65
        } catch (SecretSantaException $exception) {
66
            throw  $exception;
67
        } catch (\Exception $exception) {
68
            throw new SecretSantaException(
69
                'Error during play, impossible to find secret santa, try again',
70
                0,
71
                $exception
72
            );
73
        }
74
    }
75
76
    /**
77
     * @throws SecretSantaException
78
     */
79
    private function combinePlayers()
80
    {
81
        if (count($this->players) < 4) {
82
            throw new SecretSantaException("Not enough players to play, at least 4 players are required");
83
        }
84
85
        $retry = count($this->players) + $this->players->countExcludePlayers();
86
87
        while (!$this->isValidCombination() && $retry > 0 ) {
88
            $this->combination = [];
89
            $secretPlayers = $this->players->shufflePlayers();
90
            foreach ($this->players as $playerId => $player) {
91
                foreach ($secretPlayers as $secretPlayer) {
92
                    if ($player->id() != $secretPlayer->id() && !$this->players->areExclude($player, $secretPlayer)) {
93
                        if (!in_array($secretPlayer->id(), $this->combination)) {
94
                            $player->setSecretSanta($secretPlayer);
95
                            $this->combination[$player->id()] = $secretPlayer->id();
96
                            unset ($secretPlayers[$secretPlayer->id()]);
97
                            break;
98
                        }
99
                    }
100
                }
101
            }
102
            $retry--;
103
        }
104
105
        if (!$this->isValidCombination() && $retry <= 0) {
106
            throw new SecretSantaException("Not enough players to play");
107
        }
108
    }
109
110
    /**
111
     * @return bool
112
     */
113
    private function isValidCombination()
114
    {
115
        return count($this->combination) > 0 && count($this->combination) == count($this->players);
116
    }
117
}
118