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 PostVote 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 PostVote, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
8 | class PostVote extends Game implements ServiceManagerAwareInterface |
||
9 | { |
||
10 | protected $postvoteMapper; |
||
11 | protected $postvoteformMapper; |
||
12 | protected $postVotePostMapper; |
||
13 | protected $postVoteVoteMapper; |
||
14 | protected $postVoteCommentMapper; |
||
15 | protected $postVotePostElementMapper; |
||
16 | |||
17 | public function getGameEntity() |
||
21 | |||
22 | public function getPath($post) |
||
36 | |||
37 | public function getMediaUrl($post) |
||
44 | |||
45 | /** |
||
46 | * @param boolean $entry |
||
47 | */ |
||
48 | public function checkPost($entry) |
||
62 | |||
63 | public function uploadFileToPost($data, $game, $user) |
||
64 | { |
||
65 | $result = false; |
||
66 | $entry = $this->findLastActiveEntry($game, $user); |
||
67 | |||
68 | if (!$entry) { |
||
69 | return '0'; |
||
70 | } |
||
71 | |||
72 | $post = $this->checkPost($entry); |
||
73 | $path = $this->getPath($post); |
||
74 | $media_url = $this->getMediaUrl($post); |
||
75 | |||
76 | $key = key($data); |
||
77 | $uploadFile = $this->uploadFile($path, $data[$key]); |
||
78 | |||
79 | if ($uploadFile) { |
||
80 | $postElement = $this->getPostVotePostElementMapper()->findOneBy(array('post' => $post, 'name' => $key)); |
||
81 | if (! $postElement) { |
||
82 | $postElement = new \PlaygroundGame\Entity\PostVotePostElement(); |
||
83 | } |
||
84 | $postElement->setName($key); |
||
85 | $postElement->setPosition(0); |
||
86 | $postElement->setValue($media_url.$uploadFile); |
||
87 | $postElement->setPost($post); |
||
88 | $postElement = $this->getPostVotePostElementMapper()->insert($postElement); |
||
89 | |||
90 | $result = $media_url.$uploadFile; |
||
91 | } |
||
92 | |||
93 | return $result; |
||
94 | } |
||
95 | |||
96 | public function deleteFilePosted($data, $game, $user) |
||
121 | |||
122 | /** |
||
123 | * |
||
124 | * @param array $data |
||
125 | * @return \PlaygroundGame\Entity\Game |
||
126 | */ |
||
127 | public function createPost(array $data, $game, $user, $form) |
||
128 | { |
||
129 | $postvotePostMapper = $this->getPostVotePostMapper(); |
||
130 | $postVotePostElementMapper = $this->getPostVotePostElementMapper(); |
||
131 | |||
132 | $entry = $this->findLastActiveEntry($game, $user); |
||
133 | |||
134 | if (!$entry) { |
||
135 | return false; |
||
136 | } |
||
137 | |||
138 | $post = $this->checkPost($entry); |
||
139 | $path = $this->getPath($post); |
||
140 | $media_url = $this->getMediaUrl($post); |
||
141 | $position=1; |
||
142 | |||
143 | foreach ($data as $name => $value) { |
||
144 | $postElement = $postVotePostElementMapper->findOneBy(array('post' => $post, 'name' => $name)); |
||
145 | if (! $postElement) { |
||
146 | $postElement = new \PlaygroundGame\Entity\PostVotePostElement(); |
||
147 | } |
||
148 | $postElement->setName($name); |
||
149 | $postElement->setPosition($position); |
||
150 | |||
151 | if (is_array($value) && isset($value['tmp_name'])) { |
||
152 | // The file upload has been done in ajax but some weird bugs remain without it |
||
153 | |||
154 | if (! $value['error']) { |
||
155 | ErrorHandler::start(); |
||
156 | $value['name'] = $this->fileNewname($path, $value['name'], true); |
||
157 | move_uploaded_file($value['tmp_name'], $path . $value['name']); |
||
158 | $image = $this->getServiceManager()->get('playgroundcore_image_service'); |
||
159 | $image->setImage($path . $value['name']); |
||
160 | |||
161 | if ($image->canCorrectOrientation()) { |
||
162 | $image->correctOrientation()->save(); |
||
163 | } |
||
164 | $postElement->setValue($media_url . $value['name']); |
||
165 | |||
166 | if (class_exists("Imagick")) { |
||
167 | $ext = pathinfo($value['name'], PATHINFO_EXTENSION); |
||
168 | $img = new \Imagick($path . $value['name']); |
||
169 | $img->cropThumbnailImage(100, 100); |
||
170 | $img->setImageCompression(\Imagick::COMPRESSION_JPEG); |
||
171 | $img->setImageCompressionQuality(75); |
||
172 | // Strip out unneeded meta data |
||
173 | $img->stripImage(); |
||
174 | $img->writeImage($path . str_replace('.'.$ext, '-thumbnail.'.$ext, $value['name'])); |
||
175 | ErrorHandler::stop(true); |
||
176 | } |
||
177 | } |
||
178 | } elseif (is_array($value) || $form->get($name) instanceof \Zend\Form\Element\Select) { |
||
179 | $arValues = $form->get($name)->getValueOptions(); |
||
180 | $postElement->setValue($arValues[$value[0]]); |
||
181 | } elseif (!empty($value)) { |
||
182 | $postElement->setValue($value); |
||
183 | } |
||
184 | $postElement->setPost($post); |
||
185 | $postVotePostElementMapper->insert($postElement); |
||
186 | $position++; |
||
187 | } |
||
188 | |||
189 | $postvotePostMapper->update($post); |
||
190 | |||
191 | // If a preview step is not proposed, I confirmPost on this step |
||
192 | $steps = $game->getStepsArray(); |
||
193 | $previewKey = array_search('preview', $steps); |
||
194 | if (!$previewKey) { |
||
195 | $post = $this->confirmPost($game, $user); |
||
196 | } |
||
197 | |||
198 | $this->getEventManager()->trigger(__FUNCTION__ . '.post', $this, array( |
||
199 | 'user' => $user, |
||
200 | 'game' => $game, |
||
201 | 'post' => $post, |
||
202 | 'entry' => $entry |
||
203 | )); |
||
204 | |||
205 | return $post; |
||
206 | } |
||
207 | |||
208 | /** |
||
209 | * |
||
210 | * @return \PlaygroundGame\Entity\Game |
||
211 | */ |
||
212 | public function confirmPost($game, $user) |
||
213 | { |
||
214 | $postvotePostMapper = $this->getPostVotePostMapper(); |
||
215 | |||
216 | $entryMapper = $this->getEntryMapper(); |
||
217 | $entry = $this->findLastActiveEntry($game, $user); |
||
218 | |||
219 | if (!$entry) { |
||
220 | return false; |
||
221 | } |
||
222 | |||
223 | $post = $postvotePostMapper->findOneBy(array('entry' => $entry)); |
||
224 | |||
225 | if (! $post) { |
||
226 | return false; |
||
227 | } |
||
228 | |||
229 | // The post is confirmed by user. I update the status and close the associated entry |
||
230 | // Post are validated by default, unless pre-moderation is enable for the game |
||
231 | if ($game->getModerationType()) { |
||
232 | $post->setStatus(1); |
||
233 | } else { |
||
234 | $post->setStatus(2); |
||
235 | } |
||
236 | |||
237 | $postvotePostMapper->update($post); |
||
238 | |||
239 | $entry->setActive(0); |
||
240 | $entryMapper->update($entry); |
||
241 | |||
242 | $this->getEventManager()->trigger(__FUNCTION__ . '.post', $this, array( |
||
243 | 'user' => $user, |
||
244 | 'game' => $game, |
||
245 | 'entry' => $entry, |
||
246 | 'post' => $post |
||
247 | )); |
||
248 | |||
249 | if ($user) { |
||
250 | // send mail for participation |
||
251 | $this->sendGameMail($game, $user, $post, 'postvote'); |
||
252 | } |
||
253 | |||
254 | return $post; |
||
255 | } |
||
256 | |||
257 | /** |
||
258 | * |
||
259 | * This service is ready for all types of games |
||
260 | * |
||
261 | * @param array $data |
||
262 | * @return \PlaygroundGame\Entity\Game |
||
263 | */ |
||
264 | View Code Duplication | public function createForm(array $data, $game, $form = null) |
|
294 | |||
295 | public function findArrayOfValidatedPosts($game, $filter, $search = '') |
||
375 | |||
376 | public function addVote($user, $ipAddress, $post) |
||
408 | |||
409 | public function addComment($user, $ipAddress, $post, $message = '') |
||
410 | { |
||
411 | $postvoteCommentMapper = $this->getPostVoteCommentMapper(); |
||
433 | |||
434 | /** |
||
435 | * Get all comments for this game |
||
436 | */ |
||
437 | public function getCommentsForPostvote($postvote) |
||
444 | |||
445 | /** |
||
446 | * Get all comments for this post |
||
447 | */ |
||
448 | public function getCommentsForPost($post) |
||
455 | |||
456 | public function removeComment($user, $ipAddress, $messageId) |
||
473 | |||
474 | public function getEntriesHeader($game) |
||
490 | |||
491 | View Code Duplication | public function getEntriesQuery($game) |
|
529 | |||
530 | /** |
||
531 | * getGameEntries : All entries of a game |
||
532 | * |
||
533 | * @return Array of PlaygroundGame\Entity\Game |
||
534 | */ |
||
535 | public function getGameEntries($header, $entries, $game) |
||
563 | |||
564 | public function getPostVoteFormMapper() |
||
572 | |||
573 | public function setPostVoteFormMapper($postvoteformMapper) |
||
579 | |||
580 | public function getPostVotePostElementMapper() |
||
590 | |||
591 | public function setPostVotePostElementMapper($postVotePostElementMapper) |
||
597 | |||
598 | public function getPostVoteVoteMapper() |
||
606 | |||
607 | public function setPostVoteVoteMapper($postVoteVoteMapper) |
||
613 | |||
614 | public function getPostVoteCommentMapper() |
||
622 | |||
623 | public function setPostVoteCommentMapper($postVoteCommentMapper) |
||
629 | |||
630 | public function getPostVotePostMapper() |
||
638 | |||
639 | public function setPostVotePostMapper($postVotePostMapper) |
||
645 | |||
646 | public function getPostVoteMapper() |
||
654 | |||
655 | /** |
||
656 | * setQuizQuestionMapper |
||
657 | * |
||
658 | * @return PostVote |
||
659 | */ |
||
660 | public function setPostVoteMapper($postvoteMapper) |
||
666 | } |
||
667 |
Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.