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 Jetpack_XMLRPC_Server 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 Jetpack_XMLRPC_Server, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
6 | class Jetpack_XMLRPC_Server { |
||
7 | /** |
||
8 | * The current error object |
||
9 | */ |
||
10 | public $error = null; |
||
11 | |||
12 | /** |
||
13 | * Whitelist of the XML-RPC methods available to the Jetpack Server. If the |
||
14 | * user is not authenticated (->login()) then the methods are never added, |
||
15 | * so they will get a "does not exist" error. |
||
16 | */ |
||
17 | function xmlrpc_methods( $core_methods ) { |
||
66 | |||
67 | /** |
||
68 | * Whitelist of the bootstrap XML-RPC methods |
||
69 | */ |
||
70 | function bootstrap_xmlrpc_methods() { |
||
76 | |||
77 | function authorize_xmlrpc_methods() { |
||
78 | return array( |
||
79 | 'jetpack.remoteAuthorize' => array( $this, 'remote_authorize' ), |
||
80 | 'jetpack.activateManage' => array( $this, 'activate_manage' ), |
||
81 | ); |
||
82 | } |
||
83 | |||
84 | function activate_manage( $request ) { |
||
85 | View Code Duplication | foreach( array( 'secret', 'state' ) as $required ) { |
|
86 | if ( ! isset( $request[ $required ] ) || empty( $request[ $required ] ) ) { |
||
87 | return $this->error( new Jetpack_Error( 'missing_parameter', 'One or more parameters is missing from the request.', 400 ) ); |
||
88 | } |
||
89 | } |
||
90 | $verified = $this->verify_action( array( 'activate_manage', $request['secret'], $request['state'] ) ); |
||
91 | if ( is_a( $verified, 'IXR_Error' ) ) { |
||
92 | return $verified; |
||
93 | } |
||
94 | $activated = Jetpack::activate_module( 'manage', false, false ); |
||
95 | if ( false === $activated || ! Jetpack::is_module_active( 'manage' ) ) { |
||
96 | return $this->error( new Jetpack_Error( 'activation_error', 'There was an error while activating the module.', 500 ) ); |
||
97 | } |
||
98 | return 'active'; |
||
99 | } |
||
100 | |||
101 | function remote_authorize( $request ) { |
||
102 | View Code Duplication | foreach( array( 'secret', 'state', 'redirect_uri', 'code' ) as $required ) { |
|
103 | if ( ! isset( $request[ $required ] ) || empty( $request[ $required ] ) ) { |
||
104 | return $this->error( new Jetpack_Error( 'missing_parameter', 'One or more parameters is missing from the request.', 400 ) ); |
||
105 | } |
||
106 | } |
||
107 | |||
108 | if ( ! get_user_by( 'id', $request['state'] ) ) { |
||
109 | return $this->error( new Jetpack_Error( 'user_unknown', 'User not found.', 404 ) ); |
||
110 | } |
||
111 | |||
112 | if ( Jetpack::is_active() && Jetpack::is_user_connected( $request['state'] ) ) { |
||
113 | return $this->error( new Jetpack_Error( 'already_connected', 'User already connected.', 400 ) ); |
||
114 | } |
||
115 | |||
116 | $verified = $this->verify_action( array( 'authorize', $request['secret'], $request['state'] ) ); |
||
117 | |||
118 | if ( is_a( $verified, 'IXR_Error' ) ) { |
||
119 | return $verified; |
||
120 | } |
||
121 | |||
122 | wp_set_current_user( $request['state'] ); |
||
123 | |||
124 | $client_server = new Jetpack_Client_Server; |
||
125 | $result = $client_server->authorize( $request ); |
||
126 | |||
127 | if ( is_wp_error( $result ) ) { |
||
128 | return $this->error( $result ); |
||
129 | } |
||
130 | // Creates a new secret, allowing someone to activate the manage module for up to 1 day after authorization. |
||
131 | $secrets = Jetpack::init()->generate_secrets( 'activate_manage', DAY_IN_SECONDS ); |
||
132 | @list( $secret ) = explode( ':', $secrets ); |
||
|
|||
133 | $response = array( |
||
134 | 'result' => $result, |
||
135 | 'activate_manage' => $secret, |
||
136 | ); |
||
137 | return $response; |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Verifies that Jetpack.WordPress.com received a registration request from this site |
||
142 | */ |
||
143 | function verify_registration( $data ) { |
||
146 | |||
147 | /** |
||
148 | * @return WP_Error|string secret_2 on success, WP_Error( error_code => error_code, error_message => error description, error_data => status code ) on failure |
||
149 | * |
||
150 | * Possible error_codes: |
||
151 | * |
||
152 | * verify_secret_1_missing |
||
153 | * verify_secret_1_malformed |
||
154 | * verify_secrets_missing: No longer have verification secrets stored |
||
155 | * verify_secrets_mismatch: stored secret_1 does not match secret_1 sent by Jetpack.WordPress.com |
||
156 | * |
||
157 | * The 'authorize' and 'register' actions have additional error codes |
||
158 | * |
||
159 | * state_missing: a state ( user id ) was not supplied |
||
160 | * state_malformed: state is not the correct data type |
||
161 | * invalid_state: supplied state does not match the stored state |
||
162 | */ |
||
163 | function verify_action( $params ) { |
||
209 | |||
210 | /** |
||
211 | * Wrapper for wp_authenticate( $username, $password ); |
||
212 | * |
||
213 | * @return WP_User|IXR_Error |
||
214 | */ |
||
215 | function login() { |
||
232 | |||
233 | /** |
||
234 | * Returns the current error as an IXR_Error |
||
235 | * |
||
236 | * @return null|IXR_Error |
||
237 | */ |
||
238 | function error( $error = null ) { |
||
256 | |||
257 | /* API Methods */ |
||
258 | |||
259 | /** |
||
260 | * Just authenticates with the given Jetpack credentials. |
||
261 | * |
||
262 | * @return bool|IXR_Error |
||
263 | */ |
||
264 | function test_connection() { |
||
267 | |||
268 | function test_api_user_code( $args ) { |
||
310 | |||
311 | /** |
||
312 | * Disconnect this blog from the connected wordpress.com account |
||
313 | * @return boolean |
||
314 | */ |
||
315 | function disconnect_blog() { |
||
321 | |||
322 | /** |
||
323 | * Unlink a user from WordPress.com |
||
324 | * |
||
325 | * This will fail if called by the Master User. |
||
326 | */ |
||
327 | function unlink_user() { |
||
331 | |||
332 | /** |
||
333 | * Returns what features are available. Uses the slug of the module files. |
||
334 | * |
||
335 | * @return array|IXR_Error |
||
336 | */ |
||
337 | View Code Duplication | function features_available() { |
|
346 | |||
347 | /** |
||
348 | * Returns what features are enabled. Uses the slug of the modules files. |
||
349 | * |
||
350 | * @return array|IXR_Error |
||
351 | */ |
||
352 | View Code Duplication | function features_enabled() { |
|
361 | |||
362 | function get_post( $id ) { |
||
372 | |||
373 | View Code Duplication | function get_posts( $args ) { |
|
381 | |||
382 | function get_comment( $id ) { |
||
400 | |||
401 | View Code Duplication | function get_comments( $args ) { |
|
409 | |||
410 | function update_attachment_parent( $args ) { |
||
419 | |||
420 | function json_api( $args = array() ) { |
||
514 | } |
||
515 |
If you suppress an error, we recommend checking for the error condition explicitly: