Completed
Push — master ( c63cd8...c4c8fb )
by Claudio
10:23
created

WC_Admin_Status   F

Complexity

Total Complexity 61

Size/Duplication

Total Lines 324
Duplicated Lines 2.78 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 9
loc 324
ccs 0
cts 191
cp 0
rs 3.52
c 0
b 0
f 0
wmc 61
lcom 1
cbo 4

11 Methods

Rating   Name   Duplication   Size   Complexity  
A output() 0 3 1
A status_report() 0 3 1
B status_tools() 0 50 8
A get_tools() 0 4 1
A status_logs() 0 7 3
A get_file_version() 0 26 4
A get_log_file_handle() 0 3 2
B scan_template_files() 0 23 6
A scan_log_files() 0 3 1
B get_latest_theme_version() 0 52 9
A remove_log() 3 13 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

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 Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like WC_Admin_Status 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 WC_Admin_Status, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Debug/Status page
4
 *
5
 * @package WooCommerce/Admin/System Status
6
 * @version 2.2.0
7
 */
8
9
defined( 'ABSPATH' ) || exit;
10
11
/**
12
 * WC_Admin_Status Class.
13
 */
14
class WC_Admin_Status {
15
16
	/**
17
	 * Handles output of the reports page in admin.
18
	 */
19
	public static function output() {
20
		include_once dirname( __FILE__ ) . '/views/html-admin-page-status.php';
21
	}
22
23
	/**
24
	 * Handles output of report.
25
	 */
26
	public static function status_report() {
27
		include_once dirname( __FILE__ ) . '/views/html-admin-page-status-report.php';
28
	}
29
30
	/**
31
	 * Handles output of tools.
32
	 */
33
	public static function status_tools() {
34
		if ( ! class_exists( 'WC_REST_System_Status_Tools_Controller' ) ) {
35
			wp_die( 'Cannot load the REST API to access WC_REST_System_Status_Tools_Controller.' );
36
		}
37
38
		$tools = self::get_tools();
39
40
		if ( ! empty( $_GET['action'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'debug_action' ) ) { // WPCS: input var ok, sanitization ok.
41
			$tools_controller = new WC_REST_System_Status_Tools_Controller();
42
			$action           = wc_clean( wp_unslash( $_GET['action'] ) ); // WPCS: input var ok.
43
44
			if ( array_key_exists( $action, $tools ) ) {
45
				$response = $tools_controller->execute_tool( $action );
46
47
				$tool = $tools[ $action ];
48
				$tool = array(
49
					'id'          => $action,
50
					'name'        => $tool['name'],
51
					'action'      => $tool['button'],
52
					'description' => $tool['desc'],
53
				);
54
				$tool = array_merge( $tool, $response );
55
56
				/**
57
				 * Fires after a WooCommerce system status tool has been executed.
58
				 *
59
				 * @param array  $tool  Details about the tool that has been executed.
60
				 */
61
				do_action( 'woocommerce_system_status_tool_executed', $tool );
62
			} else {
63
				$response = array(
64
					'success' => false,
65
					'message' => __( 'Tool does not exist.', 'woocommerce' ),
66
				);
67
			}
68
69
			if ( $response['success'] ) {
70
				echo '<div class="updated inline"><p>' . esc_html( $response['message'] ) . '</p></div>';
71
			} else {
72
				echo '<div class="error inline"><p>' . esc_html( $response['message'] ) . '</p></div>';
73
			}
74
		}
75
76
		// Display message if settings settings have been saved.
77
		if ( isset( $_REQUEST['settings-updated'] ) ) { // WPCS: input var ok.
78
			echo '<div class="updated inline"><p>' . esc_html__( 'Your changes have been saved.', 'woocommerce' ) . '</p></div>';
79
		}
80
81
		include_once dirname( __FILE__ ) . '/views/html-admin-page-status-tools.php';
82
	}
83
84
	/**
85
	 * Get tools.
86
	 *
87
	 * @return array of tools
88
	 */
89
	public static function get_tools() {
90
		$tools_controller = new WC_REST_System_Status_Tools_Controller();
91
		return $tools_controller->get_tools();
92
	}
93
94
	/**
95
	 * Show the logs page.
96
	 */
97
	public static function status_logs() {
98
		if ( defined( 'WC_LOG_HANDLER' ) && 'WC_Log_Handler_DB' === WC_LOG_HANDLER ) {
99
			self::status_logs_db();
100
		} else {
101
			self::status_logs_file();
102
		}
103
	}
104
105
	/**
106
	 * Show the log page contents for file log handler.
107
	 */
108
	public static function status_logs_file() {
109
		$logs = self::scan_log_files();
110
111
		if ( ! empty( $_REQUEST['log_file'] ) && isset( $logs[ sanitize_title( wp_unslash( $_REQUEST['log_file'] ) ) ] ) ) { // WPCS: input var ok, CSRF ok.
112
			$viewed_log = $logs[ sanitize_title( wp_unslash( $_REQUEST['log_file'] ) ) ]; // WPCS: input var ok, CSRF ok.
113
		} elseif ( ! empty( $logs ) ) {
114
			$viewed_log = current( $logs );
115
		}
116
117
		$handle = ! empty( $viewed_log ) ? self::get_log_file_handle( $viewed_log ) : '';
0 ignored issues
show
Unused Code introduced by
$handle is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
118
119
		if ( ! empty( $_REQUEST['handle'] ) ) { // WPCS: input var ok, CSRF ok.
120
			self::remove_log();
121
		}
122
123
		include_once 'views/html-admin-page-status-logs.php';
124
	}
125
126
	/**
127
	 * Show the log page contents for db log handler.
128
	 */
129
	public static function status_logs_db() {
130
		if ( ! empty( $_REQUEST['flush-logs'] ) ) { // WPCS: input var ok, CSRF ok.
131
			self::flush_db_logs();
132
		}
133
134
		if ( isset( $_REQUEST['action'] ) && isset( $_REQUEST['log'] ) ) { // WPCS: input var ok, CSRF ok.
135
			self::log_table_bulk_actions();
136
		}
137
138
		$log_table_list = new WC_Admin_Log_Table_List();
139
		$log_table_list->prepare_items();
140
141
		include_once 'views/html-admin-page-status-logs-db.php';
142
	}
143
144
	/**
145
	 * Retrieve metadata from a file. Based on WP Core's get_file_data function.
146
	 *
147
	 * @since  2.1.1
148
	 * @param  string $file Path to the file.
149
	 * @return string
150
	 */
151
	public static function get_file_version( $file ) {
152
153
		// Avoid notices if file does not exist.
154
		if ( ! file_exists( $file ) ) {
155
			return '';
156
		}
157
158
		// We don't need to write to the file, so just open for reading.
159
		$fp = fopen( $file, 'r' ); // @codingStandardsIgnoreLine.
160
161
		// Pull only the first 8kiB of the file in.
162
		$file_data = fread( $fp, 8192 ); // @codingStandardsIgnoreLine.
163
164
		// PHP will close file handle, but we are good citizens.
165
		fclose( $fp ); // @codingStandardsIgnoreLine.
166
167
		// Make sure we catch CR-only line endings.
168
		$file_data = str_replace( "\r", "\n", $file_data );
169
		$version   = '';
170
171
		if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( '@version', '/' ) . '(.*)$/mi', $file_data, $match ) && $match[1] ) {
172
			$version = _cleanup_header_comment( $match[1] );
173
		}
174
175
		return $version;
176
	}
177
178
	/**
179
	 * Return the log file handle.
180
	 *
181
	 * @param string $filename Filename to get the handle for.
182
	 * @return string
183
	 */
184
	public static function get_log_file_handle( $filename ) {
185
		return substr( $filename, 0, strlen( $filename ) > 48 ? strlen( $filename ) - 48 : strlen( $filename ) - 4 );
186
	}
187
188
	/**
189
	 * Scan the template files.
190
	 *
191
	 * @param  string $template_path Path to the template directory.
192
	 * @return array
193
	 */
194
	public static function scan_template_files( $template_path ) {
195
		$files  = @scandir( $template_path ); // @codingStandardsIgnoreLine.
196
		$result = array();
197
198
		if ( ! empty( $files ) ) {
199
200
			foreach ( $files as $key => $value ) {
201
202
				if ( ! in_array( $value, array( '.', '..' ), true ) ) {
203
204
					if ( is_dir( $template_path . DIRECTORY_SEPARATOR . $value ) ) {
205
						$sub_files = self::scan_template_files( $template_path . DIRECTORY_SEPARATOR . $value );
206
						foreach ( $sub_files as $sub_file ) {
207
							$result[] = $value . DIRECTORY_SEPARATOR . $sub_file;
208
						}
209
					} else {
210
						$result[] = $value;
211
					}
212
				}
213
			}
214
		}
215
		return $result;
216
	}
217
218
	/**
219
	 * Scan the log files.
220
	 *
221
	 * @return array
222
	 */
223
	public static function scan_log_files() {
224
		return WC_Log_Handler_File::get_log_files();
225
	}
226
227
	/**
228
	 * Get latest version of a theme by slug.
229
	 *
230
	 * @param  object $theme WP_Theme object.
231
	 * @return string Version number if found.
232
	 */
233
	public static function get_latest_theme_version( $theme ) {
234
		include_once ABSPATH . 'wp-admin/includes/theme.php';
235
236
		$api = themes_api(
237
			'theme_information',
238
			array(
239
				'slug'   => $theme->get_stylesheet(),
240
				'fields' => array(
241
					'sections' => false,
242
					'tags'     => false,
243
				),
244
			)
245
		);
246
247
		$update_theme_version = 0;
248
249
		// Check .org for updates.
250
		if ( is_object( $api ) && ! is_wp_error( $api ) ) {
251
			$update_theme_version = $api->version;
252
		} elseif ( strstr( $theme->{'Author URI'}, 'woothemes' ) ) { // Check WooThemes Theme Version.
253
			$theme_dir          = substr( strtolower( str_replace( ' ', '', $theme->Name ) ), 0, 45 ); // @codingStandardsIgnoreLine.
254
			$theme_version_data = get_transient( $theme_dir . '_version_data' );
255
256
			if ( false === $theme_version_data ) {
257
				$theme_changelog = wp_safe_remote_get( 'http://dzv365zjfbd8v.cloudfront.net/changelogs/' . $theme_dir . '/changelog.txt' );
258
				$cl_lines        = explode( "\n", wp_remote_retrieve_body( $theme_changelog ) );
259
				if ( ! empty( $cl_lines ) ) {
260
					foreach ( $cl_lines as $line_num => $cl_line ) {
261
						if ( preg_match( '/^[0-9]/', $cl_line ) ) {
262
							$theme_date         = str_replace( '.', '-', trim( substr( $cl_line, 0, strpos( $cl_line, '-' ) ) ) );
263
							$theme_version      = preg_replace( '~[^0-9,.]~', '', stristr( $cl_line, 'version' ) );
264
							$theme_update       = trim( str_replace( '*', '', $cl_lines[ $line_num + 1 ] ) );
265
							$theme_version_data = array(
266
								'date'      => $theme_date,
267
								'version'   => $theme_version,
268
								'update'    => $theme_update,
269
								'changelog' => $theme_changelog,
270
							);
271
							set_transient( $theme_dir . '_version_data', $theme_version_data, DAY_IN_SECONDS );
272
							break;
273
						}
274
					}
275
				}
276
			}
277
278
			if ( ! empty( $theme_version_data['version'] ) ) {
279
				$update_theme_version = $theme_version_data['version'];
280
			}
281
		}
282
283
		return $update_theme_version;
284
	}
285
286
	/**
287
	 * Remove/delete the chosen file.
288
	 */
289
	public static function remove_log() {
290 View Code Duplication
		if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), 'remove_log' ) ) { // WPCS: input var ok, sanitization ok.
291
			wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
292
		}
293
294
		if ( ! empty( $_REQUEST['handle'] ) ) {  // WPCS: input var ok.
295
			$log_handler = new WC_Log_Handler_File();
296
			$log_handler->remove( wp_unslash( $_REQUEST['handle'] ) ); // WPCS: input var ok, sanitization ok.
297
		}
298
299
		wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) );
300
		exit();
301
	}
302
303
	/**
304
	 * Clear DB log table.
305
	 *
306
	 * @since 3.0.0
307
	 */
308
	private static function flush_db_logs() {
309 View Code Duplication
		if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'woocommerce-status-logs' ) ) { // WPCS: input var ok, sanitization ok.
310
			wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
311
		}
312
313
		WC_Log_Handler_DB::flush();
314
315
		wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) );
316
		exit();
317
	}
318
319
	/**
320
	 * Bulk DB log table actions.
321
	 *
322
	 * @since 3.0.0
323
	 */
324
	private static function log_table_bulk_actions() {
325 View Code Duplication
		if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'woocommerce-status-logs' ) ) { // WPCS: input var ok, sanitization ok.
326
			wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
327
		}
328
329
		$log_ids = array_map( 'absint', (array) isset( $_REQUEST['log'] ) ? wp_unslash( $_REQUEST['log'] ) : array() ); // WPCS: input var ok, sanitization ok.
330
331
		if ( ( isset( $_REQUEST['action'] ) && 'delete' === $_REQUEST['action'] ) || ( isset( $_REQUEST['action2'] ) && 'delete' === $_REQUEST['action2'] ) ) { // WPCS: input var ok, sanitization ok.
332
			WC_Log_Handler_DB::delete( $log_ids );
333
			wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) );
334
			exit();
335
		}
336
	}
337
}
338