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 TwitchSDK 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 TwitchSDK, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
15 | class TwitchSDK |
||
16 | { |
||
17 | /** @var array */ |
||
18 | protected $auth_config = false; |
||
19 | |||
20 | /** @var integer Set timeout default. */ |
||
21 | public $timeout = 30; |
||
22 | |||
23 | /** @var integer Set connect timeout */ |
||
24 | public $connect_timeout = 30; |
||
25 | |||
26 | /** @var boolean Verify SSL Cert */ |
||
27 | public $ssl_verifypeer = false; |
||
28 | |||
29 | /** @var integer Contains the last HTTP status code returned */ |
||
30 | public $http_code = 0; |
||
31 | |||
32 | /** @var array Contains the last Server headers returned */ |
||
33 | public $http_header = array(); |
||
34 | |||
35 | /** @var array Contains the last HTTP headers returned */ |
||
36 | public $http_info = array(); |
||
37 | |||
38 | /** @var boolean Throw cURL errors */ |
||
39 | public $throw_curl_errors = true; |
||
40 | |||
41 | /** @var string Set the useragnet */ |
||
42 | private $useragent = 'ritero TwitchSDK dev-0.4.*'; |
||
43 | |||
44 | /** @var string */ |
||
45 | private $clientId; |
||
46 | |||
47 | /** |
||
48 | * TwitchAPI URI's |
||
49 | */ |
||
50 | const URL_TWITCH = 'https://api.twitch.tv/kraken/'; |
||
51 | const URI_USER = 'users/'; |
||
52 | const URI_USER_FOLLOWS_CHANNEL = '/users/%s/follows/channels'; |
||
53 | const URI_USER_FOLLOW_RELATION = '/users/%s/follows/channels/%s'; |
||
54 | const URI_CHANNEL = 'channels/'; |
||
55 | const URI_CHANNEL_FOLLOWS = 'channels/%s/follows'; |
||
56 | const URI_CHANNEL_SUBSCRIPTIONS = 'channels/%s/subscriptions'; |
||
57 | const URI_STREAM = 'streams/'; |
||
58 | const URI_STREAM_SUMMARY = 'streams/summary/'; |
||
59 | const URI_STREAMS_FEATURED = 'streams/featured/'; |
||
60 | const URI_STREAMS_SEARCH = 'search/streams/'; |
||
61 | const URI_GAMES_SEARCH = 'search/games/'; |
||
62 | const URI_VIDEO = 'videos/'; |
||
63 | const URI_CHAT = 'chat/'; |
||
64 | const URI_CHAT_EMOTICONS = 'chat/emoticons'; |
||
65 | const URI_GAMES_TOP = 'games/top/'; |
||
66 | const URI_AUTH = 'oauth2/authorize'; |
||
67 | const URI_AUTH_TOKEN = 'oauth2/token'; |
||
68 | const URI_USER_AUTH = 'user'; |
||
69 | const URI_CHANNEL_AUTH = 'channel'; |
||
70 | const URI_CHANNEL_EDITORS_AUTH = 'channels/%s/editors'; |
||
71 | const URI_STREAMS_FOLLOWED_AUTH = 'streams/followed'; |
||
72 | const URI_TEAMS = 'teams/'; |
||
73 | |||
74 | /** |
||
75 | * For teams API we have different URI's and |
||
76 | * use HTTP instead of HTTPS |
||
77 | */ |
||
78 | const URL_TWITCH_TEAM = "http://api.twitch.tv/api/team/"; |
||
79 | |||
80 | /** |
||
81 | * @return string |
||
82 | */ |
||
83 | public function getClientId() |
||
87 | |||
88 | /** |
||
89 | * @param string $clientId |
||
90 | */ |
||
91 | public function setClientId($clientId) |
||
95 | |||
96 | /** |
||
97 | * SDK constructor |
||
98 | * @param array |
||
99 | * @throws \ritero\SDK\TwitchTV\TwitchException |
||
100 | * @throws \InvalidArgumentException |
||
101 | */ |
||
102 | public function __construct($config = array()) |
||
122 | |||
123 | /** |
||
124 | * Basic information about the API and authentication status |
||
125 | * @param string |
||
126 | * @return stdClass |
||
127 | */ |
||
128 | public function status($token = null) |
||
142 | |||
143 | /** |
||
144 | * Get the specified user |
||
145 | * @param string |
||
146 | * @return stdClass |
||
147 | */ |
||
148 | public function userGet($username) |
||
152 | |||
153 | /** |
||
154 | * Get a user's list of followed channels |
||
155 | * @param integer |
||
156 | * @param integer |
||
157 | * @param integer |
||
158 | * @return stdClass |
||
159 | */ |
||
160 | View Code Duplication | public function userFollowChannels($user, $limit = null, $offset = null) |
|
169 | |||
170 | /** |
||
171 | * Get the status of a follow relationship |
||
172 | * @param string |
||
173 | * @param string |
||
174 | * @return stdClass |
||
175 | */ |
||
176 | public function userFollowRelationship($user, $channel) |
||
180 | |||
181 | /** |
||
182 | * Set user to follow given channel |
||
183 | * @param string |
||
184 | * @param string |
||
185 | * @param string |
||
186 | * @return stdClass |
||
187 | */ |
||
188 | View Code Duplication | public function userFollowChannel($user, $channel, $userToken) |
|
196 | |||
197 | /** |
||
198 | * Set user to unfollow given channel |
||
199 | * @param string |
||
200 | * @param string |
||
201 | * @param string |
||
202 | * @return stdClass |
||
203 | */ |
||
204 | View Code Duplication | public function userUnfollowChannel($user, $channel, $userToken) |
|
212 | |||
213 | /** |
||
214 | * Get the specified channel |
||
215 | * @param string |
||
216 | * @return stdClass |
||
217 | */ |
||
218 | public function channelGet($channel) |
||
222 | |||
223 | /** |
||
224 | * Get the specified team |
||
225 | * @param string |
||
226 | * @return stdClass |
||
227 | */ |
||
228 | public function teamGet($teamName) |
||
232 | |||
233 | /** |
||
234 | * |
||
235 | */ |
||
236 | public function teamMembersAll($teamName) |
||
240 | |||
241 | /** |
||
242 | * Returns an array of users who follow the specified channel |
||
243 | * @param string |
||
244 | * @param integer |
||
245 | * @param integer |
||
246 | * @return stdClass |
||
247 | */ |
||
248 | View Code Duplication | public function channelFollows($channel, $limit = null, $offset = null) |
|
257 | |||
258 | /** |
||
259 | * Get the specified channel's stream |
||
260 | * @param string |
||
261 | * @return stdClass |
||
262 | */ |
||
263 | public function streamGet($channel) |
||
267 | |||
268 | /** |
||
269 | * Search live streams |
||
270 | * @param string |
||
271 | * @param integer |
||
272 | * @param integer |
||
273 | * @return stdClass |
||
274 | */ |
||
275 | View Code Duplication | public function streamSearch($query, $limit = null, $offset = null) |
|
285 | |||
286 | /** |
||
287 | * Search games |
||
288 | * @param string |
||
289 | * @param integer |
||
290 | * @param integer |
||
291 | * @return stdClass |
||
292 | */ |
||
293 | View Code Duplication | public function gamesSearch($query, $live = true) |
|
303 | |||
304 | /** |
||
305 | * Summarize streams |
||
306 | * @param string |
||
307 | * @param array |
||
308 | * @param boolean |
||
309 | * @return stdClass |
||
310 | */ |
||
311 | public function streamsSummarize($game = null, array $channels = null, $hls = null) |
||
325 | |||
326 | /** |
||
327 | * Get featured streams |
||
328 | * @param integer |
||
329 | * @param integer |
||
330 | * @param boolean |
||
331 | * @return stdClass |
||
332 | */ |
||
333 | View Code Duplication | public function streamsFeatured($limit = null, $offset = null, $hls = null) |
|
343 | |||
344 | /** |
||
345 | * Get streams by channel |
||
346 | * @param array |
||
347 | * @param integer |
||
348 | * @param integer |
||
349 | * @param boolean |
||
350 | * @param boolean |
||
351 | * @return stdClass |
||
352 | */ |
||
353 | public function streamsByChannels($channels, $limit = null, $offset = null, $embeddable = null, $hls = null) |
||
359 | |||
360 | /** |
||
361 | * Get streams by game |
||
362 | * @param string |
||
363 | * @param integer |
||
364 | * @param integer |
||
365 | * @param boolean |
||
366 | * @param boolean |
||
367 | * @return stdClass |
||
368 | */ |
||
369 | public function streamsByGame($game, $limit = null, $offset = null, $embeddable = null, $hls = null) |
||
373 | |||
374 | /** |
||
375 | * Get video |
||
376 | * @param integer |
||
377 | * @return stdClass |
||
378 | */ |
||
379 | public function videoGet($video) |
||
383 | |||
384 | /** |
||
385 | * Get videos for a channel |
||
386 | * @param string |
||
387 | * @param integer |
||
388 | * @param integer |
||
389 | * @return stdClass |
||
390 | */ |
||
391 | public function videosByChannel($channel, $limit = null, $offset = null) |
||
400 | |||
401 | /** |
||
402 | * Get the specified channel's chat |
||
403 | * @param string |
||
404 | * @return stdClass |
||
405 | */ |
||
406 | public function chatGet($channel) |
||
410 | |||
411 | /** |
||
412 | * Get a chat's emoticons |
||
413 | * @return stdClass |
||
414 | */ |
||
415 | public function chatEmoticons() |
||
419 | |||
420 | /** |
||
421 | * Get top games |
||
422 | * @param integer |
||
423 | * @param integer |
||
424 | * @return stdClass |
||
425 | */ |
||
426 | View Code Duplication | public function gamesTop($limit = null, $offset = null) |
|
435 | |||
436 | /** |
||
437 | * Get HTML code for stream embedding |
||
438 | * @param string |
||
439 | * @param integer |
||
440 | * @param integer |
||
441 | * @param integer |
||
442 | * @return string |
||
443 | */ |
||
444 | View Code Duplication | public function embedStream($channel, $width = 620, $height = 378, $volume = 25) |
|
464 | |||
465 | /** |
||
466 | * Get HTML code for video embedding |
||
467 | * @param string |
||
468 | * @param integer |
||
469 | * @param integer |
||
470 | * @param integer |
||
471 | * @param integer |
||
472 | * @return string |
||
473 | */ |
||
474 | View Code Duplication | public function embedVideo($channel, $chapterid, $width = 400, $height = 300, $volume = 25) |
|
494 | |||
495 | /** |
||
496 | * Get HTML code for chat embedding |
||
497 | * @param string |
||
498 | * @param integer |
||
499 | * @param integer |
||
500 | * @return string |
||
501 | */ |
||
502 | public function embedChat($channel, $width = 400, $height = 300) |
||
512 | |||
513 | /** |
||
514 | * Get login URL for authentication |
||
515 | * @param string $scope Specify which permissions your app requires (space separated list) |
||
516 | * @return string |
||
517 | */ |
||
518 | public function authLoginURL($scope) |
||
533 | |||
534 | /** |
||
535 | * Get authentication access token |
||
536 | * @param string code returned after app authorization by user |
||
537 | * @return stdClass |
||
538 | */ |
||
539 | public function authAccessTokenGet($code) |
||
555 | |||
556 | /** |
||
557 | * Get the authenticated user |
||
558 | * - requires scope 'user_read' |
||
559 | * @param string |
||
560 | * @return stdClass |
||
561 | */ |
||
562 | View Code Duplication | public function authUserGet($token) |
|
575 | |||
576 | /** |
||
577 | * Get the authenticated channel |
||
578 | * - requires scope 'channel_read' |
||
579 | * @param string |
||
580 | * @return stdClass |
||
581 | */ |
||
582 | View Code Duplication | public function authChannelGet($token) |
|
595 | |||
596 | /** |
||
597 | * Returns an array of users who are editors of specified channel |
||
598 | * - requires scope 'channel_read' |
||
599 | * @param string |
||
600 | * @param string |
||
601 | * @return stdClass |
||
602 | */ |
||
603 | View Code Duplication | public function authChannelEditors($token, $channel) |
|
616 | |||
617 | /** |
||
618 | * @description Returns an array of subscriptions who are subscribed to specified channel |
||
619 | * - requires scope 'channel_subscriptions' |
||
620 | * @param string $token - user's access token |
||
621 | * @param string $channel |
||
622 | * @param integer $limit - can be up to 100 |
||
623 | * @param integer $offset |
||
624 | * @param string $direction can be DESC|ASC, if DESC - lasts will be showed first |
||
625 | * @return stdClass |
||
626 | */ |
||
627 | public function authChannelSubscriptions($token, $channel, $limit = 25, $offset = 0, $direction = 'DESC') |
||
643 | |||
644 | /** |
||
645 | * List the live streams that the authenticated user is following |
||
646 | * - requires scope 'user_read' |
||
647 | * |
||
648 | * @param string $token API access token of an authenticated user |
||
649 | * @param integer $limit Maximum number of objects in streams array |
||
650 | * Default => 25 |
||
651 | * Maximum => 100 |
||
652 | * @param integer $offset Object offset for pagination |
||
653 | * Default => 0 |
||
654 | * @param boolean $hls Limit the results to only the streams using HLS |
||
655 | * |
||
656 | * @return stdClass |
||
657 | */ |
||
658 | public function authStreamsFollowed($token, $limit = null, $offset = null, $hls = null) |
||
679 | |||
680 | /** |
||
681 | * Get streams helper |
||
682 | * @param string |
||
683 | * @param integer |
||
684 | * @param integer |
||
685 | * @param string |
||
686 | * @param boolean |
||
687 | * @param boolean |
||
688 | * @return stdClass |
||
689 | */ |
||
690 | public function getStreams($game = null, $limit = null, $offset = null, $channels = null, $embeddable = null, $hls = null) |
||
705 | |||
706 | /** |
||
707 | * Validate parameters for authentication |
||
708 | * @param array |
||
709 | * @return boolean |
||
710 | */ |
||
711 | private function configValidate($config) |
||
726 | |||
727 | /** |
||
728 | * Build query string |
||
729 | * @param array |
||
730 | * @return string |
||
731 | */ |
||
732 | private function buildQueryString($params) |
||
749 | |||
750 | /** |
||
751 | * TwitchAPI request |
||
752 | * @param string |
||
753 | * @param string |
||
754 | * @param string |
||
755 | * @return stdClass |
||
756 | * @throws \ritero\SDK\TwitchTV\TwitchException |
||
757 | */ |
||
758 | private function request($uri, $method = 'GET', $postfields = null) |
||
763 | |||
764 | /** |
||
765 | * Twitch Team API request |
||
766 | * @param string |
||
767 | * @param string |
||
768 | * @param string |
||
769 | * @return stdClass |
||
770 | * @throws \ritero\SDK\TwitchTV\TwitchException |
||
771 | */ |
||
772 | private function teamRequest($uri, $method = 'GET', $postfields = null) |
||
776 | |||
777 | /** |
||
778 | * TwitchAPI request |
||
779 | * method used by teamRequest && request methods |
||
780 | * because there are two different Twitch APIs |
||
781 | * don't call it directly |
||
782 | * @param array |
||
783 | * @param string |
||
784 | * @param string |
||
785 | * @param string |
||
786 | * @return stdClass |
||
787 | * @throws \ritero\SDK\TwitchTV\TwitchException |
||
788 | */ |
||
789 | private function generalRequest($params, $uri, $method = 'GET', $postfields = null) |
||
842 | |||
843 | /** |
||
844 | * Get the header info to store |
||
845 | */ |
||
846 | private function getHeader($ch, $header) |
||
857 | |||
858 | /** |
||
859 | * Configuration exception |
||
860 | * @throws \ritero\SDK\TwitchTV\TwitchException |
||
861 | */ |
||
862 | private function authConfigException() |
||
866 | } |
||
867 |
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.