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_Cxn_Tests 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_Cxn_Tests, and based on these observations, apply Extract Interface, too.
| 1 | <?php | ||
| 21 | class Jetpack_Cxn_Tests extends Jetpack_Cxn_Test_Base { | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Jetpack_Cxn_Tests constructor. | ||
| 25 | */ | ||
| 26 | 	public function __construct() { | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Helper function to look up the expected master user and return the local WP_User. | ||
| 68 | * | ||
| 69 | * @return WP_User Jetpack's expected master user. | ||
| 70 | */ | ||
| 71 | 	protected function helper_retrieve_local_master_user() { | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Is Jetpack even connected and supposed to be talking to WP.com? | ||
| 78 | */ | ||
| 79 | 	protected function helper_is_jetpack_connected() { | ||
| 82 | |||
| 83 | /** | ||
| 84 | * Retrieve the `blog_token` if it exists. | ||
| 85 | * | ||
| 86 | * @return object|false | ||
| 87 | */ | ||
| 88 | 	protected function helper_get_blog_token() { | ||
| 91 | |||
| 92 | /** | ||
| 93 | * Returns a support url based on using a development version. | ||
| 94 | */ | ||
| 95 | 	protected function helper_get_support_url() { | ||
| 100 | |||
| 101 | /** | ||
| 102 | * Returns the url to reconnect Jetpack. | ||
| 103 | * | ||
| 104 | * @return string The reconnect url. | ||
| 105 | */ | ||
| 106 | 	protected static function helper_get_reconnect_url() { | ||
| 109 | |||
| 110 | /** | ||
| 111 | * Gets translated support text. | ||
| 112 | */ | ||
| 113 | 	protected function helper_get_support_text() { | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Returns the translated text to reconnect Jetpack. | ||
| 119 | * | ||
| 120 | * @return string The translated reconnect text. | ||
| 121 | */ | ||
| 122 | 	protected static function helper_get_reconnect_text() { | ||
| 125 | |||
| 126 | /** | ||
| 127 | * Returns the translated text for failing tests due to timeouts. | ||
| 128 | * | ||
| 129 | * @return string The translated timeout text. | ||
| 130 | */ | ||
| 131 | 	protected static function helper_get_timeout_text() { | ||
| 134 | |||
| 135 | /** | ||
| 136 | * Gets translated reconnect long description. | ||
| 137 | * | ||
| 138 | * @param string $connection_error The connection specific error. | ||
| 139 | * @param string $recommendation The recommendation for resolving the connection error. | ||
| 140 | * | ||
| 141 | * @return string The translated long description for reconnection recommendations. | ||
| 142 | */ | ||
| 143 | 	protected static function helper_get_reconnect_long_description( $connection_error, $recommendation ) { | ||
| 155 | |||
| 156 | /** | ||
| 157 | * Helper function to return consistent responses for a connection failing test. | ||
| 158 | * | ||
| 159 | * @param string $name The raw method name that runs the test. Default unnamed_test. | ||
| 160 | * @param string $connection_error The connection specific error. Default 'Your site is not connected to Jetpack.'. | ||
| 161 | * @param string $recommendation The recommendation for resolving the connection error. Default 'We recommend reconnecting Jetpack.'. | ||
| 162 | * | ||
| 163 | * @return array Test results. | ||
| 164 | */ | ||
| 165 | 	public static function connection_failing_test( $name, $connection_error = '', $recommendation = '' ) { | ||
| 179 | |||
| 180 | /** | ||
| 181 | * Gets translated text to enable outbound requests. | ||
| 182 | * | ||
| 183 | * @param string $protocol Either 'HTTP' or 'HTTPS'. | ||
| 184 | * | ||
| 185 | * @return string The translated text. | ||
| 186 | */ | ||
| 187 | 	protected function helper_enable_outbound_requests( $protocol ) { | ||
| 198 | |||
| 199 | /** | ||
| 200 | * Returns 30 for use with a filter. | ||
| 201 | * | ||
| 202 | * To allow time for WP.com to run upstream testing, this function exists to increase the http_request_timeout value | ||
| 203 | * to 30. | ||
| 204 | * | ||
| 205 | * @return int 30 | ||
| 206 | */ | ||
| 207 | 	public static function increase_timeout() { | ||
| 210 | |||
| 211 | /** | ||
| 212 | * The test verifies the blog token exists. | ||
| 213 | * | ||
| 214 | * @return array | ||
| 215 | */ | ||
| 216 | 	protected function test__blog_token_if_exists() { | ||
| 217 | $name = __FUNCTION__; | ||
| 218 | |||
| 219 | View Code Duplication | 		if ( ! $this->helper_is_jetpack_connected() ) { | |
| 220 | return self::skipped_test( | ||
| 221 | array( | ||
| 222 | 'name' => $name, | ||
| 223 | 'short_description' => __( 'Jetpack is not connected. No blog token to check.', 'jetpack' ), | ||
| 224 | ) | ||
| 225 | ); | ||
| 226 | } | ||
| 227 | $blog_token = $this->helper_get_blog_token(); | ||
| 228 | |||
| 229 | 		if ( $blog_token ) { | ||
| 230 | $result = self::passing_test( array( 'name' => $name ) ); | ||
| 231 | 		} else { | ||
| 232 | $connection_error = __( 'Blog token is missing.', 'jetpack' ); | ||
| 233 | |||
| 234 | $result = self::connection_failing_test( $name, $connection_error ); | ||
| 235 | } | ||
| 236 | |||
| 237 | return $result; | ||
| 238 | } | ||
| 239 | |||
| 240 | /** | ||
| 241 | * Test if Jetpack is connected. | ||
| 242 | */ | ||
| 243 | 	protected function test__check_if_connected() { | ||
| 244 | $name = __FUNCTION__; | ||
| 245 | |||
| 246 | View Code Duplication | 		if ( ! $this->helper_get_blog_token() ) { | |
| 247 | return self::skipped_test( | ||
| 248 | array( | ||
| 249 | 'name' => $name, | ||
| 250 | 'short_description' => __( 'Blog token is missing.', 'jetpack' ), | ||
| 251 | ) | ||
| 252 | ); | ||
| 253 | } | ||
| 254 | |||
| 255 | 		if ( $this->helper_is_jetpack_connected() ) { | ||
| 256 | $result = self::passing_test( | ||
| 257 | array( | ||
| 258 | 'name' => $name, | ||
| 259 | 'label' => __( 'Your site is connected to Jetpack', 'jetpack' ), | ||
| 260 | 'long_description' => sprintf( | ||
| 261 | '<p>%1$s</p>' . | ||
| 262 | '<p><span class="dashicons pass"><span class="screen-reader-text">%2$s</span></span> %3$s</p>', | ||
| 263 | __( 'A healthy connection ensures Jetpack essential services are provided to your WordPress site, such as Stats and Site Security.', 'jetpack' ), | ||
| 264 | /* translators: Screen reader text indicating a test has passed */ | ||
| 265 | __( 'Passed', 'jetpack' ), | ||
| 266 | __( 'Your site is connected to Jetpack.', 'jetpack' ) | ||
| 267 | ), | ||
| 268 | ) | ||
| 269 | ); | ||
| 270 | 		} elseif ( ( new Status() )->is_offline_mode() ) { | ||
| 271 | $result = self::skipped_test( | ||
| 272 | array( | ||
| 273 | 'name' => $name, | ||
| 274 | 'short_description' => __( 'Jetpack is in Offline Mode:', 'jetpack' ) . ' ' . Jetpack::development_mode_trigger_text(), | ||
| 275 | ) | ||
| 276 | ); | ||
| 277 | 		} else { | ||
| 278 | $connection_error = __( 'Your site is not connected to Jetpack', 'jetpack' ); | ||
| 279 | |||
| 280 | $result = self::connection_failing_test( $name, $connection_error ); | ||
| 281 | } | ||
| 282 | |||
| 283 | return $result; | ||
| 284 | } | ||
| 285 | |||
| 286 | /** | ||
| 287 | * Test that the master user still exists on this site. | ||
| 288 | * | ||
| 289 | * @return array Test results. | ||
| 290 | */ | ||
| 291 | 	protected function test__master_user_exists_on_site() { | ||
| 292 | $name = __FUNCTION__; | ||
| 293 | View Code Duplication | 		if ( ! $this->helper_is_jetpack_connected() ) { | |
| 294 | return self::skipped_test( | ||
| 295 | array( | ||
| 296 | 'name' => $name, | ||
| 297 | 'short_description' => __( 'Jetpack is not connected. No master user to check.', 'jetpack' ), | ||
| 298 | ) | ||
| 299 | ); | ||
| 300 | } | ||
| 301 | View Code Duplication | 		if ( ! ( new Connection_Manager() )->get_connection_owner_id() && ( new Status() )->is_no_user_testing_mode() ) { | |
| 302 | return self::skipped_test( | ||
| 303 | array( | ||
| 304 | 'name' => $name, | ||
| 305 | 'short_description' => __( 'Jetpack is running in userless mode. No master user to check.', 'jetpack' ), | ||
| 306 | ) | ||
| 307 | ); | ||
| 308 | } | ||
| 309 | $local_user = $this->helper_retrieve_local_master_user(); | ||
| 310 | |||
| 311 | 		if ( $local_user->exists() ) { | ||
| 312 | $result = self::passing_test( array( 'name' => $name ) ); | ||
| 313 | 		} else { | ||
| 314 | $connection_error = __( 'The user who setup the Jetpack connection no longer exists on this site.', 'jetpack' ); | ||
| 315 | |||
| 316 | $result = self::connection_failing_test( $name, $connection_error ); | ||
| 317 | } | ||
| 318 | |||
| 319 | return $result; | ||
| 320 | } | ||
| 321 | |||
| 322 | /** | ||
| 323 | * Test that the master user has the manage options capability (e.g. is an admin). | ||
| 324 | * | ||
| 325 | * Generic calls from WP.com execute on Jetpack as the master user. If it isn't an admin, random things will fail. | ||
| 326 | * | ||
| 327 | * @return array Test results. | ||
| 328 | */ | ||
| 329 | 	protected function test__master_user_can_manage_options() { | ||
| 330 | $name = __FUNCTION__; | ||
| 331 | View Code Duplication | 		if ( ! $this->helper_is_jetpack_connected() ) { | |
| 332 | return self::skipped_test( | ||
| 333 | array( | ||
| 334 | 'name' => $name, | ||
| 335 | 'short_description' => __( 'Jetpack is not connected.', 'jetpack' ), | ||
| 336 | ) | ||
| 337 | ); | ||
| 338 | } | ||
| 339 | View Code Duplication | 		if ( ! ( new Connection_Manager() )->get_connection_owner_id() && ( new Status() )->is_no_user_testing_mode() ) { | |
| 340 | return self::skipped_test( | ||
| 341 | array( | ||
| 342 | 'name' => $name, | ||
| 343 | 'short_description' => __( 'Jetpack is running in userless mode. No master user to check.', 'jetpack' ), | ||
| 344 | ) | ||
| 345 | ); | ||
| 346 | } | ||
| 347 | $master_user = $this->helper_retrieve_local_master_user(); | ||
| 348 | |||
| 349 | 		if ( user_can( $master_user, 'manage_options' ) ) { | ||
| 350 | $result = self::passing_test( array( 'name' => $name ) ); | ||
| 351 | 		} else { | ||
| 352 | /* translators: a WordPress username */ | ||
| 353 | $connection_error = sprintf( __( 'The user (%s) who setup the Jetpack connection is not an administrator.', 'jetpack' ), $master_user->user_login ); | ||
| 354 | /* translators: a WordPress username */ | ||
| 355 | $recommendation = sprintf( __( 'We recommend either upgrading the user (%s) or reconnecting Jetpack.', 'jetpack' ), $master_user->user_login ); | ||
| 356 | |||
| 357 | $result = self::connection_failing_test( $name, $connection_error, $recommendation ); | ||
| 358 | } | ||
| 359 | |||
| 360 | return $result; | ||
| 361 | } | ||
| 362 | |||
| 363 | /** | ||
| 364 | * Test that the PHP's XML library is installed. | ||
| 365 | * | ||
| 366 | * While it should be installed by default, increasingly in PHP 7, some OSes require an additional php-xml package. | ||
| 367 | * | ||
| 368 | * @return array Test results. | ||
| 369 | */ | ||
| 370 | 	protected function test__xml_parser_available() { | ||
| 387 | |||
| 388 | /** | ||
| 389 | * Test that the server is able to send an outbound http communication. | ||
| 390 | * | ||
| 391 | * @return array Test results. | ||
| 392 | */ | ||
| 393 | View Code Duplication | 	protected function test__outbound_http() { | |
| 411 | |||
| 412 | /** | ||
| 413 | * Test that the server is able to send an outbound https communication. | ||
| 414 | * | ||
| 415 | * @return array Test results. | ||
| 416 | */ | ||
| 417 | View Code Duplication | 	protected function test__outbound_https() { | |
| 435 | |||
| 436 | /** | ||
| 437 | * Check for an IDC. | ||
| 438 | * | ||
| 439 | * @return array Test results. | ||
| 440 | */ | ||
| 441 | 	protected function test__identity_crisis() { | ||
| 472 | |||
| 473 | /** | ||
| 474 | * Tests the health of the Connection tokens. | ||
| 475 | * | ||
| 476 | * This will always check the blog token health. It will also check the user token health if | ||
| 477 | * a user is logged in and connected, or if there's a connected owner. | ||
| 478 | * | ||
| 479 | * @since 9.0.0 | ||
| 480 | * @since 9.6.0 Checks only blog token if current user not connected or site does not have a connected owner. | ||
| 481 | * | ||
| 482 | * @return array Test results. | ||
| 483 | */ | ||
| 484 | 	protected function test__connection_token_health() { | ||
| 508 | |||
| 509 | /** | ||
| 510 | * Tests blog and user's token against wp.com's check-token-health endpoint. | ||
| 511 | * | ||
| 512 | * @since 9.6.0 | ||
| 513 | * | ||
| 514 | * @return array Test results. | ||
| 515 | */ | ||
| 516 | 	protected function check_blog_token_health() { | ||
| 526 | |||
| 527 | /** | ||
| 528 | * Tests blog token against wp.com's check-token-health endpoint. | ||
| 529 | * | ||
| 530 | * @since 9.6.0 | ||
| 531 | * | ||
| 532 | * @param int $user_id The user ID to check the tokens for. | ||
| 533 | * | ||
| 534 | * @return array Test results. | ||
| 535 | */ | ||
| 536 | 	protected function check_tokens_health( $user_id ) { | ||
| 565 | |||
| 566 | /** | ||
| 567 | * Tests connection status against wp.com's test-connection endpoint. | ||
| 568 | * | ||
| 569 | * @todo: Compare with the wpcom_self_test. We only need one of these. | ||
| 570 | * | ||
| 571 | * @return array Test results. | ||
| 572 | */ | ||
| 573 | 	protected function test__wpcom_connection_test() { | ||
| 639 | |||
| 640 | /** | ||
| 641 | * Tests the port number to ensure it is an expected value. | ||
| 642 | * | ||
| 643 | * We expect that sites on be on one of: | ||
| 644 | * port 80, | ||
| 645 | * port 443 (https sites only), | ||
| 646 | * the value of JETPACK_SIGNATURE__HTTP_PORT, | ||
| 647 | * unless the site is intentionally on a different port (e.g. example.com:8080 is the site's URL). | ||
| 648 | * | ||
| 649 | * If the value isn't one of those and the site's URL doesn't include a port, then the signature verification will fail. | ||
| 650 | * | ||
| 651 | * This happens most commonly on sites with reverse proxies, so the edge (e.g. Varnish) is running on 80/443, but nginx | ||
| 652 | * or Apache is responding internally on a different port (e.g. 81). | ||
| 653 | * | ||
| 654 | * @return array Test results | ||
| 655 | */ | ||
| 656 | 	protected function test__server_port_value() { | ||
| 709 | |||
| 710 | /** | ||
| 711 | * Full Sync Health Test. | ||
| 712 | * | ||
| 713 | * Sync Disabled: Results in a skipped test | ||
| 714 | * Not In Progress : Results in a skipped test | ||
| 715 | * In Progress: Results in skipped test w/ status in CLI | ||
| 716 | */ | ||
| 717 | 	protected function test__full_sync_health() { | ||
| 781 | |||
| 782 | /** | ||
| 783 | * Sync Health Tests. | ||
| 784 | * | ||
| 785 | * Disabled: Results in a failing test (recommended) | ||
| 786 | * Delayed: Results in failing test (recommended) | ||
| 787 | * Error: Results in failing test (critical) | ||
| 788 | */ | ||
| 789 | 	protected function test__sync_health() { | ||
| 930 | |||
| 931 | /** | ||
| 932 | * Calls to WP.com to run the connection diagnostic testing suite. | ||
| 933 | * | ||
| 934 | * Intentionally added last as it will be skipped if any local failed conditions exist. | ||
| 935 | * | ||
| 936 | * @since 7.1.0 | ||
| 937 | * @since 7.9.0 Timeout waiting for a WP.com response no longer fails the test. Test is marked skipped instead. | ||
| 938 | * | ||
| 939 | * @return array Test results. | ||
| 940 | */ | ||
| 941 | 	protected function last__wpcom_self_test() { | ||
| 986 | } | ||
| 987 | 
In PHP, under loose comparison (like
==, or!=, orswitchconditions), values of different types might be equal.For
stringvalues, the empty string''is a special case, in particular the following results might be unexpected: