Passed
Branch dev-1.6.x (5fe494)
by Boudry
03:05
created

Election::__sleep()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 4
cts 4
cp 1
rs 9.0856
c 0
b 0
f 0
cc 2
crap 2
eloc 14
nc 2
nop 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 27 and the first side effect is on line 119.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/*
3
    Condorcet PHP Class, with Schulze Methods and others !
4
5
    By Julien Boudry - MIT LICENSE (Please read LICENSE.txt)
6
    https://github.com/julien-boudry/Condorcet
7
*/
8
declare(strict_types=1);
9
10
namespace Condorcet;
11
12
use Condorcet\Condorcet;
13
use Condorcet\CondorcetException;
14
use Condorcet\CondorcetVersion;
15
use Condorcet\Result;
16
use Condorcet\CondorcetUtil;
17
use Condorcet\Vote;
18
use Condorcet\Algo\Pairwise;
19
use Condorcet\DataManager\VotesManager;
20
use Condorcet\DataManager\DataHandlerDrivers\DataHandlerDriverInterface;
21
use Condorcet\ElectionProcess\ResultManager;
22
use Condorcet\Timer\Chrono as Timer_Chrono;
23
use Condorcet\Timer\Manager as Timer_Manager;
24
25
26
// Base Condorcet class
27
class Election
28
{
29
30
/////////// PROPERTIES ///////////
31
32
    public const MAX_LENGTH_CANDIDATE_ID = 30; // Max length for candidate identifiant string
33
34
    protected static $_maxParseIteration = null;
35
    protected static $_maxVoteNumber = null;
36
    protected static $_checksumMode = false;
37
38
/////////// STATICS METHODS ///////////
39
40
    // Change max parse iteration
41 1
    public static function setMaxParseIteration (?int $value) : ?int
42
    {
43 1
        self::$_maxParseIteration = $value;
44 1
        return self::$_maxParseIteration;
45
    }
46
47
    // Change max vote number
48 1
    public static function setMaxVoteNumber (?int $value) : ?int
49
    {
50 1
        self::$_maxVoteNumber = $value;
51 1
        return self::$_maxVoteNumber;
52
    }
53
54
55
/////////// CONSTRUCTOR ///////////
56
57
    use CondorcetVersion;
58
59
    // Data and global options
60
    protected $_Candidates = []; // Candidate list
61
    protected $_Votes; // Votes list
62
63
    // Mechanics
64
    protected $_i_CandidateId = 'A';
65
    protected $_State = 1; // 1 = Add Candidates / 2 = Voting / 3 = Some result have been computing
66
    protected $_timer;
67
    protected $_nextVoteTag = 0;
68
    protected $_ignoreStaticMaxVote = false;
69
70
    // Params
71
    protected $_ImplicitRanking = true;
72
    protected $_VoteWeightRule = false;
73
74
    // Result
75
    protected $_ResultManager;
76
77
        //////
78
79 110
    public function __construct ()
80
    {
81 110
        $this->_Candidates = [];
82 110
        $this->_Votes = new VotesManager ($this);
83 110
        $this->_timer = new Timer_Manager;
84 110
    }
85
86 1
    public function __destruct ()
87
    {
88 1
        $this->destroyAllLink();
89 1
    }
90
91 2
    public function __sleep () : array
92
    {
93
        // Don't include others data
94
        $include = [
95 2
            '_Candidates',
96
            '_Votes',
97
98
            '_i_CandidateId',
99
            '_State',
100
            '_nextVoteTag',
101
            '_objectVersion',
102
            '_ignoreStaticMaxVote',
103
104
            '_ImplicitRanking',
105
            '_VoteWeightRule',
106
107
            '_ResultManager'
108
        ];
109
110 2
        !self::$_checksumMode && array_push($include, '_timer');
111
112 2
        return $include;
113
    }
114
115 1
    public function __wakeup ()
116
    {
117 1
        if ( version_compare($this->getObjectVersion('MAJOR'),Condorcet::getVersion('MAJOR'),'!=') ) :
118
            throw new CondorcetException(11, 'Your object version is '.$this->getObjectVersion().' but the class engine version is '.Condorcet::getVersion('ENV'));
119
        endif;
120 1
    }
121
122 1
    public function __clone ()
123
    {
124 1
        $this->_Votes = clone $this->_Votes;
125 1
        $this->_Votes->setElection($this);      
126 1
        $this->registerAllLinks();
127
128 1
        $this->_timer = clone $this->_timer;
129
130 1
        if ($this->_ResultManager !== null) :
131 1
            $this->_ResultManager = clone $this->_ResultManager;
132 1
            $this->_ResultManager->setElection($this);
133
        endif;
134 1
    }
135
136
137
/////////// INTERNAL GENERIC REGULATION ///////////
138
139
140 1
    protected function registerAllLinks () : void
141
    {
142 1
        foreach ($this->_Candidates as $value) :
143 1
            $value->registerLink($this);
144
        endforeach;
145
146 1
        if ($this->_State > 1) :
147 1
            foreach ($this->_Votes as $value) :
148 1
                $value->registerLink($this);
149
            endforeach;
150
        endif;
151 1
    }
152
153 1
    protected function destroyAllLink () : void
154
    {
155 1
        foreach ($this->_Candidates as $value) :
156 1
            $value->destroyLink($this);
157
        endforeach;
158
159 1
        if ($this->_State > 1) :
160 1
            foreach ($this->_Votes as $value) :
161 1
                $value->destroyLink($this);
162
            endforeach;
163
        endif;
164 1
    }
165
166
        //////
167
168
169 2
    public function getGlobalTimer (bool $float = false) {
170 2
        return $this->_timer->getGlobalTimer($float);
171
    }
172
173 2
    public function getLastTimer (bool $float = false) {
174 2
        return $this->_timer->getLastTimer($float);
175
    }
176
177 80
    public function getTimerManager () : Timer_Manager {
178 80
        return $this->_timer;
179
    }
180
181 1
    public function getChecksum () : string
182
    {
183 1
        self::$_checksumMode = true;
184
185 1
        $r = hash_init('sha256');
186
187 1
        foreach ($this->_Candidates as $value) :
188 1
            hash_update($r, (string) $value);
189
        endforeach;
190
191 1
        foreach ($this->_Votes as $value) :
192 1
            hash_update($r, (string) $value);
193
        endforeach;
194
195 1
        $this->_ResultManager !== null
196 1
            && hash_update($r,serialize($this->_ResultManager->getPairwise()->getExplicitPairwise()));
197
198 1
        hash_update($r, $this->getObjectVersion('major'));
199
200 1
        self::$_checksumMode = false;
201
202 1
        return hash_final($r);
203
    }
204
205 1
    public function ignoreMaxVote (bool $state = true) : bool
206
    {
207 1
        return $this->_ignoreStaticMaxVote = $state;
208
    }
209
210 86
    public function getImplicitRankingRule () : bool
211
    {
212 86
        return $this->_ImplicitRanking;
213
    }
214
215 3
    public function setImplicitRanking (bool $rule = true) : bool
216
    {
217 3
        $this->_ImplicitRanking = $rule;
218 3
        $this->cleanupResult();
219 3
        return $this->getImplicitRankingRule();
220
    }
221
222 82
    public function isVoteWeightIsAllowed () : bool
223
    {
224 82
        return $this->_VoteWeightRule;
225
    }
226
227 1
    public function allowVoteWeight (bool $rule = true) : bool
228
    {
229 1
        $this->_VoteWeightRule = $rule;
230 1
        $this->cleanupResult();
231 1
        return $this->isVoteWeightIsAllowed();
232
    }
233
234
235
/////////// CANDIDATES ///////////
236
237
238
    // Add a vote candidate before voting
239 105
    public function addCandidate ($candidate_id = null) : Candidate
240
    {
241
        // only if the vote has not started
242 105
        if ( $this->_State > 1 ) :
243
            throw new CondorcetException(2);
244
        endif;
245
246
        // Filter
247 105
        if ( is_bool($candidate_id) || is_array($candidate_id) || (is_object($candidate_id) && !($candidate_id instanceof Candidate)) ) :
248
            throw new CondorcetException(1, $candidate_id);
249
        endif;
250
251
252
        // Process
253 105
        if ( empty($candidate_id) ) :
254 5
            while ( !$this->canAddCandidate($this->_i_CandidateId) ) :
255 5
                $this->_i_CandidateId++;
256
            endwhile;
257
258 5
            $newCandidate = new Candidate($this->_i_CandidateId);
259
        else : // Try to add the candidate_id
260 102
            $newCandidate = ($candidate_id instanceof Candidate) ? $candidate_id : new Candidate ((string) $candidate_id);
261
262 102
            if ( !$this->canAddCandidate($newCandidate) ) :
263
                throw new CondorcetException(3,$candidate_id);
264
            endif;
265
        endif;
266
267
        // Register it
268 105
        $this->_Candidates[] = $newCandidate;
269
270
        // Linking
271 105
        $newCandidate->registerLink($this);
272
273
        // Disallow other candidate object name matching 
274 105
        $newCandidate->setProvisionalState(false);
275
276 105
        return $newCandidate;
277
    }
278
279 105
        public function canAddCandidate ($candidate_id) : bool
280
        {
281 105
            return !$this->existCandidateId($candidate_id, false);
282
        }
283
284
285
    // Destroy a register vote candidate before voting
286 3
    public function removeCandidate ($list) : array
287
    {
288
        // only if the vote has not started
289 3
        if ( $this->_State > 1 ) :
290
            throw new CondorcetException(2);
291
        endif;
292
        
293 3
        if ( !is_array($list) ) :
294 3
            $list = [$list];
295
        endif;
296
297 3
        foreach ($list as &$candidate_id) :
298 3
            $candidate_key = $this->getCandidateKey($candidate_id);
299
300 3
            if ( $candidate_key === false ) :
301
                throw new CondorcetException(4,$candidate_id);
302
            endif;
303
304 3
            $candidate_id = $candidate_key;
305
        endforeach;
306
307 3
        $rem = [];
308 3
        foreach ($list as $candidate_key) :
309 3
            $this->_Candidates[$candidate_key]->destroyLink($this);
310
311 3
            $rem[] = $this->_Candidates[$candidate_key];
312
313 3
            unset($this->_Candidates[$candidate_key]);
314
        endforeach;
315
316 3
        return $rem;
317
    }
318
319
320 1
    public function jsonCandidates (string $input)
321
    {
322 1
        $input = CondorcetUtil::prepareJson($input);
323 1
        if ($input === false) :
324
            return $input;
325
        endif;
326
327
            //////
328
329 1
        $adding = [];
330 1
        foreach ($input as $candidate) :
331
            try {
332 1
                $adding[] = $this->addCandidate($candidate);
333
            }
334 1
            catch (CondorcetException $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
335
        endforeach;
336
337 1
        return $adding;
338
    }
339
340 7
    public function parseCandidates (string $input, bool $allowFile = true)
341
    {
342 7
        $input = CondorcetUtil::prepareParse($input, $allowFile);
343 7
        if ($input === false) :
344
            return $input;
345
        endif;
346
347 7
        $adding = [];
348 7
        foreach ($input as $line) :
349
            // Empty Line
350 7
            if (empty($line)) :
351 1
                continue;
352
            endif;
353
354
            // addCandidate
355
            try {
356 7
                if (self::$_maxParseIteration !== null && count($adding) >= self::$_maxParseIteration) :
357
                    throw new CondorcetException(12, self::$_maxParseIteration);
358
                endif;
359
360 7
                $adding[] = $this->addCandidate($line);
361
            } catch (CondorcetException $e) {
362
                if ($e->getCode() === 12)
363 7
                    {throw $e;}
364
            }
365
        endforeach;
366
367 7
        return $adding;
368
    }
369
370
371
        //:: CANDIDATES TOOLS :://
372
373
        // Count registered candidates
374 87
        public function countCandidates () : int
375
        {
376 87
            return count($this->_Candidates);
377
        }
378
379
        // Get the list of registered CANDIDATES
380 88
        public function getCandidatesList (bool $stringMode = false) : array
381
        {
382 88
            if (!$stringMode) :
383 86
                return $this->_Candidates;
384
            else :
385 4
                $result = [];
386
387 4
                foreach ($this->_Candidates as $candidateKey => &$oneCandidate) :
388 4
                    $result[$candidateKey] = $oneCandidate->getName();
389
                endforeach;
390
391 4
                return $result;
392
            endif;
393
        }
394
395 93
        public function getCandidateKey ($candidate_id)
396
        {
397 93
            if ($candidate_id instanceof Candidate) :
398 80
                return array_search($candidate_id, $this->_Candidates, true);
399
            else:
400 91
                return array_search(trim((string) $candidate_id), $this->_Candidates, false);
401
            endif;
402
        }
403
404 77
        public function getCandidateId (int $candidate_key, bool $onlyName = false)
405
        {
406 77
            if (!array_key_exists($candidate_key, $this->_Candidates)) :
407
                return false;
408
            else :
409 77
                return ($onlyName) ? $this->_Candidates[$candidate_key]->getName() : $this->_Candidates[$candidate_key];
410
            endif;
411
        }
412
413 105
        public function existCandidateId ($candidate_id, bool $strict = true) : bool
414
        {
415 105
            return ($strict) ? in_array($candidate_id, $this->_Candidates, true) : in_array((string) $candidate_id, $this->_Candidates);
416
        }
417
418 3
        public function getCandidateObjectByName (string $s)
419
        {
420 3
            foreach ($this->_Candidates as $oneCandidate) :
421
422 3
                if ($oneCandidate->getName() === $s) :
423 3
                    return $oneCandidate;
424
                endif;
425
            endforeach;
426
427 1
            return false;
428
        }
429
430
431
432
/////////// VOTING ///////////
433
434
435
    // Close the candidate config, be ready for voting (optional)
436 98
    public function setStateToVote () : bool
437
    {
438 98
        if ( $this->_State === 1 ) :
439 98
                if (empty($this->_Candidates)) :
440
                    throw new CondorcetException(20);
441
                endif;
442
443 98
                $this->_State = 2;
444
445
        // If voting continues after a first set of results
446 86
        elseif ( $this->_State > 2 ) :
447 5
                $this->cleanupResult();
448
        endif;
449
450 98
        return true;
451
    }
452
453
454
    // Add a single vote. Array key is the rank, each candidate in a rank are separate by ',' It is not necessary to register the last rank.
455 98
    public function addVote ($vote, $tag = null) : Vote
456
    {
457 98
        $this->prepareVoteInput($vote, $tag);
458
459
        // Check Max Vote Count
460 98
        if ( self::$_maxVoteNumber !== null && !$this->_ignoreStaticMaxVote && $this->countVotes() >= self::$_maxVoteNumber ) :
461 1
            throw new CondorcetException(16, self::$_maxVoteNumber);
462
        endif;
463
464
465
        // Register vote
466 98
        return $this->registerVote($vote, $tag); // Return the vote object
467
    }
468
469
        // return True or throw an Exception
470 5
        public function prepareModifyVote (Vote $existVote)
471
        {
472
            try {
473 5
                $this->prepareVoteInput($existVote);
474 5
                $this->setStateToVote();
475
            }
476
            catch (\Exception $e) {
477
                throw $e;
478
            }
479 5
        }
480
481
        // Return the well formated vote to use.
482 98
        protected function prepareVoteInput (&$vote, $tag = null) : void
483
        {
484 98
            if (!($vote instanceof Vote)) :
485 82
                $vote = new Vote ($vote, $tag);
486
            endif;
487
488
            // Check array format && Make checkVoteCandidate
489 98
            if ( !$this->checkVoteCandidate($vote) ) :
490
                throw new CondorcetException(5);
491
            endif;
492 98
        }
493
494
495 98
        public function checkVoteCandidate (Vote $vote) : bool
496
        {
497 98
            $linkCount = $vote->countLinks();
498 98
            $links = $vote->getLinks();
499
500 98
            $mirror = $vote->getRanking();
501 98
            $change = false;
502 98
            foreach ($vote as $rank => $choice) :
503 98
                foreach ($choice as $choiceKey => $candidate) :
504 98
                    if ( !$this->existCandidateId($candidate, true) ) :
505 91
                        if ($candidate->getProvisionalState() && $this->existCandidateId($candidate, false)) :
506 90
                            if ( $linkCount === 0 || ($linkCount === 1 && reset($links) === $this) ) :
507 90
                                $mirror[$rank][$choiceKey] = $this->_Candidates[$this->getCandidateKey((string) $candidate)];
508 90
                                $change = true;
509
                            else :
510 98
                                return false;
511
                            endif;
512
                        endif;
513
                    endif;
514
                endforeach;
515
            endforeach;
516
517 98
            if ($change) :
518 90
                $vote->setRanking(
519 90
                                    $mirror,
520 90
                                    ( abs($vote->getTimestamp() - microtime(true)) > 0.5 ) ? ($vote->getTimestamp() + 0.001) : false
0 ignored issues
show
Bug introduced by
It seems like abs($vote->getTimestamp(...stamp() + 0.001 : false can also be of type double; however, Condorcet\Vote::setRanking() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
521
                );
522
            endif;
523
524 98
            return true;
525
        }
526
527
        // Write a new vote
528 98
        protected function registerVote (Vote $vote, $tag = null) : Vote
529
        {
530
            // Vote identifiant
531 98
            $vote->addTags($tag);
532
            
533
            // Register
534
            try {
535 98
                $vote->registerLink($this);
536 98
                $this->_Votes[] = $vote;
537
            } catch (CondorcetException $e) {
538
                // Security : Check if vote object not already register
539
                throw new CondorcetException(6,'Vote object already registred');
540
            }
541
542 98
            return $vote;
543
        }
544
545
546 5
    public function removeVote ($in, bool $with = true) : array
547
    {    
548 5
        $rem = [];
549
550 5
        if ($in instanceof Vote) :
551 4
            $key = $this->getVoteKey($in);
552 4
            if ($key !== false) :
553 4
                $this->_Votes[$key]->destroyLink($this);
554
555 4
                $rem[] = $this->_Votes[$key];
556
557 4
                unset($this->_Votes[$key]);
558
            endif;
559
        else :
560
            // Prepare Tags
561 3
            $tag = Vote::tagsConvert($in);
562
563
            // Deleting
564 3
            foreach ($this->getVotesList($tag, $with) as $key => $value) :
565 3
                $this->_Votes[$key]->destroyLink($this);
566
567 3
                $rem[] = $this->_Votes[$key];
568
569 3
                unset($this->_Votes[$key]);
570
            endforeach;
571
572
        endif;
573
574 5
        return $rem;
575
    }
576
577
578 2
    public function jsonVotes (string $input)
579
    {
580 2
        $input = CondorcetUtil::prepareJson($input);
581 1
        if ($input === false) :
582
            return $input;
583
        endif;
584
585
            //////
586
587 1
        $adding = [];
588
589 1
        foreach ($input as $record) :
590 1
            if (empty($record['vote'])) :
591 1
                continue;
592
            endif;
593
594 1
            $tags = (!isset($record['tag'])) ? null : $record['tag'];
595 1
            $multi = (!isset($record['multi'])) ? 1 : $record['multi'];
596
597 1
            for ($i = 0; $i < $multi; $i++) :
598 1
                if (self::$_maxParseIteration !== null && $this->countVotes() >= self::$_maxParseIteration) :
599
                    throw new CondorcetException(12, self::$_maxParseIteration);
600
                endif;
601
602
                try {
603 1
                    $adding[] = $this->addVote($record['vote'], $tags);
604
                } catch (\Exception $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
605
            endfor;
606
        endforeach;
607
608 1
        return $adding;
609
    }
610
611 70
    public function parseVotes (string $input, bool $allowFile = true)
612
    {
613 70
        $input = CondorcetUtil::prepareParse($input, $allowFile);
614 70
        if ($input === false) :
615
            return $input;
616
        endif;
617
618
        // Check each lines
619 70
        $adding = [];
620 70
        foreach ($input as $line) :
621
            // Empty Line
622 70
            if (empty($line)) :
623 63
                continue;
624
            endif;
625
626
            // Multiples
627 70
            $is_multiple = mb_strpos($line, '*');
628 70
            if ($is_multiple !== false) :
629 63
                $multiple = trim( substr($line, $is_multiple + 1) );
630
631
                // Errors
632 63
                if ( !is_numeric($multiple) ) :
633
                    throw new CondorcetException(13, null);
634
                endif;
635
636 63
                $multiple = intval($multiple);
637
638
                // Reformat line
639 63
                $line = substr($line, 0, $is_multiple);
640
            else :
641 9
                $multiple = 1;
642
            endif;
643
644
            // Vote Weight
645 70
            $is_voteWeight = mb_strpos($line, '^');
646 70
            if ($is_voteWeight !== false) :
647 2
                $weight = trim( substr($line, $is_voteWeight + 1) );
648
649
                // Errors
650 2
                if ( !is_numeric($weight) ) :
651
                    throw new CondorcetException(13, null);
652
                endif;
653
654 2
                $weight = intval($weight);
655
656
                // Reformat line
657 2
                $line = substr($line, 0, $is_voteWeight);
658
            else :
659 69
                $weight = 1;
660
            endif;
661
662
            // Tags + vote
663 70
            if (mb_strpos($line, '||') !== false) :
664 4
                $data = explode('||', $line);
665
666 4
                $vote = $data[1];
667 4
                $tags = $data[0];
668
            // Vote without tags
669
            else :
670 69
                $vote = $line;
671 69
                $tags = null;
672
            endif;
673
674
            // addVote
675 70
            for ($i = 0; $i < $multiple; $i++) :
676 70
                if (self::$_maxParseIteration !== null && count($adding) >= self::$_maxParseIteration) :
677 1
                    throw new CondorcetException(12, self::$_maxParseIteration);
678
                endif;
679
680
                try {
681 70
                    $adding[] = ($newVote = $this->addVote($vote, $tags));
682 70
                    $newVote->setWeight($weight);
683 1
                } catch (CondorcetException $e) {}
1 ignored issue
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
684
            endfor;
685
        endforeach;
686
687 70
        return $adding;
688
    }
689
690
691
    //:: LARGE ELECTION MODE :://
692
693 3
    public function setExternalDataHandler (DataHandlerDriverInterface $driver) : bool
694
    {
695 3
        if (!$this->_Votes->isUsingHandler()) :
696 3
            $this->_Votes->importHandler($driver);
697 3
            return true;
698
        else :
699
            throw new CondorcetException(24);
700
        endif;
701
    }
702
703 1
    public function removeExternalDataHandler () : bool
704
    {
705 1
        if ($this->_Votes->isUsingHandler()) :
706 1
            $this->_Votes->closeHandler();
707 1
            return true;
708
        else :
709
            throw new CondorcetException(23);
710
        endif;
711
    }
712
713
714
    //:: VOTING TOOLS :://
715
716
    // How many votes are registered ?
717 10
    public function countVotes ($tag = null, bool $with = true) : int
718
    {
719 10
        return $this->_Votes->countVotes(Vote::tagsConvert($tag),$with);
720
    }
721
722
    // Get the votes registered list
723 9
    public function getVotesList ($tag = null, bool $with = true) : array
724
    {
725 9
        return $this->_Votes->getVotesList(Vote::tagsConvert($tag), $with);
726
    }
727
728 4
    public function getVotesListAsString () : string
729
    {
730 4
        return $this->_Votes->getVotesListAsString();
731
    }
732
733 81
    public function getVotesManager () : VotesManager {
734 81
        return $this->_Votes;
735
    }
736
737 4
    public function getVoteKey (Vote $vote) {
738 4
        return $this->_Votes->getVoteKey($vote);
739
    }
740
741
742
/////////// RESULTS ///////////
743
744
    //:: PUBLIC FUNCTIONS :://
745
746
    // Generic function for default result with ability to change default object method
747 48
    public function getResult ($method = true, array $options = []) : Result
748
    {
749 48
        $this->prepareResult();
750
751 48
        return $this->_ResultManager->getResult($method,$options);
752
    }
753
754
755 78
    public function getWinner (?string $substitution = null)
756
    {
757 78
        $this->prepareResult();
758
759 78
        return $this->_ResultManager->getWinner($substitution);
760
    }
761
762
763 75
    public function getLoser (?string $substitution = null)
764
    {
765 75
        $this->prepareResult();
766
767 75
        return $this->_ResultManager->getLoser($substitution);
768
    }
769
770
771 1
    public function computeResult ($method = true) : void
772
    {
773 1
        $this->getResult($method);
774 1
    }
775
776
777
    //:: TOOLS FOR RESULT PROCESS :://
778
779
780
    // Prepare to compute results & caching system
781 80
    protected function prepareResult () : bool
782
    {
783 80
        if ($this->_State > 2) :
784 77
            return false;
785 80
        elseif ($this->_State === 2) :
786 80
            $this->cleanupResult();
787
788 80
            $this->_ResultManager = new ResultManager ($this);
789
790
            // Change state to result
791 80
            $this->_State = 3;
792
793
            // Return
794 80
            return true;
795
        else :
796
            throw new CondorcetException(6);
797
        endif;
798
    }
799
800
801
    // Cleanup results to compute again with new votes
802 80
    protected function cleanupResult () : void
803
    {
804
        // Reset state
805 80
        if ($this->_State > 2) : 
806 7
            $this->_State = 2;
807
        endif;
808
809
            //////
810
811 80
        $this->_ResultManager = null;
812 80
    }
813
814
815
    //:: GET RAW DATA :://
816
817 77
    public function getPairwise (bool $explicit = true)
818
    {
819 77
        $this->prepareResult();
820
821 77
        $pairwise = $this->_ResultManager->getPairwise($explicit);
822
823 77
        return (!$explicit) ? $pairwise : $pairwise->getExplicitPairwise($explicit);
824
    }
825
826
}
827