Test Failed
Pull Request — master (#1942)
by Devin
05:03
created

Give_Updates::__change_donations_label()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 4
nop 0
dl 0
loc 22
rs 8.6737
c 0
b 0
f 0
1
<?php
2
/**
3
 * Class Give_Updates
4
 *
5
 * @since 1.8.12
6
 */
7
class Give_Updates {
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
8
9
	/**
10
	 * Instance.
11
	 *
12
	 * @since
13
	 * @access static
14
	 * @var
15
	 */
16
	static private $instance;
17
18
	/**
19
	 * Updates
20
	 *
21
	 * @since  1.8.12
22
	 * @access private
23
	 * @var array
24
	 */
25
	private $updates = array();
26
27
	/**
28
	 * Current update percentage number
29
	 *
30
	 * @since  1.8.12
31
	 * @access private
32
	 * @var array
33
	 */
34
	public $percentage = 0;
35
36
	/**
37
	 * Current update step number
38
	 *
39
	 * @since  1.8.12
40
	 * @access private
41
	 * @var array
42
	 */
43
	public $step = 1;
44
45
	/**
46
	 * Current update number
47
	 *
48
	 * @since  1.8.12
49
	 * @access private
50
	 * @var array
51
	 */
52
	public $update = 1;
53
54
	/**
55
	 * Singleton pattern.
56
	 *
57
	 * @since  1.8.12
58
	 * @access private
59
	 *
60
	 * @param Give_Updates .
61
	 */
62
	private function __construct() {
63
	}
64
65
	/**
66
	 * Register updates
67
	 *
68
	 * @since  1.8.12
69
	 * @access public
70
	 *
71
	 * @param array $args
72
	 */
73
	public function register( $args ) {
74
		$args_default = array(
75
			'id'       => '',
76
			'version'  => '',
77
			'callback' => '',
78
		);
79
80
		$args = wp_parse_args( $args, $args_default );
81
82
		// You can only register database upgrade.
83
		$args['type'] = 'database';
84
85
		// Bailout.
86
		if ( empty( $args['id'] ) || empty( $args['version'] ) || empty( $args['callback'] ) || ! is_callable( $args['callback'] ) ) {
87
			return;
88
		}
89
90
		$this->updates[ $args['type'] ][] = $args;
91
	}
92
93
94
	/**
95
	 * Get updates.
96
	 *
97
	 * @since  1.8.12
98
	 * @access public
99
	 *
100
	 * @param string $update_type Tye of update.
101
	 * @param string $status      Tye of update.
102
	 *
103
	 * @return array
104
	 */
105
	public function get_updates( $update_type = '', $status = 'all' ) {
106
		// return all updates.
107
		if ( empty( $update_type ) ) {
108
			return $this->updates;
109
		}
110
111
		// Get specific update.
112
		$updates = ! empty( $this->updates[ $update_type ] ) ? $this->updates[ $update_type ] : array();
113
114
		// Bailout.
115
		if ( empty( $updates ) ) {
116
			return $updates;
117
		}
118
119
		switch ( $status ) {
120
			case 'new':
121
				// Remove already completed updates.
122
				$completed_updates = give_get_completed_upgrades();
123
124
				if ( ! empty( $completed_updates ) ) {
125
					foreach ( $updates as $index => $update ) {
126
						if ( in_array( $update['id'], $completed_updates ) ) {
127
							unset( $updates[ $index ] );
128
						}
129
					}
130
					$updates = array_values( $updates );
131
				}
132
133
				break;
134
		}
135
136
		return $updates;
137
	}
138
139
	/**
140
	 * Get instance.
141
	 *
142
	 * @since
143
	 * @access static
144
	 * @return static
145
	 */
146
	static function get_instance() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
147
		if ( is_null( self::$instance ) ) {
148
			self::$instance = new self();
149
		}
150
151
		return self::$instance;
152
	}
153
154
	/**
155
	 *
156
	 * Setup hook
157
	 *
158
	 * @since  1.8.12
159
	 * @access public
160
	 */
161
	public function setup() {
162
		/**
163
		 * Setup hooks.
164
		 */
165
		add_action( 'init', array( $this, '__register_upgrade' ), 9999 );
166
		add_action( 'admin_init', array( $this, '__change_donations_label' ), 9999 );
167
		add_action( 'admin_menu', array( $this, '__register_menu' ), 9999 );
168
		add_action( 'give_set_upgrade_completed', array( $this, '__flush_resume_updates' ), 9999 );
169
		add_action( 'wp_ajax_give_do_ajax_updates', array( $this, '__give_ajax_updates' ) );
170
171
		/**
172
		 * Load file
173
		 */
174
		require_once GIVE_PLUGIN_DIR . 'includes/admin/upgrades/upgrade-functions.php';
175
	}
176
177
	/**
178
	 * Register plugin add-on updates.
179
	 *
180
	 * @since  1.8.12
181
	 * @access public
182
	 */
183
	public function __register_plugin_addon_updates() {
0 ignored issues
show
Coding Style introduced by
Method name "Give_Updates::__register_plugin_addon_updates" is invalid; only PHP magic methods should be prefixed with a double underscore
Loading history...
184
		$addons         = give_get_plugins();
185
		$plugin_updates = get_plugin_updates();
186
187
		foreach ( $addons as $key => $info ) {
188
			if ( 'active' != $info['Status'] || 'add-on' != $info['Type'] || empty( $plugin_updates[ $key ] ) ) {
189
				continue;
190
			}
191
192
			$this->updates['plugin'][] = array_merge( $info, (array) $plugin_updates[ $key ] );
193
		}
194
	}
195
196
197
	/**
198
	 * Fire custom action hook to register updates
199
	 *
200
	 * @since  1.8.12
201
	 * @access public
202
	 */
203
	public function __register_upgrade() {
0 ignored issues
show
Coding Style introduced by
Method name "Give_Updates::__register_upgrade" is invalid; only PHP magic methods should be prefixed with a double underscore
Loading history...
204
		if ( ! is_admin() ) {
205
			return;
206
		}
207
208
		/**
209
		 * Fire the hook
210
		 *
211
		 * @since 1.8.12
212
		 */
213
		do_action( 'give_register_updates', $this );
214
	}
215
216
	/**
217
	 * Rename `Donations` menu title if updates exists
218
	 *
219
	 * @since  1.8.12
220
	 * @access public
221
	 */
222
	function __change_donations_label() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Coding Style introduced by
Method name "Give_Updates::__change_donations_label" is invalid; only PHP magic methods should be prefixed with a double underscore
Loading history...
223
		global $menu;
224
		global $submenu;
225
226
		// Bailout.
227
		if ( empty( $menu ) || ! $this->get_update_count() ) {
228
			return;
229
		}
230
231
		foreach ( $menu as $index => $menu_item ) {
232
			if ( 'edit.php?post_type=give_forms' !== $menu_item[2] ) {
233
				continue;
234
			}
235
236
			$menu[ $index ][0] = sprintf(
237
				__( 'Donations <span class="update-plugins count-%1$d"><span class="plugin-count">%1$d</span></span>', 'give' ),
238
				$this->get_update_count()
239
			);
240
241
			break;
242
		}
243
	}
244
245
	/**
246
	 * Register updates menu
247
	 *
248
	 * @since  1.8.12
249
	 * @access public
250
	 */
251
	public function __register_menu() {
0 ignored issues
show
Coding Style introduced by
Method name "Give_Updates::__register_menu" is invalid; only PHP magic methods should be prefixed with a double underscore
Loading history...
252
253
		// Load plugin updates.
254
		$this->__register_plugin_addon_updates();
255
256
		// Bailout.
257
		if ( ! $this->get_update_count()) {
0 ignored issues
show
introduced by
No space before closing parenthesis is prohibited
Loading history...
258
			// Show complete update message if still on update setting page.
259
			if ( isset($_GET['page']) && 'give-updates' === $_GET['page'] ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
260
				// Upgrades
261
				add_submenu_page(
262
					'edit.php?post_type=give_forms',
263
					esc_html__( 'Give Updates Complete', 'give' ),
264
					__( 'Updates', 'give' ),
265
					'manage_give_settings',
266
					'give-updates',
267
					array( $this, 'render_complete_page' )
268
				);
269
			}
270
271
			return;
272
		}
273
274
		// Upgrades
275
		add_submenu_page(
276
			'edit.php?post_type=give_forms',
277
			esc_html__( 'Give Updates', 'give' ),
278
			sprintf(
279
				'%1$s <span class="update-plugins count-%2$d"><span class="plugin-count">%2$d</span></span>',
280
				__( 'Updates', 'give' ),
281
				$this->get_update_count()
282
			),
283
			'manage_give_settings',
284
			'give-updates',
285
			array( $this, 'render_page' )
286
		);
287
	}
288
289
	/**
290
	 * Get total updates count
291
	 *
292
	 * @since  1.8.12
293
	 * @access public
294
	 * @return int
295
	 */
296
	public function get_db_update_count() {
297
		return count( $this->get_updates( 'database', 'new' ) );
298
	}
299
300
	/**
301
	 * Render Give Updates Completed page
302
	 *
303
	 * @since  1.8.12
304
	 * @access public
305
	 */
306
	public function render_complete_page() {
307
		include_once GIVE_PLUGIN_DIR . 'includes/admin/upgrades/views/upgrades-complete.php';
308
	}
309
310
	/**
311
	 * Render Give Updates page
312
	 *
313
	 * @since  1.8.12
314
	 * @access public
315
	 */
316
	public function render_page() {
317
		include_once GIVE_PLUGIN_DIR . 'includes/admin/upgrades/views/upgrades.php';
318
	}
319
320
	/**
321
	 * Get addon update count.
322
	 *
323
	 * @since  1.8.12
324
	 * @access public
325
	 * @return int
326
	 */
327
	public function get_plugin_update_count() {
328
		return count( $this->get_updates( 'plugin' ) );
329
	}
330
331
	/**
332
	 * Get total update count
333
	 *
334
	 * @since  1.8.12
335
	 * @access public
336
	 *
337
	 * @return int
338
	 */
339
	public function get_update_count() {
340
		$db_update_count     = $this->get_db_update_count();
341
		$plugin_update_count = $this->get_plugin_update_count();
342
343
		return ( $db_update_count + $plugin_update_count );
344
	}
345
346
347
	/**
348
	 * Delete resume updates
349
	 *
350
	 * @since  1.8.12
351
	 * @access public
352
	 */
353
	public function __flush_resume_updates() {
0 ignored issues
show
Coding Style introduced by
Method name "Give_Updates::__flush_resume_updates" is invalid; only PHP magic methods should be prefixed with a double underscore
Loading history...
354
		delete_option( 'give_doing_upgrade' );
355
		update_option( 'give_version', preg_replace( '/[^0-9.].*/', '', GIVE_VERSION ) );
356
357
		// Reset counter.
358
		$this->step = $this->percentage = 0;
0 ignored issues
show
Documentation Bug introduced by
It seems like 0 of type integer is incompatible with the declared type array of property $percentage.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
Documentation Bug introduced by
It seems like $this->percentage = 0 of type integer is incompatible with the declared type array of property $step.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
359
		++ $this->update;
360
	}
361
362
	/**
363
	 *  Process give updates.
364
	 *
365
	 * @since  1.8.12
366
	 * @access public
367
	 */
368
	public function __give_ajax_updates() {
0 ignored issues
show
Coding Style introduced by
Method name "Give_Updates::__give_ajax_updates" is invalid; only PHP magic methods should be prefixed with a double underscore
Loading history...
369
		// Check permission.
370
		if ( ! current_user_can( 'manage_give_settings' ) ) {
371
			$this->send_ajax_response(
372
				array(
373
					'message' => esc_html__( 'You do not have permission to do Give upgrades.', 'give' ),
374
				),
375
				'error'
376
			);
377
		}
378
379
		// Update timeout error.
380
		ignore_user_abort( true );
381
		if ( ! give_is_func_disabled( 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) {
382
			@set_time_limit( 0 );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Coding Style introduced by
Silencing errors is discouraged
Loading history...
383
		}
384
385
		// Set params.
386
		$this->step   = absint( $_POST['step'] );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
387
		$this->update = absint( $_POST['update'] );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
388
389
		// Bailout: step and update must be positive and greater then zero.
390
		if ( ! $this->step ) {
391
			$this->send_ajax_response(
392
				array(
393
					'message'    => __( 'Please reload this page  and try again', 'give' ),
394
					'heading'    => '',
395
					'percentage' => 0,
396
				),
397
				'error'
398
			);
399
		}
400
401
		// Get updates.
402
		$updates = $this->get_updates( 'database', 'new' );
403
404
		// Bailout if we do not have nay updates.
405 View Code Duplication
		if ( empty( $updates ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
406
			$this->send_ajax_response(
407
				array(
408
					'message'    => __( 'The database is already up to date.', 'give' ),
409
					'heading'    => __( 'Updates Completed.', 'give' ),
410
					'percentage' => 0,
411
				),
412
				'success'
413
			);
414
		}
415
416
		// Process update.
417
		foreach ( $updates as $index => $update ) {
418
			// Check if update depend upon any other update.
419
			if ( ! empty( $update['depend'] ) && ! give_has_upgrade_completed( $update['depend'] ) ) {
420
				continue;
421
			}
422
423
			// Run update.
424
			if ( is_array( $update['callback'] ) ) {
425
				$update['callback'][0]->$update['callback'][1]();
426
			} else {
427
				$update['callback']();
428
			}
429
430
			// Check if current update completed or not.
431 View Code Duplication
			if ( give_has_upgrade_completed( $update['id'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
432
				if ( 1 === count( $updates ) ) {
433
					$this->send_ajax_response(
434
						array(
435
							'message'    => __( 'Database updated successfully.', 'give' ),
436
							'heading'    => __( 'Updates Completed.', 'give' ),
437
							'percentage' => 0,
438
						),
439
						'success'
440
					);
441
				}
442
			}
443
444
			$doing_upgrade_args = array(
445
				'update_info' => $update,
446
				'step'        => ++ $this->step,
447
				'update'      => $this->update,
448
				'heading'     => sprintf( 'Update %s of {update_count}', $this->update ),
449
				'percentage'  => $this->percentage,
450
			);
451
452
			// Cache upgrade.
453
			update_option( 'give_doing_upgrade', $doing_upgrade_args );
454
455
			$this->send_ajax_response( $doing_upgrade_args );
456
		}// End foreach().
457
	}
458
459
	/**
460
	 * Send ajax response
461
	 *
462
	 * @since  1.8.12
463
	 * @access public
464
	 *
465
	 * @param        $data
466
	 * @param string $type
467
	 */
468
	public function send_ajax_response( $data, $type = '' ) {
469
		$default = array(
470
			'message'    => '',
471
			'heading'    => '',
472
			'percentage' => 0,
473
			'step'       => 0,
474
			'update'     => 0,
475
		);
476
477
		// Set data.
478
		$data = wp_parse_args( $data, $default );
479
480
		switch ( $type ) {
481
			case 'success':
482
				wp_send_json_success( $data );
483
				break;
484
485
			case 'error':
486
				wp_send_json_error( $data );
487
				break;
488
489
			default:
490
				wp_send_json( array(
491
					'data' => $data,
492
				) );
493
				break;
494
		}
495
	}
496
497
498
	/**
499
	 * Resume updates
500
	 *
501
	 * @since  1.8.12
502
	 * @access public
503
	 *
504
	 * @return bool|int
505
	 */
506
	public function resume_updates() {
507
		$status = false;
508
509
		if ( $update = get_option( 'give_doing_upgrade' ) ) {
510
			$status = ! empty( $update['step'] ) ? $update['step'] : $status;
511
		}
512
513
		return $status;
514
	}
515
516
517
	/**
518
	 * Set current update percentage.
519
	 *
520
	 * @since  1.8.12
521
	 * @access public
522
	 *
523
	 * @param $total
524
	 * @param $current_total
525
	 */
526
	public function set_percentage( $total, $current_total ) {
527
		// Set percentage.
528
		$this->percentage = $total ? ( ( $current_total ) / $total ) * 100 : 0;
0 ignored issues
show
Documentation Bug introduced by
It seems like $total ? $current_total / $total * 100 : 0 of type integer or double is incompatible with the declared type array of property $percentage.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
529
530
		// Verify percentage.
531
		$this->percentage = ( 100 < $this->percentage ) ? 100 : $this->percentage;
0 ignored issues
show
Documentation Bug introduced by
It seems like 100 < $this->percentage ? 100 : $this->percentage of type integer or double is incompatible with the declared type array of property $percentage.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
532
	}
533
}
534
535
Give_Updates::get_instance()->setup();
536