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 WP2D_API 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 WP2D_API, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
27 | class WP2D_API { |
||
28 | |||
29 | /** |
||
30 | * The provider name to display when posting to diaspora*. |
||
31 | * |
||
32 | * @var string |
||
33 | */ |
||
34 | public $provider = 'WP to diaspora*'; |
||
35 | |||
36 | /** |
||
37 | * The last http request error that occurred. |
||
38 | * |
||
39 | * @var WP_Error |
||
40 | */ |
||
41 | private $last_error; |
||
42 | |||
43 | /** |
||
44 | * Security token to be used for making requests. |
||
45 | * |
||
46 | * @var string |
||
47 | */ |
||
48 | private $token; |
||
49 | |||
50 | /** |
||
51 | * Save the cookies for the requests. |
||
52 | * |
||
53 | * @var array |
||
54 | */ |
||
55 | private $cookies; |
||
56 | |||
57 | /** |
||
58 | * The last http request made to diaspora*. |
||
59 | * Contains the response and request infos. |
||
60 | * |
||
61 | * @var object |
||
62 | */ |
||
63 | private $last_request; |
||
64 | |||
65 | /** |
||
66 | * Is this a secure server, use HTTPS instead of HTTP? |
||
67 | * |
||
68 | * @var boolean |
||
69 | */ |
||
70 | private $is_secure; |
||
71 | |||
72 | /** |
||
73 | * The pod domain to make the http requests to. |
||
74 | * |
||
75 | * @var string |
||
76 | */ |
||
77 | private $pod; |
||
78 | |||
79 | /** |
||
80 | * Username to use when logging in to diaspora*. |
||
81 | * |
||
82 | * @var string |
||
83 | */ |
||
84 | private $username; |
||
85 | |||
86 | /** |
||
87 | * Password to use when logging in to diaspora*. |
||
88 | * |
||
89 | * @var string |
||
90 | */ |
||
91 | private $password; |
||
92 | |||
93 | /** |
||
94 | * Remember the current login state. |
||
95 | * |
||
96 | * @var boolean |
||
97 | */ |
||
98 | private $is_logged_in = false; |
||
99 | |||
100 | /** |
||
101 | * The list of user's aspects, which get set after ever http request. |
||
102 | * |
||
103 | * @var array |
||
104 | */ |
||
105 | private $aspects = []; |
||
106 | |||
107 | /** |
||
108 | * The list of user's connected services, which get set after ever http request. |
||
109 | * |
||
110 | * @var array |
||
111 | */ |
||
112 | private $services = []; |
||
113 | |||
114 | /** |
||
115 | * List of regex expressions used to filter out details from http request responses. |
||
116 | * |
||
117 | * @var array |
||
118 | */ |
||
119 | private static $regexes = [ |
||
120 | 'token' => '/content="(.*?)" name="csrf-token"|name="csrf-token" content="(.*?)"/', |
||
121 | 'aspects' => '/"aspects"\:(\[.*?\])/', |
||
122 | 'services' => '/"configured_services"\:(\[.*?\])/', |
||
123 | ]; |
||
124 | |||
125 | /** |
||
126 | * The full pod url, with the used protocol. |
||
127 | * |
||
128 | * @param string $path Path to add to the pod url. |
||
129 | * |
||
130 | * @return string Full pod url. |
||
131 | */ |
||
132 | public function get_pod_url( $path = '' ) { |
||
142 | |||
143 | /** |
||
144 | * Constructor to initialise the connection to diaspora*. |
||
145 | * |
||
146 | * @param string $pod The pod domain to connect to. |
||
147 | * @param bool $is_secure Is this a secure server? (Default: true). |
||
148 | */ |
||
149 | public function __construct( $pod, $is_secure = true ) { |
||
154 | |||
155 | /** |
||
156 | * Initialise the connection to diaspora*. The pod and protocol can be changed by passing new parameters. |
||
157 | * Check if we can connect to the pod to retrieve the token. |
||
158 | * |
||
159 | * @param string $pod Pod domain to connect to, if it should be changed. |
||
160 | * @param bool $is_secure Is this a secure server? (Default: true). |
||
161 | * |
||
162 | * @return bool True if we could get the token, else false. |
||
163 | */ |
||
164 | public function init( $pod = null, $is_secure = true ) { |
||
195 | |||
196 | /** |
||
197 | * Check if there is an API error around. |
||
198 | * |
||
199 | * @return bool If there is an API error around. |
||
200 | */ |
||
201 | public function has_last_error() { |
||
204 | |||
205 | /** |
||
206 | * Get the last API error object. |
||
207 | * |
||
208 | * @param bool $clear If the error should be cleared after returning it. |
||
209 | * |
||
210 | * @return WP_Error|null The last API error object or null. |
||
211 | */ |
||
212 | public function get_last_error_object( $clear = true ) { |
||
220 | |||
221 | /** |
||
222 | * Get the last API error message. |
||
223 | * |
||
224 | * @param bool $clear If the error should be cleared after returning it. |
||
225 | * |
||
226 | * @return string The last API error message. |
||
227 | */ |
||
228 | public function get_last_error( $clear = false ) { |
||
236 | |||
237 | /** |
||
238 | * Fetch the secure token from Diaspora and save it for future use. |
||
239 | * |
||
240 | * @param bool $force Force to fetch a new token. |
||
241 | * |
||
242 | * @return string The fetched token. |
||
243 | */ |
||
244 | private function fetch_token( $force = false ) { |
||
253 | |||
254 | /** |
||
255 | * Check if the API has been initialised. Otherwise set the last error. |
||
256 | * |
||
257 | * @return bool Has the connection been initialised? |
||
258 | */ |
||
259 | private function check_init() { |
||
268 | |||
269 | /** |
||
270 | * Check if we're logged in. Otherwise set the last error. |
||
271 | * |
||
272 | * @return bool Are we logged in already? |
||
273 | */ |
||
274 | private function check_login() { |
||
286 | |||
287 | /** |
||
288 | * Check if we are logged in. |
||
289 | * |
||
290 | * @return bool Are we logged in already? |
||
291 | */ |
||
292 | public function is_logged_in() { |
||
295 | |||
296 | /** |
||
297 | * Log in to diaspora*. |
||
298 | * |
||
299 | * @param string $username Username used for login. |
||
300 | * @param string $password Password used for login. |
||
301 | * @param bool $force Force a new login even if we are already logged in. |
||
302 | * |
||
303 | * @return bool Did the login succeed? |
||
304 | */ |
||
305 | public function login( $username, $password, $force = false ) { |
||
375 | |||
376 | /** |
||
377 | * Perform a logout, resetting all login info. |
||
378 | * |
||
379 | * @since 1.6.0 |
||
380 | */ |
||
381 | public function logout() { |
||
388 | |||
389 | /** |
||
390 | * Perform a de-initialisation, resetting all class variables. |
||
391 | * |
||
392 | * @since 1.7.0 |
||
393 | */ |
||
394 | public function deinit() { |
||
401 | |||
402 | /** |
||
403 | * Post to diaspora*. |
||
404 | * |
||
405 | * @param string $text The text to post. |
||
406 | * @param array|string $aspects The aspects to post to. Array or comma separated ids. |
||
407 | * @param array $extra_data Any extra data to be added to the post call. |
||
408 | * |
||
409 | * @return bool|object Return the response data of the new diaspora* post if successfully posted, else false. |
||
410 | */ |
||
411 | public function post( $text, $aspects = 'public', array $extra_data = [] ) { |
||
475 | |||
476 | /** |
||
477 | * Delete a post or comment from diaspora*. |
||
478 | * |
||
479 | * @since 1.6.0 |
||
480 | * |
||
481 | * @param string $what What to delete, 'post' or 'comment'. |
||
482 | * @param string $id The ID of the post or comment to delete. |
||
483 | * |
||
484 | * @return bool If the deletion was successful. |
||
485 | */ |
||
486 | public function delete( $what, $id ) { |
||
538 | |||
539 | /** |
||
540 | * Get the list of aspects. |
||
541 | * |
||
542 | * @param bool $force Force to fetch new aspects. |
||
543 | * |
||
544 | * @return array|bool Array of aspect objects or false. |
||
545 | */ |
||
546 | public function get_aspects( $force = false ) { |
||
551 | |||
552 | /** |
||
553 | * Get the list of connected services. |
||
554 | * |
||
555 | * @param bool $force Force to fetch new connected services. |
||
556 | * |
||
557 | * @return array|bool Array of service objects or false. |
||
558 | */ |
||
559 | public function get_services( $force = false ) { |
||
564 | |||
565 | /** |
||
566 | * Get the list of aspects or connected services. |
||
567 | * |
||
568 | * @param string $type Type of list to get. |
||
569 | * @param array $list The current list of items. |
||
570 | * @param bool $force Force to fetch new list. |
||
571 | * |
||
572 | * @return array|bool List of fetched aspects or services, or false. |
||
573 | */ |
||
574 | private function get_aspects_services( $type, $list, $force ) { |
||
623 | |||
624 | /** |
||
625 | * Send an http(s) request via WP_HTTP API. |
||
626 | * |
||
627 | * @see WP_Http::request() |
||
628 | * |
||
629 | * @param string $url The URL to request. |
||
630 | * @param array $args Arguments to be posted with the request. |
||
631 | * |
||
632 | * @return object An object containing details about this request. |
||
633 | */ |
||
634 | private function request( $url, array $args = [] ) { |
||
695 | |||
696 | /** |
||
697 | * Helper method to set the last occurred error. |
||
698 | * |
||
699 | * @since 1.6.0 |
||
700 | * |
||
701 | * @see WP_Error::__construct() |
||
702 | * |
||
703 | * @param string|int $code Error code. |
||
704 | * @param string $message Error message. |
||
705 | * @param mixed $data Error data. |
||
706 | */ |
||
707 | private function error( $code, $message, $data = '' ) { |
||
716 | |||
717 | /** |
||
718 | * Parse the regex and return the found string. |
||
719 | * |
||
720 | * @param string $regex Shorthand of a saved regex or a custom regex. |
||
721 | * @param string $content Text to parse the regex with. |
||
722 | * |
||
723 | * @return string The found string, or an empty string. |
||
724 | */ |
||
725 | private function parse_regex( $regex, $content ) { |
||
735 | } |
||
736 |
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.