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 Client 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 Client, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
40 | class Client extends GuzzleClient implements ClientInterface |
||
41 | { |
||
42 | const USER_AGENT = 'wonnova-php-sdk'; |
||
43 | const TOKEN_KEY = 'wonnova_auth_token'; |
||
44 | |||
45 | /** |
||
46 | * @var CredentialsInterface |
||
47 | */ |
||
48 | protected $credentials; |
||
49 | /** |
||
50 | * @var string |
||
51 | */ |
||
52 | protected $language; |
||
53 | /** |
||
54 | * @var Cache |
||
55 | */ |
||
56 | protected $cache; |
||
57 | /** |
||
58 | * @var Serializer |
||
59 | */ |
||
60 | protected $serializer; |
||
61 | /** |
||
62 | * @var TokenInterface |
||
63 | */ |
||
64 | protected $token; |
||
65 | /** |
||
66 | * @var string |
||
67 | */ |
||
68 | protected $tokenCacheKey; |
||
69 | |||
70 | /** |
||
71 | * @param CredentialsInterface $credentials |
||
72 | * @param string $language |
||
73 | * @param Cache $cache |
||
74 | * @param null $baseUrl |
||
75 | */ |
||
76 | 43 | public function __construct( |
|
105 | |||
106 | /** |
||
107 | * Performs a connection to defined endpoint with defined options |
||
108 | * |
||
109 | * @param string $method |
||
110 | * @param Route|string $route |
||
111 | * @param array $options |
||
112 | * @return \GuzzleHttp\Message\ResponseInterface |
||
113 | * @throws \Wonnova\SDK\Exception\ServerException |
||
114 | * @throws \Wonnova\SDK\Exception\InvalidRequestException |
||
115 | * @throws \Wonnova\SDK\Exception\NotFoundException |
||
116 | * @throws \Wonnova\SDK\Exception\RuntimeException |
||
117 | */ |
||
118 | 42 | public function connect($method, $route, array $options = []) |
|
186 | |||
187 | /** |
||
188 | * Resets the token so that it can be reinitialized. |
||
189 | * This has to be used when current token has expired or is invalid |
||
190 | */ |
||
191 | 1 | private function resetToken() |
|
196 | |||
197 | /** |
||
198 | * Performs authentication caching the auth token |
||
199 | */ |
||
200 | 41 | private function authenticate() |
|
212 | |||
213 | /** |
||
214 | * @param array $options |
||
215 | * @return array |
||
216 | */ |
||
217 | 42 | protected function processOptionsWithDefaults(array $options) |
|
226 | |||
227 | /** |
||
228 | * Fetches a route and maps a resource list of models under provided key |
||
229 | * |
||
230 | * @param Route|string $route |
||
231 | * @param $resourceKey |
||
232 | * @param $resourceClass |
||
233 | * @return ArrayCollection |
||
234 | */ |
||
235 | 11 | protected function getResourceCollection($route, $resourceKey, $resourceClass) |
|
245 | |||
246 | /** |
||
247 | * Returns users list |
||
248 | * |
||
249 | * @return Collection|User[] |
||
250 | */ |
||
251 | 7 | View Code Duplication | public function getUsers() |
261 | |||
262 | /** |
||
263 | * Returns information about certain user |
||
264 | * |
||
265 | * @param $userId |
||
266 | * @return User |
||
267 | */ |
||
268 | 3 | View Code Duplication | public function getUser($userId) |
276 | |||
277 | /** |
||
278 | * Creates provided user |
||
279 | * |
||
280 | * @param User $user |
||
281 | */ |
||
282 | 1 | View Code Duplication | public function createUser(User $user) |
292 | |||
293 | /** |
||
294 | * Updates provided user |
||
295 | * |
||
296 | * @param User $user |
||
297 | */ |
||
298 | 2 | public function updateUser(User $user) |
|
314 | |||
315 | /** |
||
316 | * |
||
317 | * |
||
318 | * @param User|string $user A User model or userId |
||
319 | * @return Collection|Notification[] |
||
320 | */ |
||
321 | 1 | View Code Duplication | public function getUserNotifications($user) |
328 | |||
329 | /** |
||
330 | * Returns the list of badges that certain user has won |
||
331 | * |
||
332 | * @param User|string $user A User model or userId |
||
333 | * @return Collection|Badge[] |
||
334 | */ |
||
335 | 1 | View Code Duplication | public function getUserBadges($user) |
342 | |||
343 | /** |
||
344 | * Returns the number of achievements of each type for certain user |
||
345 | * |
||
346 | * @param User|string $user A User model or userId |
||
347 | * @param array|string $types List of types in a comma-separated string or array. |
||
348 | * All the types will be returned by default |
||
349 | * @return Collection|Achievement[] |
||
350 | */ |
||
351 | 1 | public function getUserAchievements($user, $types = []) |
|
363 | |||
364 | /** |
||
365 | * Returns the list of steps in a quest telling if certain user has already completed them |
||
366 | * |
||
367 | * @param User|string $user A User model or userId |
||
368 | * @param string $questCode |
||
369 | * @return Collection|QuestStep[] |
||
370 | */ |
||
371 | 1 | View Code Duplication | public function getUserProgressInQuest($user, $questCode) |
379 | |||
380 | /** |
||
381 | * Returns the list of created quests |
||
382 | * |
||
383 | * @return Collection|Quest[] |
||
384 | */ |
||
385 | 1 | public function getQuests() |
|
389 | |||
390 | /** |
||
391 | * Returns all the quests with which a user is involved with, including the list of their steps |
||
392 | * |
||
393 | * @param User|string $user A User model or userId |
||
394 | * @return Collection|Quest[] |
||
395 | */ |
||
396 | 1 | View Code Duplication | public function getUserStatusInQuests($user) |
403 | |||
404 | /** |
||
405 | * @return Collection|Level[] |
||
406 | */ |
||
407 | 1 | public function getLevels() |
|
411 | |||
412 | /** |
||
413 | * Returns the level of a user in certain scenario |
||
414 | * |
||
415 | * @param User|string $user A User model or userId |
||
416 | * @param string|null $scenarioCode |
||
417 | * @return Level |
||
418 | */ |
||
419 | 2 | public function getUserLevelInScenario($user, $scenarioCode = null) |
|
438 | |||
439 | /** |
||
440 | * Returns the list of top teams ordered by total score of their members |
||
441 | * If a user is provided, the list will include the team of that user, even if it is not in the top list |
||
442 | * |
||
443 | * @param int|null $maxCount Maximum number of results |
||
444 | * @param User|string|null $user A User model or userId |
||
445 | * @return Collection|Team[] |
||
446 | */ |
||
447 | 2 | public function getTeamsLeaderboard($maxCount = null, $user = null) |
|
466 | |||
467 | /** |
||
468 | * Returns the top rated items |
||
469 | * |
||
470 | * @param int $maxCount |
||
471 | * @return Collection|Item[] |
||
472 | */ |
||
473 | 1 | public function getItemsLeaderboard($maxCount = 6) |
|
479 | |||
480 | /** |
||
481 | * Rates an item increasing its score and setting the rate from certain user. |
||
482 | * |
||
483 | * @param User|string $user a User model or userId |
||
484 | * @param Item|string $item an Item model or itemId |
||
485 | * @param int $score |
||
486 | * @return Item |
||
487 | */ |
||
488 | 1 | public function rateItem($user, $item, $score = 0) |
|
512 | |||
513 | /** |
||
514 | * Rates an item increasing its score and setting the rate from certain user. |
||
515 | * |
||
516 | * @param User|string $user a User model or userId |
||
517 | * @param array $items an array of Item models |
||
518 | * @return ArrayCollection |
||
519 | */ |
||
520 | 1 | public function rateSeveralItems($user, array $items) |
|
544 | |||
545 | /** |
||
546 | * Deletes certain item |
||
547 | * |
||
548 | * @param Item|string $item an Item model or itemId |
||
549 | * @return void |
||
550 | */ |
||
551 | 1 | View Code Duplication | public function deleteItem($item) |
558 | |||
559 | /** |
||
560 | * Resets an item's score to zero |
||
561 | * |
||
562 | * @param Item|string $item an Item model or itemId |
||
563 | * @return void |
||
564 | */ |
||
565 | 1 | View Code Duplication | public function resetItemScore($item) |
572 | |||
573 | /** |
||
574 | * Returns a partial model of certain user defined by its userId |
||
575 | * By calling this method, only the properties username, fullName, avatar and score of the User will be popullated, |
||
576 | * as well as the provided userId |
||
577 | * |
||
578 | * @param $userId |
||
579 | * @return User |
||
580 | */ |
||
581 | 1 | public function getUserData($userId) |
|
595 | |||
596 | /** |
||
597 | * Performs an action notification from certain user |
||
598 | * |
||
599 | * @param User|string $user A User model or userId |
||
600 | * @param string $actionCode |
||
601 | * @param Item|string $item An Item model or itemId |
||
602 | * @param array $categories |
||
603 | * @return void |
||
604 | */ |
||
605 | 3 | public function notifyAction($user, $actionCode, $item = null, array $categories = []) |
|
626 | |||
627 | /** |
||
628 | * Performs an action notification from certain user |
||
629 | * |
||
630 | * @param User|string $user A User model or userId |
||
631 | * @param array $actions array of Action objects or strings |
||
632 | * @return void |
||
633 | */ |
||
634 | 4 | public function notifySeveralActions($user, array $actions) |
|
660 | |||
661 | /** |
||
662 | * Performs an interaction notification between two users |
||
663 | * |
||
664 | * @param User|string $user A User model or userId |
||
665 | * @param User|string $targetUser A User model or userId |
||
666 | * @param string $interactionCode |
||
667 | * @param Item|null $item An Item model or itemId |
||
668 | * @param array $categories |
||
669 | * @return void |
||
670 | */ |
||
671 | 3 | public function notifyInteraction($user, $targetUser, $interactionCode, $item = null, array $categories = []) |
|
693 | |||
694 | /** |
||
695 | * Returns the number of times a user has performed certain action |
||
696 | * |
||
697 | * @param User|string $user A User model or userId |
||
698 | * @param string $actionCode |
||
699 | * @return int |
||
700 | */ |
||
701 | 1 | View Code Duplication | public function getUserActionOccurrences($user, $actionCode) |
710 | |||
711 | /** |
||
712 | * Returns information about the status of an interactionaccording to its limits |
||
713 | * |
||
714 | * @param User|string $user A User model or userId |
||
715 | * @param User|string $targetUser A User model or userId |
||
716 | * @param string $interactionCode |
||
717 | * @param Item|string $item An Item model or itemId |
||
718 | * @return array |
||
719 | */ |
||
720 | 1 | public function getInteractionStatus($user, $targetUser, $interactionCode, $item) |
|
748 | |||
749 | /** |
||
750 | * Returns the list of most recent updates for certain user |
||
751 | * |
||
752 | * @param User|string $user A User model or userId |
||
753 | * @param int $maxCount |
||
754 | * @return Collection|Update[] |
||
755 | */ |
||
756 | 1 | public function getUserLastUpdates($user, $maxCount = null) |
|
767 | } |
||
768 |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.