Completed
Branch dev-1.8.x (7905e8)
by Boudry
03:47
created

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