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_Sync_Module_Users 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_Sync_Module_Users, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
3 | class Jetpack_Sync_Module_Users extends Jetpack_Sync_Module { |
||
4 | const MAX_INITIAL_SYNC_USERS = 100; |
||
5 | |||
6 | protected $flags = array(); |
||
7 | |||
8 | function name() { |
||
11 | |||
12 | // this is here to support the backfill API |
||
13 | public function get_object_by_id( $object_type, $id ) { |
||
20 | |||
21 | public function init_listeners( $callable ) { |
||
65 | |||
66 | public function init_full_sync_listeners( $callable ) { |
||
69 | |||
70 | public function init_before_send() { |
||
78 | |||
79 | private function get_user( $user ) { |
||
88 | |||
89 | public function sanitize_user( $user ) { |
||
99 | |||
100 | public function expand_user( $user ) { |
||
114 | |||
115 | public function get_real_user_capabilities( $user ) { |
||
127 | |||
128 | public function sanitize_user_and_expand( $user ) { |
||
133 | |||
134 | public function expand_action( $args ) { |
||
144 | |||
145 | public function expand_login_username( $args ) { |
||
151 | |||
152 | public function expand_logout_username( $args, $user_id ) { |
||
167 | |||
168 | /** |
||
169 | * Additional processing is needed for wp_login so we introduce this wrapper |
||
170 | * handler. |
||
171 | * |
||
172 | * @param String $user_login the user login. |
||
173 | * @param WP_User $user the user object. |
||
174 | */ |
||
175 | function wp_login_handler( $user_login, $user ) { |
||
176 | /** |
||
177 | * Fires when a user is logged into a site. |
||
178 | * |
||
179 | * @since 7.2.0 |
||
180 | * |
||
181 | * @param Numeric $user_id The user ID. |
||
182 | * @param WP_User $user The User Object of the user that currently logged in |
||
183 | * @param Array $params Any Flags that have been added during login |
||
184 | */ |
||
185 | do_action( 'jetpack_wp_login', $user->ID, $user, $this->get_flags( $user->ID ) ); |
||
186 | $this->clear_flags( $user->ID ); |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * A hook for the authenticate event that checks the password strength. |
||
191 | * |
||
192 | * @param WP_Error|WP_User $user the user object, or an error. |
||
193 | * @param String $username the username. |
||
194 | * @param Sting $password the password used to authenticate. |
||
195 | * @return WP_Error|WP_User the same object that was passed into the function. |
||
196 | */ |
||
197 | public function authenticate_handler( $user, $username, $password ) { |
||
198 | // In case of cookie authentication we don't do anything here. |
||
199 | if ( empty( $password ) ) { |
||
200 | return $user; |
||
201 | } |
||
202 | |||
203 | // We are only interested in successful authentication events. |
||
204 | if ( is_wp_error( $user ) || ! ( $user instanceof WP_User ) ) { |
||
205 | return $user; |
||
206 | } |
||
207 | |||
208 | jetpack_require_lib( 'class.jetpack-password-checker' ); |
||
209 | $password_checker = new Jetpack_Password_Checker( $user->ID ); |
||
210 | |||
211 | $test_results = $password_checker->test( $password, true ); |
||
212 | |||
213 | // If the password passes tests, we don't do anything. |
||
214 | if ( empty( $test_results['test_results']['failed'] ) ) { |
||
215 | return $user; |
||
216 | } |
||
217 | |||
218 | $this->add_flags( |
||
219 | $user->ID, |
||
220 | array( |
||
221 | 'warning' => 'The password failed at least one strength test.', |
||
222 | 'failures' => $test_results['test_results']['failed'], |
||
223 | ) |
||
224 | ); |
||
225 | |||
226 | return $user; |
||
227 | } |
||
228 | |||
229 | public function deleted_user_handler( $deleted_user_id, $reassigned_user_id = '' ) { |
||
230 | $is_multisite = is_multisite(); |
||
231 | /** |
||
232 | * Fires when a user is deleted on a site |
||
233 | * |
||
234 | * @since 5.4.0 |
||
235 | * |
||
236 | * @param int $deleted_user_id - ID of the deleted user |
||
237 | * @param int $reassigned_user_id - ID of the user the deleted user's posts is reassigned to (if any) |
||
238 | * @param bool $is_multisite - Whether this site is a multisite installation |
||
239 | */ |
||
240 | do_action( 'jetpack_deleted_user', $deleted_user_id, $reassigned_user_id, $is_multisite ); |
||
241 | } |
||
242 | |||
243 | View Code Duplication | function user_register_handler( $user_id, $old_user_data = null ) { |
|
244 | // ensure we only sync users who are members of the current blog |
||
245 | if ( ! is_user_member_of_blog( $user_id, get_current_blog_id() ) ) { |
||
246 | return; |
||
247 | } |
||
248 | |||
249 | if ( Jetpack_Constants::is_true( 'JETPACK_INVITE_ACCEPTED' ) ) { |
||
250 | $this->add_flags( $user_id, array( 'invitation_accepted' => true ) ); |
||
251 | } |
||
252 | /** |
||
253 | * Fires when a new user is registered on a site |
||
254 | * |
||
255 | * @since 4.9.0 |
||
256 | * |
||
257 | * @param object The WP_User object |
||
258 | */ |
||
259 | do_action( 'jetpack_sync_register_user', $user_id, $this->get_flags( $user_id ) ); |
||
260 | $this->clear_flags( $user_id ); |
||
261 | |||
262 | } |
||
263 | |||
264 | View Code Duplication | function add_user_to_blog_handler( $user_id, $old_user_data = null ) { |
|
265 | // ensure we only sync users who are members of the current blog |
||
266 | if ( ! is_user_member_of_blog( $user_id, get_current_blog_id() ) ) { |
||
267 | return; |
||
268 | } |
||
269 | |||
270 | if ( Jetpack_Constants::is_true( 'JETPACK_INVITE_ACCEPTED' ) ) { |
||
271 | $this->add_flags( $user_id, array( 'invitation_accepted' => true ) ); |
||
272 | } |
||
273 | /** |
||
274 | * Fires when a user is added on a site |
||
275 | * |
||
276 | * @since 4.9.0 |
||
277 | * |
||
278 | * @param object The WP_User object |
||
279 | */ |
||
280 | do_action( 'jetpack_sync_add_user', $user_id, $this->get_flags( $user_id ) ); |
||
281 | $this->clear_flags( $user_id ); |
||
282 | } |
||
283 | |||
284 | function save_user_handler( $user_id, $old_user_data = null ) { |
||
285 | // ensure we only sync users who are members of the current blog |
||
286 | if ( ! is_user_member_of_blog( $user_id, get_current_blog_id() ) ) { |
||
287 | return; |
||
288 | } |
||
289 | |||
290 | $user = get_user_by( 'id', $user_id ); |
||
291 | |||
292 | // Older versions of WP don't pass the old_user_data in ->data |
||
293 | if ( isset( $old_user_data->data ) ) { |
||
294 | $old_user = $old_user_data->data; |
||
295 | } else { |
||
296 | $old_user = $old_user_data; |
||
297 | } |
||
298 | |||
299 | if ( $old_user !== null && $user->user_pass !== $old_user->user_pass ) { |
||
300 | $this->flags[ $user_id ]['password_changed'] = true; |
||
301 | } |
||
302 | if ( $old_user !== null && $user->data->user_email !== $old_user->user_email ) { |
||
303 | // The '_new_email' user meta is deleted right after the call to wp_update_user |
||
304 | // that got us to this point so if it's still set then this was a user confirming |
||
305 | // their new email address |
||
306 | if ( 1 === intval( get_user_meta( $user->ID, '_new_email', true ) ) ) { |
||
307 | $this->flags[ $user_id ]['email_changed'] = true; |
||
308 | } |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * Fires when the client needs to sync an updated user |
||
313 | * |
||
314 | * @since 4.2.0 |
||
315 | * |
||
316 | * @param object The WP_User object |
||
317 | * @param array state - New since 5.8.0 |
||
318 | */ |
||
319 | do_action( 'jetpack_sync_save_user', $user_id, $this->get_flags( $user_id ) ); |
||
320 | $this->clear_flags( $user_id ); |
||
321 | } |
||
322 | |||
323 | function save_user_role_handler( $user_id, $role, $old_roles = null ) { |
||
324 | $this->add_flags( |
||
325 | $user_id, |
||
326 | array( |
||
327 | 'role_changed' => true, |
||
328 | 'previous_role' => $old_roles, |
||
329 | ) |
||
330 | ); |
||
331 | |||
332 | // The jetpack_sync_register_user payload is identical to jetpack_sync_save_user, don't send both |
||
333 | if ( $this->is_create_user() || $this->is_add_user_to_blog() ) { |
||
334 | return; |
||
335 | } |
||
336 | /** |
||
337 | * This action is documented already in this file |
||
338 | */ |
||
339 | do_action( 'jetpack_sync_save_user', $user_id, $this->get_flags( $user_id ) ); |
||
340 | $this->clear_flags( $user_id ); |
||
341 | } |
||
342 | |||
343 | function get_flags( $user_id ) { |
||
349 | |||
350 | function clear_flags( $user_id ) { |
||
355 | |||
356 | function add_flags( $user_id, $flags ) { |
||
359 | |||
360 | function maybe_save_user_meta( $meta_id, $user_id, $meta_key, $value ) { |
||
381 | |||
382 | public function enqueue_full_sync_actions( $config, $max_items_to_enqueue, $state ) { |
||
387 | |||
388 | public function estimate_full_sync_actions( $config ) { |
||
401 | |||
402 | View Code Duplication | private function get_where_sql( $config ) { |
|
414 | |||
415 | function get_full_sync_actions() { |
||
418 | |||
419 | function get_initial_sync_user_config() { |
||
430 | |||
431 | public function expand_users( $args ) { |
||
436 | |||
437 | public function remove_user_from_blog_handler( $user_id, $blog_id ) { |
||
456 | |||
457 | protected function is_add_new_user_to_blog() { |
||
460 | |||
461 | protected function is_add_user_to_blog() { |
||
464 | |||
465 | protected function is_delete_user() { |
||
468 | |||
469 | protected function is_create_user() { |
||
478 | |||
479 | protected function get_reassigned_network_user_id() { |
||
492 | } |
||
493 |
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.