Election::removeExternalDataHandler()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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