Test Failed
Pull Request — master (#2054)
by Devin
05:04
created

Give_Updates::__flush_resume_updates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 8
rs 9.4285
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 %s', 'give' ),
238
				sprintf(
239
					'<span class="update-plugins count-%1$d"><span class="plugin-count">%1$d</span></span>',
240
					$this->get_update_count()
241
				)
242
			);
243
244
			break;
245
		}
246
	}
247
248
	/**
249
	 * Register updates menu
250
	 *
251
	 * @since  1.8.12
252
	 * @access public
253
	 */
254
	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...
255
256
		// Load plugin updates.
257
		$this->__register_plugin_addon_updates();
258
259
		// Bailout.
260
		if ( ! $this->get_update_count()) {
0 ignored issues
show
introduced by
No space before closing parenthesis is prohibited
Loading history...
261
			// Show complete update message if still on update setting page.
262
			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...
263
				// Upgrades
264
				add_submenu_page(
265
					'edit.php?post_type=give_forms',
266
					esc_html__( 'Give Updates Complete', 'give' ),
267
					__( 'Updates', 'give' ),
268
					'manage_give_settings',
269
					'give-updates',
270
					array( $this, 'render_complete_page' )
271
				);
272
			}
273
274
			return;
275
		}
276
277
		// Upgrades
278
		add_submenu_page(
279
			'edit.php?post_type=give_forms',
280
			esc_html__( 'Give Updates', 'give' ),
281
			sprintf(
282
				'%1$s <span class="update-plugins count-%2$d"><span class="plugin-count">%2$d</span></span>',
283
				__( 'Updates', 'give' ),
284
				$this->get_update_count()
285
			),
286
			'manage_give_settings',
287
			'give-updates',
288
			array( $this, 'render_page' )
289
		);
290
	}
291
292
	/**
293
	 * Get total updates count
294
	 *
295
	 * @since  1.8.12
296
	 * @access public
297
	 * @return int
298
	 */
299
	public function get_db_update_count() {
300
		return count( $this->get_updates( 'database', 'new' ) );
301
	}
302
303
	/**
304
	 * Render Give Updates Completed page
305
	 *
306
	 * @since  1.8.12
307
	 * @access public
308
	 */
309
	public function render_complete_page() {
310
		include_once GIVE_PLUGIN_DIR . 'includes/admin/upgrades/views/upgrades-complete.php';
311
	}
312
313
	/**
314
	 * Render Give Updates page
315
	 *
316
	 * @since  1.8.12
317
	 * @access public
318
	 */
319
	public function render_page() {
320
		include_once GIVE_PLUGIN_DIR . 'includes/admin/upgrades/views/upgrades.php';
321
	}
322
323
	/**
324
	 * Get addon update count.
325
	 *
326
	 * @since  1.8.12
327
	 * @access public
328
	 * @return int
329
	 */
330
	public function get_plugin_update_count() {
331
		return count( $this->get_updates( 'plugin' ) );
332
	}
333
334
	/**
335
	 * Get total update count
336
	 *
337
	 * @since  1.8.12
338
	 * @access public
339
	 *
340
	 * @return int
341
	 */
342
	public function get_update_count() {
343
		$db_update_count     = $this->get_db_update_count();
344
		$plugin_update_count = $this->get_plugin_update_count();
345
346
		return ( $db_update_count + $plugin_update_count );
347
	}
348
349
350
	/**
351
	 * Delete resume updates
352
	 *
353
	 * @since  1.8.12
354
	 * @access public
355
	 */
356
	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...
357
		delete_option( 'give_doing_upgrade' );
358
		update_option( 'give_version', preg_replace( '/[^0-9.].*/', '', GIVE_VERSION ) );
359
360
		// Reset counter.
361
		$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...
362
		++ $this->update;
363
	}
364
365
	/**
366
	 *  Process give updates.
367
	 *
368
	 * @since  1.8.12
369
	 * @access public
370
	 */
371
	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...
372
		// Check permission.
373
		if ( ! current_user_can( 'manage_give_settings' ) ) {
374
			$this->send_ajax_response(
375
				array(
376
					'message' => esc_html__( 'You do not have permission to do Give upgrades.', 'give' ),
377
				),
378
				'error'
379
			);
380
		}
381
382
		// Set params.
383
		$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...
384
		$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...
385
386
		// Bailout: step and update must be positive and greater then zero.
387
		if ( ! $this->step ) {
388
			$this->send_ajax_response(
389
				array(
390
					'message'    => __( 'Please reload this page  and try again', 'give' ),
391
					'heading'    => '',
392
					'percentage' => 0,
393
				),
394
				'error'
395
			);
396
		}
397
398
		// Get updates.
399
		$updates = $this->get_updates( 'database', 'new' );
400
401
		// Bailout if we do not have nay updates.
402 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...
403
			$this->send_ajax_response(
404
				array(
405
					'message'    => __( 'The database is already up to date.', 'give' ),
406
					'heading'    => __( 'Updates Completed.', 'give' ),
407
					'percentage' => 0,
408
				),
409
				'success'
410
			);
411
		}
412
413
		// Process update.
414
		foreach ( $updates as $index => $update ) {
415
			// Check if update depend upon any other update.
416
			if ( ! empty( $update['depend'] ) && ! give_has_upgrade_completed( $update['depend'] ) ) {
417
				continue;
418
			}
419
420
			// Run update.
421
			if ( is_array( $update['callback'] ) ) {
422
				$update['callback'][0]->$update['callback'][1]();
423
			} else {
424
				$update['callback']();
425
			}
426
427
			// Check if current update completed or not.
428 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...
429
				if ( 1 === count( $updates ) ) {
430
					$this->send_ajax_response(
431
						array(
432
							'message'    => __( 'Database updated successfully.', 'give' ),
433
							'heading'    => __( 'Updates Completed.', 'give' ),
434
							'percentage' => 0,
435
						),
436
						'success'
437
					);
438
				}
439
			}
440
441
			$doing_upgrade_args = array(
442
				'update_info' => $update,
443
				'step'        => ++ $this->step,
444
				'update'      => $this->update,
445
				'heading'     => sprintf( 'Update %s of {update_count}', $this->update ),
446
				'percentage'  => $this->percentage,
447
			);
448
449
			// Cache upgrade.
450
			update_option( 'give_doing_upgrade', $doing_upgrade_args );
451
452
			$this->send_ajax_response( $doing_upgrade_args );
453
		}// End foreach().
454
	}
455
456
	/**
457
	 * Send ajax response
458
	 *
459
	 * @since  1.8.12
460
	 * @access public
461
	 *
462
	 * @param        $data
463
	 * @param string $type
464
	 */
465
	public function send_ajax_response( $data, $type = '' ) {
466
		$default = array(
467
			'message'    => '',
468
			'heading'    => '',
469
			'percentage' => 0,
470
			'step'       => 0,
471
			'update'     => 0,
472
		);
473
474
		// Set data.
475
		$data = wp_parse_args( $data, $default );
476
477
		switch ( $type ) {
478
			case 'success':
479
				wp_send_json_success( $data );
480
				break;
481
482
			case 'error':
483
				wp_send_json_error( $data );
484
				break;
485
486
			default:
487
				wp_send_json( array(
488
					'data' => $data,
489
				) );
490
				break;
491
		}
492
	}
493
494
495
	/**
496
	 * Resume updates
497
	 *
498
	 * @since  1.8.12
499
	 * @access public
500
	 *
501
	 * @return bool|int
502
	 */
503
	public function resume_updates() {
504
		$status = false;
505
506
		if ( $update = get_option( 'give_doing_upgrade' ) ) {
507
			$status = ! empty( $update['step'] ) ? $update['step'] : $status;
508
		}
509
510
		return $status;
511
	}
512
513
514
	/**
515
	 * Set current update percentage.
516
	 *
517
	 * @since  1.8.12
518
	 * @access public
519
	 *
520
	 * @param $total
521
	 * @param $current_total
522
	 */
523
	public function set_percentage( $total, $current_total ) {
524
		// Set percentage.
525
		$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...
526
527
		// Verify percentage.
528
		$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...
529
	}
530
}
531
532
Give_Updates::get_instance()->setup();
533