Passed
Branch dev-2.0 (2cc6f8)
by Boudry
02:44
created

Election::isVoteWeightIsAllowed()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
    Condorcet PHP - Election manager and results calculator.
4
    Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
5
6
    By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
7
    https://github.com/julien-boudry/Condorcet
8
*/
9
declare(strict_types=1);
10
11
namespace CondorcetPHP\Condorcet;
12
13
14
use CondorcetPHP\Condorcet\DataManager\VotesManager;
15
use CondorcetPHP\Condorcet\DataManager\DataHandlerDrivers\DataHandlerDriverInterface;
16
use CondorcetPHP\Condorcet\ElectionProcess\CandidatesProcess;
17
use CondorcetPHP\Condorcet\ElectionProcess\ResultsProcess;
18
use CondorcetPHP\Condorcet\ElectionProcess\VotesProcess;
19
use CondorcetPHP\Condorcet\Timer\Manager as Timer_Manager;
20
21
22
// Base Condorcet class
23
class Election
24
{
25
26
/////////// PROPERTIES ///////////
27
28
    public const MAX_LENGTH_CANDIDATE_ID = 30; // Max length for candidate identifiant string
29
30
    protected static $_maxParseIteration = null;
31
    protected static $_maxVoteNumber = null;
32
    protected static $_checksumMode = false;
33
34
/////////// STATICS METHODS ///////////
35
36
    // Change max parse iteration
37 3
    public static function setMaxParseIteration (?int $value) : ?int
38
    {
39 3
        self::$_maxParseIteration = $value;
40 3
        return self::$_maxParseIteration;
41
    }
42
43
    // Change max vote number
44 1
    public static function setMaxVoteNumber (?int $value) : ?int
45
    {
46 1
        self::$_maxVoteNumber = $value;
47 1
        return self::$_maxVoteNumber;
48
    }
49
50
51
/////////// CONSTRUCTOR ///////////
52
53
    use CondorcetVersion;
54
55
    // Mechanics
56
    protected $_State = 1; // 1 = Add Candidates / 2 = Voting / 3 = Some result have been computing
57
    protected $_timer;
58
59
    // Params
60
    protected $_ImplicitRanking = true;
61
    protected $_VoteWeightRule = false;
62
    protected $_Constraints = [];
63
64
        //////
65
66 145
    public function __construct ()
67
    {
68 145
        $this->_Candidates = [];
69 145
        $this->_Votes = new VotesManager ($this);
70 145
        $this->_timer = new Timer_Manager;
71 145
    }
72
73
    public function __destruct ()
74
    {
75
        $this->destroyAllLink();
76
    }
77
78 2
    public function __sleep () : array
79
    {
80
        // Don't include others data
81
        $include = [
82 2
            '_Candidates',
83
            '_Votes',
84
85
            '_i_CandidateId',
86
            '_State',
87
            '_objectVersion',
88
            '_ignoreStaticMaxVote',
89
90
            '_ImplicitRanking',
91
            '_VoteWeightRule',
92
            '_Constraints',
93
94
            '_Pairwise',
95
            '_Calculator',
96
        ];
97
98 2
        !self::$_checksumMode && array_push($include, '_timer');
99
100 2
        return $include;
101
    }
102
103 1
    public function __wakeup ()
104
    {
105 1
        if ( version_compare($this->getObjectVersion(true),Condorcet::getVersion(true),'!=') ) :
106
            throw new CondorcetException(11, 'Your object version is '.$this->getObjectVersion().' but the class engine version is '.Condorcet::getVersion());
107
        endif;
108 1
    }
109
110 1
    public function __clone ()
111
    {
112 1
        $this->_Votes = clone $this->_Votes;
113 1
        $this->_Votes->setElection($this);      
114 1
        $this->registerAllLinks();
115
116 1
        $this->_timer = clone $this->_timer;
117
118 1
        if ($this->_Pairwise !== null) :
119 1
            $this->_Pairwise = clone $this->_Pairwise;
120 1
            $this->_Pairwise->setElection($this);
121
        endif;
122 1
    }
123
124
125
/////////// TIMER & CHECKSUM ///////////
126
127 2
    public function getGlobalTimer () : float {
128 2
        return $this->_timer->getGlobalTimer();
129
    }
130
131 2
    public function getLastTimer () : float {
132 2
        return $this->_timer->getLastTimer();
133
    }
134
135 93
    public function getTimerManager () : Timer_Manager {
136 93
        return $this->_timer;
137
    }
138
139 1
    public function getChecksum () : string
140
    {
141 1
        self::$_checksumMode = true;
142
143 1
        $r = hash_init('sha256');
144
145 1
        foreach ($this->_Candidates as $value) :
146 1
            hash_update($r, (string) $value);
147
        endforeach;
148
149 1
        foreach ($this->_Votes as $value) :
150 1
            hash_update($r, (string) $value);
151
        endforeach;
152
153 1
        $this->_Pairwise !== null
154 1
            && hash_update($r,serialize($this->_Pairwise->getExplicitPairwise()));
155
156 1
        hash_update($r, $this->getObjectVersion(true));
157
158 1
        self::$_checksumMode = false;
159
160 1
        return hash_final($r);
161
    }
162
163
164
/////////// LINKS REGULATION ///////////
165
166 1
    protected function registerAllLinks () : void
167
    {
168 1
        foreach ($this->_Candidates as $value) :
169 1
            $value->registerLink($this);
170
        endforeach;
171
172 1
        if ($this->_State > 1) :
173 1
            foreach ($this->_Votes as $value) :
174 1
                $value->registerLink($this);
175
            endforeach;
176
        endif;
177 1
    }
178
179
    protected function destroyAllLink () : void
180
    {
181
        foreach ($this->_Candidates as $value) :
182
            $value->destroyLink($this);
183
        endforeach;
184
185
        if ($this->_State > 1) :
186
            foreach ($this->_Votes as $value) :
187
                $value->destroyLink($this);
188
            endforeach;
189
        endif;
190
    }
191
192
193
  /////////// IMPLICIT RANKING & VOTE WEIGHT ///////////
194
195 100
    public function getImplicitRankingRule () : bool
196
    {
197 100
        return $this->_ImplicitRanking;
198
    }
199
200 6
    public function setImplicitRanking (bool $rule = true) : bool
201
    {
202 6
        $this->_ImplicitRanking = $rule;
203 6
        $this->cleanupResult();
204 6
        return $this->getImplicitRankingRule();
205
    }
206
207 96
    public function isVoteWeightIsAllowed () : bool
208
    {
209 96
        return $this->_VoteWeightRule;
210
    }
211
212 4
    public function allowVoteWeight (bool $rule = true) : bool
213
    {
214 4
        $this->_VoteWeightRule = $rule;
215 4
        $this->cleanupResult();
216 4
        return $this->isVoteWeightIsAllowed();
217
    }
218
219
220
    /////////// VOTE CONSTRAINT ///////////
221
222 4
    public function addConstraint (string $class) : bool
223
    {
224 4
        if ( !class_exists($class) ) :
225 1
            throw new CondorcetException(27);
226 3
        elseif ( !is_subclass_of($class, __NAMESPACE__.'\\VoteConstraint') ) :
227 1
            throw new CondorcetException(28);
228 2
        elseif (in_array($class,$this->getConstraints(), true)) :
229 1
            throw new CondorcetException(29);
230
        endif;
231
232 2
        if ( $this->_State > 2) :
233 1
            $this->cleanupResult();;
234
        endif;
235
236 2
        $this->_Constraints[] = $class;
237
238 2
        return true;
239
    }
240
241 2
    public function getConstraints () : array
242
    {
243 2
        return $this->_Constraints;
244
    }
245
246 2
    public function clearConstraints () : bool
247
    {
248 2
        $this->_Constraints = [];
249
250 2
        if ( $this->_State > 2) :
251 1
            $this->cleanupResult();;
252
        endif;
253
254 2
        return true;
255
    }
256
257 93
    public function testIfVoteIsValidUnderElectionConstraints (Vote $vote) : bool
258
    {
259 93
        foreach ($this->_Constraints as $oneConstraint) :
260 1
            if ($oneConstraint::isVoteAllow($this,$vote) === false) :
261 1
                return false;
262
            endif;
263
        endforeach;
264
265 93
        return true;
266
    }
267
268
269
/////////// LARGE ELECTION MODE ///////////
270
271 6
    public function setExternalDataHandler (DataHandlerDriverInterface $driver) : bool
272
    {
273 6
        if (!$this->_Votes->isUsingHandler()) :
274 6
            $this->_Votes->importHandler($driver);
275 6
            return true;
276
        else :
277
            throw new CondorcetException(24);
278
        endif;
279
    }
280
281 1
    public function removeExternalDataHandler () : bool
282
    {
283 1
        if ($this->_Votes->isUsingHandler()) :
284 1
            $this->_Votes->closeHandler();
285 1
            return true;
286
        else :
287
            throw new CondorcetException(23);
288
        endif;
289
    }
290
291
292
/////////// STATE ///////////
293
294
    // Close the candidate config, be ready for voting (optional)
295 123
    public function setStateToVote () : bool
296
    {
297 123
        if ( $this->_State === 1 ) :
298 123
                if (empty($this->_Candidates)) :
299
                    throw new CondorcetException(20);
300
                endif;
301
302 123
                $this->_State = 2;
303
304
        // If voting continues after a first set of results
305 105
        elseif ( $this->_State > 2 ) :
306 6
                $this->cleanupResult();
307
        endif;
308
309 123
        return true;
310
    }
311
312
    // Prepare to compute results & caching system
313 93
    protected function prepareResult () : bool
314
    {
315 93
        if ($this->_State > 2) :
316 87
            return false;
317 93
        elseif ($this->_State === 2) :
318 93
            $this->cleanupResult();
319
320
            // Do Pairewise
321 93
            $this->makePairwise();
322
323
            // Change state to result
324 93
            $this->_State = 3;
325
326
            // Return
327 93
            return true;
328
        else :
329
            throw new CondorcetException(6);
330
        endif;
331
    }
332
333
334
/////////// CANDIDATES ///////////
335
336
    use CandidatesProcess;
337
338
339
/////////// VOTING ///////////
340
341
    use VotesProcess;
342
343
344
/////////// RESULTS ///////////
345
346
    use ResultsProcess;
347
}
348