Passed
Branch dev-2.0 (faa14c)
by Boudry
02:42
created

VotesProcess::ignoreMaxVote()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
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\ElectionProcess;
12
13
use CondorcetPHP\Condorcet\CondorcetException;
14
use CondorcetPHP\Condorcet\CondorcetUtil;
15
use CondorcetPHP\Condorcet\Vote;
16
use CondorcetPHP\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
27
28
/////////// VOTES LIST ///////////
29
30
    // How many votes are registered ?
31 12
    public function countVotes ($tag = null, bool $with = true) : int
32
    {
33 12
        return $this->_Votes->countVotes(VoteUtil::tagsConvert($tag),$with);
34
    }
35
36 1
    public function countInvalidVoteWithConstraints () : int
37
    {
38 1
        return $this->_Votes->countInvalidVoteWithConstraints();
39
    }
40
41 1
    public function countValidVoteWithConstraints () : int
42
    {
43 1
        return $this->countVotes() - $this->countInvalidVoteWithConstraints();
44
    }
45
46
    // Sum votes weight
47 2
    public function sumVotesWeight () : int
48
    {
49 2
        return $this->_Votes->sumVotesWeight(false);
50
    }
51
52 6
    public function sumValidVotesWeightWithConstraints () : int
53
    {
54 6
        return $this->_Votes->sumVotesWeight(true);
55
    }
56
57
    // Get the votes registered list
58 11
    public function getVotesList ($tag = null, bool $with = true) : array
59
    {
60 11
        return $this->_Votes->getVotesList(VoteUtil::tagsConvert($tag), $with);
61
    }
62
63 5
    public function getVotesListAsString () : string
64
    {
65 5
        return $this->_Votes->getVotesListAsString();
66
    }
67
68 101
    public function getVotesManager () : VotesManager {
69 101
        return $this->_Votes;
70
    }
71
72 2
    public function getVotesListGenerator ($tag = null, bool $with = true) : \Generator
73
    {
74 2
        return $this->_Votes->getVotesListGenerator(VoteUtil::tagsConvert($tag), $with);
75
    }
76
77 5
    public function getVoteKey (Vote $vote) {
78 5
        return $this->_Votes->getVoteKey($vote);
79
    }
80
81
82
/////////// ADD & REMOVE VOTE ///////////
83
84
    // 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.
85 125
    public function addVote ($vote, $tag = null) : Vote
86
    {
87 125
        $this->prepareVoteInput($vote, $tag);
88
89
        // Check Max Vote Count
90 125
        if ( self::$_maxVoteNumber !== null && $this->countVotes() >= self::$_maxVoteNumber ) :
91 1
            throw new CondorcetException(16, self::$_maxVoteNumber);
92
        endif;
93
94
95
        // Register vote
96 125
        return $this->registerVote($vote, $tag); // Return the vote object
97
    }
98
99
    // return True or throw an Exception
100 6
    public function prepareModifyVote (Vote $existVote) : void
101
    {
102
        try {
103 6
            $this->prepareVoteInput($existVote);
104 6
            $this->setStateToVote();
105
106 6
            if ($this->_Votes->isUsingHandler()) : 
107 6
                $this->_Votes[$this->getVoteKey($existVote)] = $existVote;
108
            endif;
109
        }
110
        catch (\Exception $e) {
111
            throw $e;
112
        }
113 6
    }
114
115 125
    public function checkVoteCandidate (Vote $vote) : bool
116
    {
117 125
        $linkCount = $vote->countLinks();
118 125
        $links = $vote->getLinks();
119
120 125
        $mirror = $vote->getRanking();
121 125
        $change = false;
122 125
        foreach ($vote as $rank => $choice) :
123 125
            foreach ($choice as $choiceKey => $candidate) :
124 125
                if ( !$this->isRegisteredCandidate($candidate, true) ) :
0 ignored issues
show
Bug introduced by
It seems like isRegisteredCandidate() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
125 108
                    if ($candidate->getProvisionalState() && $this->isRegisteredCandidate($candidate, false)) :
0 ignored issues
show
Bug introduced by
It seems like isRegisteredCandidate() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
126 107
                        if ( $linkCount === 0 || ($linkCount === 1 && reset($links) === $this) ) :
127 107
                            $mirror[$rank][$choiceKey] = $this->_Candidates[$this->getCandidateKey((string) $candidate)];
128 107
                            $change = true;
129
                        else :
130 125
                            return false;
131
                        endif;
132
                    endif;
133
                endif;
134
            endforeach;
135
        endforeach;
136
137 125
        if ($change) :
138 107
            $vote->setRanking(  $mirror,
139 107
                                ( abs($vote->getTimestamp() - microtime(true)) > 0.5 ) ? ($vote->getTimestamp() + 0.001) : null
140
            );
141
        endif;
142
143 125
        return true;
144
    }
145
146
    // Write a new vote
147 125
    protected function registerVote (Vote $vote, $tag = null) : Vote
148
    {
149
        // Vote identifiant
150 125
        $vote->addTags($tag);
151
        
152
        // Register
153
        try {
154 125
            $vote->registerLink($this);
155 125
            $this->_Votes[] = $vote;
156 1
        } catch (CondorcetException $e) {
157
            // Security : Check if vote object not already register
158 1
            throw new CondorcetException(31);
159
        }
160
161 125
        return $vote;
162
    }
163
164 5
    public function removeVote ($in, bool $with = true) : array
165
    {    
166 5
        $rem = [];
167
168 5
        if ($in instanceof Vote) :
169 4
            $key = $this->getVoteKey($in);
170 4
            if ($key !== false) :
171 4
                $this->_Votes[$key]->destroyLink($this);
172
173 4
                $rem[] = $this->_Votes[$key];
174
175 4
                unset($this->_Votes[$key]);
176
            endif;
177
        else :
178
            // Prepare Tags
179 3
            $tag = VoteUtil::tagsConvert($in);
180
181
            // Deleting
182 3
            foreach ($this->getVotesList($tag, $with) as $key => $value) :
183 3
                $this->_Votes[$key]->destroyLink($this);
184
185 3
                $rem[] = $this->_Votes[$key];
186
187 3
                unset($this->_Votes[$key]);
188
            endforeach;
189
190
        endif;
191
192 5
        return $rem;
193
    }
194
195
196
/////////// PARSE VOTE ///////////
197
198
    // Return the well formated vote to use.
199 125
    protected function prepareVoteInput (&$vote, $tag = null) : void
200
    {
201 125
        if (!($vote instanceof Vote)) :
202 18
            $vote = new Vote ($vote, $tag);
203
        endif;
204
205
        // Check array format && Make checkVoteCandidate
206 125
        if ( !$this->checkVoteCandidate($vote) ) :
207
            throw new CondorcetException(5);
208
        endif;
209 125
    }
210
211 2
    public function jsonVotes (string $input) : array
212
    {
213 2
        $input = CondorcetUtil::prepareJson($input);
214
215
            //////
216
217 1
        $adding = [];
218
219 1
        foreach ($input as $record) :
220 1
            if (empty($record['vote'])) :
221 1
                continue;
222
            endif;
223
224 1
            $tags = (!isset($record['tag'])) ? null : $record['tag'];
225 1
            $multi = (!isset($record['multi'])) ? 1 : $record['multi'];
226
227 1
            $adding_predicted_count = count($adding) + $multi;
228
229 1 View Code Duplication
            if (self::$_maxVoteNumber && self::$_maxVoteNumber < ($this->countVotes() + $adding_predicted_count)) :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
230
                throw new CondorcetException(16, self::$_maxParseIteration);
231
            endif;
232
233 1 View Code Duplication
            if (self::$_maxParseIteration !== null && $adding_predicted_count >= self::$_maxParseIteration) :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
234
                throw new CondorcetException(12, self::$_maxParseIteration);
235
            endif;
236
237 1
            for ($i = 0; $i < $multi; $i++) :
238 1
                $adding[] = new Vote ($record['vote'], $tags);
239
            endfor;
240
        endforeach;
241
242 1
        foreach ($adding as $oneNewVote) :
243 1
            $this->addVote($oneNewVote);
244
        endforeach;
245
246 1
        return $adding;
247
    }
248
249 89
    public function parseVotes (string $input, bool $isFile = false) : array
250
    {
251 89
        $input = CondorcetUtil::prepareParse($input, $isFile);
252
253
        // Check each lines
254 89
        $adding = [];
255 89
        foreach ($input as $line) :
256
            // Empty Line
257 89
            if (empty($line)) :
258 78
                continue;
259
            endif;
260
261
            // Multiples
262 89
            $multiple = VoteUtil::parseAnalysingOneLine(mb_strpos($line, '*'),$line);
263
264
            // Vote Weight
265 89
            $weight = VoteUtil::parseAnalysingOneLine(mb_strpos($line, '^'),$line);
266
267
            // Tags + vote
268 89
            if (mb_strpos($line, '||') !== false) :
269 6
                $data = explode('||', $line);
270
271 6
                $vote = $data[1];
272 6
                $tags = $data[0];
273
            // Vote without tags
274
            else :
275 88
                $vote = $line;
276 88
                $tags = null;
277
            endif;
278
279 89
            $adding_predicted_count = count($adding) + $multiple;
280
281 89 View Code Duplication
            if (self::$_maxVoteNumber && self::$_maxVoteNumber < ($this->countVotes() + $adding_predicted_count)) :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
282 1
                throw new CondorcetException(16, self::$_maxParseIteration);
283
            endif;
284
285 89 View Code Duplication
            if (self::$_maxParseIteration !== null && $adding_predicted_count >= self::$_maxParseIteration) :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
286 2
                throw new CondorcetException(12, self::$_maxParseIteration);
287
            endif;
288
289
            // addVote
290 88
            for ($i = 0; $i < $multiple; $i++) :
291 88
                $newVote = new Vote ($vote, $tags);
292 88
                $newVote->setWeight($weight);
293
294 88
                $adding[] = $newVote;
295
            endfor;
296
        endforeach;
297
298 87
        foreach ($adding as $oneNewVote) :
299 87
            $this->addVote($oneNewVote);
300
        endforeach;
301
302 87
        return $adding;
303
    }
304
305
}
306