Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like VotesProcess often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use VotesProcess, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 19 | { |
||
| 20 | |||
| 21 | /////////// CONSTRUCTOR /////////// |
||
| 22 | |||
| 23 | // Data and global options |
||
| 24 | protected $_Votes; // Votes list |
||
| 25 | protected $_voteFastMode = false; // When parsing vote, avoid unnecessary checks |
||
| 26 | |||
| 27 | |||
| 28 | /////////// VOTES LIST /////////// |
||
| 29 | |||
| 30 | // How many votes are registered ? |
||
| 31 | 12 | public function countVotes ($tags = null, bool $with = true) : int |
|
| 35 | |||
| 36 | 1 | public function countInvalidVoteWithConstraints () : int |
|
| 40 | |||
| 41 | 1 | public function countValidVoteWithConstraints () : int |
|
| 45 | |||
| 46 | // Sum votes weight |
||
| 47 | 2 | public function sumVotesWeight () : int |
|
| 51 | |||
| 52 | 6 | public function sumValidVotesWeightWithConstraints () : int |
|
| 56 | |||
| 57 | // Get the votes registered list |
||
| 58 | 13 | public function getVotesList ($tags = null, bool $with = true) : array |
|
| 62 | |||
| 63 | 5 | public function getVotesListAsString () : string |
|
| 67 | |||
| 68 | 102 | public function getVotesManager () : VotesManager |
|
| 72 | |||
| 73 | 3 | public function getVotesListGenerator ($tags = null, bool $with = true) : \Generator |
|
| 77 | |||
| 78 | 9 | public function getVoteKey (Vote $vote) : ?int |
|
| 82 | |||
| 83 | |||
| 84 | /////////// ADD & REMOVE VOTE /////////// |
||
| 85 | |||
| 86 | // 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. |
||
| 87 | 129 | public function addVote ($vote, $tags = null) : Vote |
|
| 99 | |||
| 100 | 7 | public function prepareUpdateVote (Vote $existVote) : void |
|
| 104 | |||
| 105 | 7 | public function finishUpdateVote (Vote $existVote) : void |
|
| 113 | |||
| 114 | 129 | public function checkVoteCandidate (Vote $vote) : bool |
|
| 140 | |||
| 141 | 129 | public function convertRankingCandidates (array &$ranking) : bool |
|
| 158 | |||
| 159 | // Write a new vote |
||
| 160 | 129 | protected function registerVote (Vote $vote, $tag = null) : Vote |
|
| 176 | |||
| 177 | 4 | public function removeVotes (Vote $votes_input) : bool |
|
| 194 | |||
| 195 | 4 | public function removeVotesByTags ($tags, bool $with = true) : array |
|
| 214 | |||
| 215 | |||
| 216 | /////////// PARSE VOTE /////////// |
||
| 217 | |||
| 218 | // Return the well formated vote to use. |
||
| 219 | 129 | protected function prepareVoteInput (&$vote, $tag = null) : void |
|
| 230 | |||
| 231 | 2 | public function addVotesFromJson (string $input) : int |
|
| 281 | |||
| 282 | 91 | public function parseVotes (string $input, bool $isFile = false) : int |
|
| 283 | { |
||
| 284 | 91 | $input = CondorcetUtil::prepareParse($input, $isFile); |
|
| 285 | |||
| 286 | 91 | $adding = []; |
|
| 287 | 91 | $count = 0; |
|
| 288 | |||
| 289 | 91 | foreach ($input as $line) : |
|
| 290 | // Empty Line |
||
| 291 | 91 | if (empty($line)) : |
|
| 292 | 79 | continue; |
|
| 293 | endif; |
||
| 294 | |||
| 295 | // Multiples |
||
| 296 | 91 | $multiple = VoteUtil::parseAnalysingOneLine(mb_strpos($line, '*'),$line); |
|
| 297 | |||
| 298 | // Vote Weight |
||
| 299 | 91 | $weight = VoteUtil::parseAnalysingOneLine(mb_strpos($line, '^'),$line); |
|
| 300 | |||
| 301 | // Tags + vote |
||
| 302 | 91 | if (mb_strpos($line, '||') !== false) : |
|
| 303 | 7 | $data = explode('||', $line); |
|
| 304 | |||
| 305 | 7 | $vote = $data[1]; |
|
| 306 | 7 | $tags = $data[0]; |
|
| 307 | // Vote without tags |
||
| 308 | else : |
||
| 309 | 89 | $vote = $line; |
|
| 310 | 89 | $tags = null; |
|
| 311 | endif; |
||
| 312 | |||
| 313 | 91 | $adding_predicted_count = $count + $multiple; |
|
| 314 | |||
| 315 | 91 | if (self::$_maxVoteNumber && self::$_maxVoteNumber < ($this->countVotes() + $adding_predicted_count)) : |
|
| 316 | 1 | throw new CondorcetException(16, (string) self::$_maxParseIteration); |
|
| 317 | endif; |
||
| 318 | |||
| 319 | 91 | if (self::$_maxParseIteration !== null && $adding_predicted_count >= self::$_maxParseIteration) : |
|
| 320 | 2 | throw new CondorcetException(12, (string) self::$_maxParseIteration); |
|
| 321 | endif; |
||
| 349 |
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
The trait
Idableprovides a methodequalsIdthat in turn relies on the methodgetId(). 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.