Completed
Push — master ( e86a88...9f06ff )
by Boudry
04:59 queued 02:04
created

VotesProcess::getVotesListGenerator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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