Completed
Branch dev-2.0 (933cbb)
by Boudry
02:44
created

Election::getImplicitRankingRule()   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 155
    public function __construct ()
67
    {
68 155
        $this->_Candidates = [];
69 155
        $this->_Votes = new VotesManager ($this);
70 155
        $this->_timer = new Timer_Manager;
71 155
    }
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
89
            '_ImplicitRanking',
90
            '_VoteWeightRule',
91
            '_Constraints',
92
93
            '_Pairwise',
94
            '_Calculator',
95
        ];
96
97 2
        !self::$_checksumMode && array_push($include, '_timer');
98
99 2
        return $include;
100
    }
101
102 1
    public function __wakeup ()
103
    {
104 1
        if ( version_compare($this->getObjectVersion(true),Condorcet::getVersion(true),'!=') ) :
105
            throw new CondorcetException(11, 'Your object version is '.$this->getObjectVersion().' but the class engine version is '.Condorcet::getVersion());
106
        endif;
107 1
    }
108
109 1
    public function __clone ()
110
    {
111 1
        $this->_Votes = clone $this->_Votes;
112 1
        $this->_Votes->setElection($this);      
113 1
        $this->registerAllLinks();
114
115 1
        $this->_timer = clone $this->_timer;
116
117 1
        if ($this->_Pairwise !== null) :
118 1
            $this->_Pairwise = clone $this->_Pairwise;
119 1
            $this->_Pairwise->setElection($this);
120
        endif;
121 1
    }
122
123
124
/////////// TIMER & CHECKSUM ///////////
125
126 2
    public function getGlobalTimer () : float {
127 2
        return $this->_timer->getGlobalTimer();
128
    }
129
130 2
    public function getLastTimer () : float {
131 2
        return $this->_timer->getLastTimer();
132
    }
133
134 95
    public function getTimerManager () : Timer_Manager {
135 95
        return $this->_timer;
136
    }
137
138 1
    public function getChecksum () : string
139
    {
140 1
        self::$_checksumMode = true;
141
142 1
        $r = hash_init('sha256');
143
144 1
        foreach ($this->_Candidates as $value) :
145 1
            hash_update($r, (string) $value);
146
        endforeach;
147
148 1
        foreach ($this->_Votes as $value) :
149 1
            hash_update($r, (string) $value);
150
        endforeach;
151
152 1
        $this->_Pairwise !== null
153 1
            && hash_update($r,serialize($this->_Pairwise->getExplicitPairwise()));
154
155 1
        hash_update($r, $this->getObjectVersion(true));
156
157 1
        self::$_checksumMode = false;
158
159 1
        return hash_final($r);
160
    }
161
162
163
/////////// LINKS REGULATION ///////////
164
165 1
    protected function registerAllLinks () : void
166
    {
167 1
        foreach ($this->_Candidates as $value) :
168 1
            $value->registerLink($this);
169
        endforeach;
170
171 1
        if ($this->_State > 1) :
172 1
            foreach ($this->_Votes as $value) :
173 1
                $value->registerLink($this);
174
            endforeach;
175
        endif;
176 1
    }
177
178
    protected function destroyAllLink () : void
179
    {
180
        foreach ($this->_Candidates as $value) :
181
            $value->destroyLink($this);
182
        endforeach;
183
184
        if ($this->_State > 1) :
185
            foreach ($this->_Votes as $value) :
186
                $value->destroyLink($this);
187
            endforeach;
188
        endif;
189
    }
190
191
192
  /////////// IMPLICIT RANKING & VOTE WEIGHT ///////////
193
194 102
    public function getImplicitRankingRule () : bool
195
    {
196 102
        return $this->_ImplicitRanking;
197
    }
198
199 6
    public function setImplicitRanking (bool $rule = true) : bool
200
    {
201 6
        $this->_ImplicitRanking = $rule;
202 6
        $this->cleanupCompute();
203 6
        return $this->getImplicitRankingRule();
204
    }
205
206 98
    public function isVoteWeightIsAllowed () : bool
207
    {
208 98
        return $this->_VoteWeightRule;
209
    }
210
211 4
    public function allowVoteWeight (bool $rule = true) : bool
212
    {
213 4
        $this->_VoteWeightRule = $rule;
214 4
        $this->cleanupCompute();
215 4
        return $this->isVoteWeightIsAllowed();
216
    }
217
218
219
    /////////// VOTE CONSTRAINT ///////////
220
221 4
    public function addConstraint (string $class) : bool
222
    {
223 4
        if ( !class_exists($class) ) :
224 1
            throw new CondorcetException(27);
225 3
        elseif ( !is_subclass_of($class, __NAMESPACE__.'\\VoteConstraint') ) :
226 1
            throw new CondorcetException(28);
227 2
        elseif (in_array($class,$this->getConstraints(), true)) :
228 1
            throw new CondorcetException(29);
229
        endif;
230
231 2
        if ( $this->_State > 2) :
232 1
            $this->cleanupCompute();;
233
        endif;
234
235 2
        $this->_Constraints[] = $class;
236
237 2
        return true;
238
    }
239
240 2
    public function getConstraints () : array
241
    {
242 2
        return $this->_Constraints;
243
    }
244
245 2
    public function clearConstraints () : bool
246
    {
247 2
        $this->_Constraints = [];
248
249 2
        if ( $this->_State > 2) :
250 1
            $this->cleanupCompute();;
251
        endif;
252
253 2
        return true;
254
    }
255
256 95
    public function testIfVoteIsValidUnderElectionConstraints (Vote $vote) : bool
257
    {
258 95
        foreach ($this->_Constraints as $oneConstraint) :
259 1
            if ($oneConstraint::isVoteAllow($this,$vote) === false) :
260 1
                return false;
261
            endif;
262
        endforeach;
263
264 95
        return true;
265
    }
266
267
268
/////////// LARGE ELECTION MODE ///////////
269
270 7
    public function setExternalDataHandler (DataHandlerDriverInterface $driver) : bool
271
    {
272 7
        if (!$this->_Votes->isUsingHandler()) :
273 7
            $this->_Votes->importHandler($driver);
274 7
            return true;
275
        else :
276 1
            throw new CondorcetException(24);
277
        endif;
278
    }
279
280 1
    public function removeExternalDataHandler () : bool
281
    {
282 1
        if ($this->_Votes->isUsingHandler()) :
283 1
            $this->_Votes->closeHandler();
284 1
            return true;
285
        else :
286 1
            throw new CondorcetException(23);
287
        endif;
288
    }
289
290
291
/////////// STATE ///////////
292
293
    public function getState () : int
294
    {
295
        return $this->_State;
296
    }
297
298
    // Close the candidate config, be ready for voting (optional)
299 128
    public function setStateToVote () : bool
300
    {
301 128
        if ( $this->_State === 1 ) :
302 128
                if (empty($this->_Candidates)) :
303 1
                    throw new CondorcetException(20);
304
                endif;
305
306 128
                $this->_State = 2;
307
308
        // If voting continues after a first set of results
309 110
        elseif ( $this->_State > 2 ) :
310 7
                $this->cleanupCompute();
311
        endif;
312
313 128
        return true;
314
    }
315
316
    // Prepare to compute results & caching system
317 96
    protected function prepareResult () : bool
318
    {
319 96
        if ($this->_State > 2) :
320 89
            return false;
321 96
        elseif ($this->_State === 2) :
322 95
            $this->cleanupCompute();
323
324
            // Do Pairewise
325 95
            $this->makePairwise();
326
327
            // Change state to result
328 95
            $this->_State = 3;
329
330
            // Return
331 95
            return true;
332
        else :
333 1
            throw new CondorcetException(6);
334
        endif;
335
    }
336
337
338
/////////// CANDIDATES ///////////
339
340
    use CandidatesProcess;
341
342
343
/////////// VOTING ///////////
344
345
    use VotesProcess;
346
347
348
/////////// RESULTS ///////////
349
350
    use ResultsProcess;
351
}
352