1 | <?php |
||
2 | |||
3 | namespace Innmind\ProvisionerBundle; |
||
4 | |||
5 | use Innmind\ProvisionerBundle\Voter\VoterInterface; |
||
6 | use Symfony\Component\Console\Input\InputInterface; |
||
7 | |||
8 | class TriggerManager |
||
9 | { |
||
10 | const STRATEGY_AFFIRMATIVE = 'affirmative'; |
||
11 | const STRATEGY_CONSENSUS = 'consensus'; |
||
12 | const STRATEGY_UNANIMOUS = 'unanimous'; |
||
13 | |||
14 | protected $voters = []; |
||
15 | protected $strategy; |
||
16 | protected $allowIfEqualGrantedDeniedDecisions; |
||
17 | protected $allowIfAllAbstainDecisions; |
||
18 | |||
19 | 12 | public function __construct($strategy = self::STRATEGY_AFFIRMATIVE, $allowIfEqualGrantedDeniedDecisions = true, $allowIfAllAbstainDecisions = false) |
|
20 | { |
||
21 | 12 | if (!defined(sprintf('self::STRATEGY_%s', strtoupper($strategy)))) { |
|
22 | throw new \InvalidArgumentException(sprintf('The strategy "%s" is not supported', $strategy)); |
||
23 | } |
||
24 | |||
25 | 12 | $this->strategy = $strategy; |
|
26 | 12 | $this->allowIfEqualGrantedDeniedDecisions = $allowIfEqualGrantedDeniedDecisions; |
|
27 | 12 | $this->allowIfAllAbstainDecisions = $allowIfAllAbstainDecisions; |
|
28 | 12 | } |
|
29 | |||
30 | /** |
||
31 | * Add a new voter to the trigger manager |
||
32 | * |
||
33 | * @param VoterInterface $voter |
||
34 | * |
||
35 | * @return TriggerManager self |
||
36 | */ |
||
37 | 12 | public function addVoter(VoterInterface $voter) |
|
38 | { |
||
39 | 12 | $this->voters[] = $voter; |
|
40 | |||
41 | 12 | return $this; |
|
42 | } |
||
43 | |||
44 | /** |
||
45 | * Decide if the decision manager should be triggered or not |
||
46 | * |
||
47 | * @param string $command |
||
48 | * @param InputInterface $input |
||
49 | * |
||
50 | * @return bool |
||
51 | */ |
||
52 | 12 | public function decide($command, InputInterface $input) |
|
53 | { |
||
54 | 12 | $grant = 0; |
|
55 | 12 | $deny = 0; |
|
56 | 12 | $abstain = 0; |
|
57 | |||
58 | 12 | foreach ($this->voters as $voter) { |
|
59 | 12 | if (!$voter->supportsCommand($command)) { |
|
60 | continue; |
||
61 | } |
||
62 | |||
63 | 12 | $vote = $voter->vote($command, $input); |
|
64 | |||
65 | switch ($vote) { |
||
66 | 12 | case VoterInterface::TRIGGER_GRANTED: |
|
67 | 9 | $grant++; |
|
68 | 9 | break; |
|
69 | 12 | case VoterInterface::TRIGGER_DENIED: |
|
70 | 3 | $deny++; |
|
71 | 3 | break; |
|
72 | 9 | default: |
|
73 | 9 | $abstain++; |
|
74 | 9 | break; |
|
75 | 9 | } |
|
76 | 12 | } |
|
77 | |||
78 | 12 | switch ($this->strategy) { |
|
79 | 12 | case self::STRATEGY_AFFIRMATIVE: |
|
80 | 3 | return $grant > 0; |
|
81 | 9 | case self::STRATEGY_CONSENSUS: |
|
82 | 9 | if ($grant > $deny) { |
|
83 | 3 | return true; |
|
84 | } |
||
85 | |||
86 | 6 | if ($deny > $grant) { |
|
87 | return false; |
||
88 | } |
||
89 | |||
90 | 6 | if ($grant === $deny && $grant !== 0) { |
|
91 | 3 | return $this->allowIfEqualGrantedDeniedDecisions; |
|
92 | } |
||
93 | |||
94 | 3 | return $this->allowIfAllAbstainDecisions; |
|
95 | case self::STRATEGY_UNANIMOUS: |
||
96 | if ($deny > 0) { |
||
97 | return false; |
||
98 | } |
||
99 | |||
100 | if ($grant > 0) { |
||
101 | return true; |
||
102 | } |
||
103 | |||
104 | return $this->allowIfAllAbstainDecisions; |
||
105 | default: |
||
106 | return false; |
||
107 | } |
||
108 | } |
||
109 | } |
||
110 |