Completed
Branch master (fa2fc5)
by Boudry
05:50 queued 02:29
created

VotesProcess::getVotesManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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\ElectionProcess;
12
13
use Condorcet\CondorcetException;
14
use Condorcet\CondorcetUtil;
15
use Condorcet\Vote;
16
use Condorcet\DataManager\VotesManager;
17
18
// Manage Results for Election class
19
trait VotesProcess
20
{
21
22
/////////// CONSTRUCTOR ///////////
23
24
    // Data and global options
25
    protected $_Votes; // Votes list
26
    protected $_ignoreStaticMaxVote = false;
27
28
29 1
    public function ignoreMaxVote (bool $state = true) : bool
30
    {
31 1
        return $this->_ignoreStaticMaxVote = $state;
32
    }
33
34
35
/////////// VOTES LIST ///////////
36
37
    // How many votes are registered ?
38 11
    public function countVotes ($tag = null, bool $with = true) : int
39
    {
40 11
        return $this->_Votes->countVotes(VoteUtil::tagsConvert($tag),$with);
41
    }
42
43
    // Sum votes weight
44 6
    public function sumVotesWeight () : int
45
    {
46 6
        return $this->_Votes->sumVotesWeight();
47
    }
48
49
    // Get the votes registered list
50 11
    public function getVotesList ($tag = null, bool $with = true) : array
51
    {
52 11
        return $this->_Votes->getVotesList(VoteUtil::tagsConvert($tag), $with);
53
    }
54
55 5
    public function getVotesListAsString () : string
56
    {
57 5
        return $this->_Votes->getVotesListAsString();
58
    }
59
60 99
    public function getVotesManager () : VotesManager {
61 99
        return $this->_Votes;
62
    }
63
64 2
    public function getVotesListGenerator ($tag = null, bool $with = true) : \Generator
65
    {
66 2
        return $this->_Votes->getVotesListGenerator(VoteUtil::tagsConvert($tag), $with);
67
    }
68
69 5
    public function getVoteKey (Vote $vote) {
70 5
        return $this->_Votes->getVoteKey($vote);
71
    }
72
73
74
/////////// ADD & REMOVE VOTE ///////////
75
76
    // 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.
77 114
    public function addVote ($vote, $tag = null) : Vote
78
    {
79 114
        $this->prepareVoteInput($vote, $tag);
80
81
        // Check Max Vote Count
82 114
        if ( self::$_maxVoteNumber !== null && !$this->_ignoreStaticMaxVote && $this->countVotes() >= self::$_maxVoteNumber ) :
83 1
            throw new CondorcetException(16, self::$_maxVoteNumber);
84
        endif;
85
86
87
        // Register vote
88 114
        return $this->registerVote($vote, $tag); // Return the vote object
89
    }
90
91
    // return True or throw an Exception
92 6
    public function prepareModifyVote (Vote $existVote) : void
93
    {
94
        try {
95 6
            $this->prepareVoteInput($existVote);
96 6
            $this->setStateToVote();
97
98 6
            if ($this->_Votes->isUsingHandler()) : 
99 6
                $this->_Votes[$this->getVoteKey($existVote)] = $existVote;
100
            endif;
101
        }
102
        catch (\Exception $e) {
103
            throw $e;
104
        }
105 6
    }
106
107 114
    public function checkVoteCandidate (Vote $vote) : bool
108
    {
109 114
        $linkCount = $vote->countLinks();
110 114
        $links = $vote->getLinks();
111
112 114
        $mirror = $vote->getRanking();
113 114
        $change = false;
114 114
        foreach ($vote as $rank => $choice) :
115 114
            foreach ($choice as $choiceKey => $candidate) :
116 114
                if ( !$this->existCandidateId($candidate, true) ) :
117 107
                    if ($candidate->getProvisionalState() && $this->existCandidateId($candidate, false)) :
118 106
                        if ( $linkCount === 0 || ($linkCount === 1 && reset($links) === $this) ) :
119 106
                            $mirror[$rank][$choiceKey] = $this->_Candidates[$this->getCandidateKey((string) $candidate)];
120 106
                            $change = true;
121
                        else :
122 114
                            return false;
123
                        endif;
124
                    endif;
125
                endif;
126
            endforeach;
127
        endforeach;
128
129 114
        if ($change) :
130 106
            $vote->setRanking(  $mirror,
131 106
                                ( abs($vote->getTimestamp() - microtime(true)) > 0.5 ) ? ($vote->getTimestamp() + 0.001) : null
132
            );
133
        endif;
134
135 114
        return true;
136
    }
137
138
    // Write a new vote
139 114
    protected function registerVote (Vote $vote, $tag = null) : Vote
140
    {
141
        // Vote identifiant
142 114
        $vote->addTags($tag);
143
        
144
        // Register
145
        try {
146 114
            $vote->registerLink($this);
147 114
            $this->_Votes[] = $vote;
148
        } catch (CondorcetException $e) {
149
            // Security : Check if vote object not already register
150
            throw new CondorcetException(6,'Vote object already registred');
151
        }
152
153 114
        return $vote;
154
    }
155
156 5
    public function removeVote ($in, bool $with = true) : array
157
    {    
158 5
        $rem = [];
159
160 5
        if ($in instanceof Vote) :
161 4
            $key = $this->getVoteKey($in);
162 4
            if ($key !== false) :
163 4
                $this->_Votes[$key]->destroyLink($this);
164
165 4
                $rem[] = $this->_Votes[$key];
166
167 4
                unset($this->_Votes[$key]);
168
            endif;
169
        else :
170
            // Prepare Tags
171 3
            $tag = VoteUtil::tagsConvert($in);
172
173
            // Deleting
174 3
            foreach ($this->getVotesList($tag, $with) as $key => $value) :
175 3
                $this->_Votes[$key]->destroyLink($this);
176
177 3
                $rem[] = $this->_Votes[$key];
178
179 3
                unset($this->_Votes[$key]);
180
            endforeach;
181
182
        endif;
183
184 5
        return $rem;
185
    }
186
187
188
/////////// PARSE VOTE ///////////
189
190
    // Return the well formated vote to use.
191 114
    protected function prepareVoteInput (&$vote, $tag = null) : void
192
    {
193 114
        if (!($vote instanceof Vote)) :
194 98
            $vote = new Vote ($vote, $tag);
195
        endif;
196
197
        // Check array format && Make checkVoteCandidate
198 114
        if ( !$this->checkVoteCandidate($vote) ) :
199
            throw new CondorcetException(5);
200
        endif;
201 114
    }
202
203 2
    public function jsonVotes (string $input)
204
    {
205 2
        $input = CondorcetUtil::prepareJson($input);
206 1
        if ($input === false) :
207
            return $input;
208
        endif;
209
210
            //////
211
212 1
        $adding = [];
213
214 1
        foreach ($input as $record) :
215 1
            if (empty($record['vote'])) :
216 1
                continue;
217
            endif;
218
219 1
            $tags = (!isset($record['tag'])) ? null : $record['tag'];
220 1
            $multi = (!isset($record['multi'])) ? 1 : $record['multi'];
221
222 1
            for ($i = 0; $i < $multi; $i++) :
223 1
                if (self::$_maxParseIteration !== null && $this->countVotes() >= self::$_maxParseIteration) :
224
                    throw new CondorcetException(12, self::$_maxParseIteration);
225
                endif;
226
227
                try {
228 1
                    $adding[] = $this->addVote($record['vote'], $tags);
229
                } catch (\Exception $e) {
230
                    // Ignore invalid vote
231
                }
232
            endfor;
233
        endforeach;
234
235 1
        return $adding;
236
    }
237
238 86
    public function parseVotes (string $input, bool $allowFile = true)
239
    {
240 86
        $input = CondorcetUtil::prepareParse($input, $allowFile);
241 86
        if ($input === false) :
242
            return $input;
243
        endif;
244
245
        // Check each lines
246 86
        $adding = [];
247 86
        foreach ($input as $line) :
248
            // Empty Line
249 86
            if (empty($line)) :
250 75
                continue;
251
            endif;
252
253
            // Multiples
254 86
            $is_multiple = mb_strpos($line, '*');
255 86 View Code Duplication
            if ($is_multiple !== false) :
256 72
                $multiple = trim( substr($line, $is_multiple + 1) );
257
258
                // Errors
259 72
                if ( !is_numeric($multiple) ) :
260
                    throw new CondorcetException(13, null);
261
                endif;
262
263 72
                $multiple = intval($multiple);
264
265
                // Reformat line
266 72
                $line = substr($line, 0, $is_multiple);
267
            else :
268 18
                $multiple = 1;
269
            endif;
270
271
            // Vote Weight
272 86
            $is_voteWeight = mb_strpos($line, '^');
273 86 View Code Duplication
            if ($is_voteWeight !== false) :
274 4
                $weight = trim( substr($line, $is_voteWeight + 1) );
275
276
                // Errors
277 4
                if ( !is_numeric($weight) ) :
278
                    throw new CondorcetException(13, null);
279
                endif;
280
281 4
                $weight = intval($weight);
282
283
                // Reformat line
284 4
                $line = substr($line, 0, $is_voteWeight);
285
            else :
286 85
                $weight = 1;
287
            endif;
288
289
            // Tags + vote
290 86
            if (mb_strpos($line, '||') !== false) :
291 6
                $data = explode('||', $line);
292
293 6
                $vote = $data[1];
294 6
                $tags = $data[0];
295
            // Vote without tags
296
            else :
297 85
                $vote = $line;
298 85
                $tags = null;
299
            endif;
300
301
            // addVote
302 86
            for ($i = 0; $i < $multiple; $i++) :
303 86 View Code Duplication
                if (self::$_maxParseIteration !== null && count($adding) >= self::$_maxParseIteration) :
304 1
                    throw new CondorcetException(12, self::$_maxParseIteration);
305
                endif;
306
307
                try {
308 86
                    $adding[] = ($newVote = $this->addVote($vote, $tags));
309 86
                    $newVote->setWeight($weight);
310 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...
311
            endfor;
312
        endforeach;
313
314 86
        return $adding;
315
    }
316
}
317