Give_Background_Updater::flush_cache()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 18
rs 9.6666
c 0
b 0
f 0
1
<?php
2
/**
3
 * Background Updater
4
 *
5
 * Uses https://github.com/A5hleyRich/wp-background-processing to handle DB
6
 * updates in the background.
7
 *
8
 * @class    Give_Background_Updater
9
 * @version  2.0.0
10
 * @package  Give/Classes
11
 * @category Class
12
 * @author   WordImpress
13
 */
14
if ( ! defined( 'ABSPATH' ) ) {
15
	exit;
16
}
17
18
/**
19
 * Give_Background_Updater Class.
20
 */
21
class Give_Background_Updater extends WP_Background_Process {
22
23
	/**
24
	 * @var string
25
	 */
26
	protected $action = 'give_db_updater';
27
28
	/**
29
	 * Dispatch updater.
30
	 *
31
	 * Updater will still run via cron job if this fails for any reason.
32
	 */
33
	public function dispatch() {
34
		if ( give_test_ajax_works() ) {
35
			parent::dispatch();
36
		} elseif ( wp_doing_ajax() ) {
37
			$this->maybe_handle();
38
		}
39
	}
40
41
42
	/**
43
	 * Get all batches.
44
	 *
45
	 * @since  2.0
46
	 * @access public
47
	 * @return stdClass
48
	 */
49
	public function get_all_batch() {
50
		return parent::get_batch();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (get_batch() instead of get_all_batch()). Are you sure this is correct? If so, you might want to change this to $this->get_batch().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
51
	}
52
53
	/**
54
	 * Is queue empty
55
	 *
56
	 * @since 2.0.3
57
	 *
58
	 * @return bool
59
	 */
60
	public function has_queue() {
61
		return ( ! parent::is_queue_empty() );
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (is_queue_empty() instead of has_queue()). Are you sure this is correct? If so, you might want to change this to $this->is_queue_empty().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
62
	}
63
64
65
	/**
66
	 * Lock process
67
	 *
68
	 * Lock the process so that multiple instances can't run simultaneously.
69
	 * Override if applicable, but the duration should be greater than that
70
	 * defined in the time_exceeded() method.
71
	 *
72
	 *
73
	 * @since 2.0.3
74
	 */
75
	protected function lock_process() {
76
		// Check if admin want to pause upgrade.
77
		if( get_option('give_pause_upgrade') ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
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...
78
			self::flush_cache();
79
80
			delete_option( 'give_paused_batches' );
81
82
			Give_Updates::get_instance()->__pause_db_update( true );
83
84
			delete_option('give_pause_upgrade');
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...
85
86
			/**
87
			 * Fire action when pause db updates
88
			 *
89
			 * @since 2.0.1
90
			 */
91
			do_action( 'give_pause_db_upgrade', Give_Updates::get_instance() );
92
93
			wp_die();
94
		}
95
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
96
97
		$this->start_time = time(); // Set start time of current process.
98
99
		$lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
100
		$lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
101
102
		set_site_transient( $this->identifier . '_process_lock', microtime(), $lock_duration );
103
	}
104
105
	/**
106
	 * Handle cron healthcheck
107
	 *
108
	 * Restart the background process if not already running
109
	 * and data exists in the queue.
110
	 */
111
	public function handle_cron_healthcheck() {
112
		if ( $this->is_process_running() || $this->is_paused_process()  ) {
113
			// Background process already running.
114
			return;
115
		}
116
117
		if ( $this->is_queue_empty() ) {
118
			// No data to process.
119
			$this->clear_scheduled_event();
120
121
			return;
122
		}
123
124
		$this->handle();
125
	}
126
127
	/**
128
	 * Schedule fallback event.
129
	 */
130
	protected function schedule_event() {
131
		if ( ! wp_next_scheduled( $this->cron_hook_identifier ) && ! $this->is_paused_process() ) {
132
			wp_schedule_event( time() + 10, $this->cron_interval_identifier, $this->cron_hook_identifier );
133
		}
134
	}
135
136
	/**
137
	 * Task
138
	 *
139
	 * Override this method to perform any actions required on each
140
	 * queue item. Return the modified item for further processing
141
	 * in the next pass through. Or, return false to remove the
142
	 * item from the queue.
143
	 *
144
	 * @param array $update Update info
145
	 *
146
	 * @return mixed
147
	 */
148
	protected function task( $update ) {
149
		// Pause upgrade immediately if admin pausing upgrades.
150
		if( $this->is_paused_process() ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
151
			wp_die();
152
		}
153
154
		if ( empty( $update ) ) {
155
			return false;
156
		}
157
158
		// Delete cache.
159
		self::flush_cache();
160
161
		/* @var  Give_Updates $give_updates */
162
		$give_updates  = Give_Updates::get_instance();
163
		$resume_update = get_option(
164
			'give_doing_upgrade',
165
0 ignored issues
show
Coding Style introduced by
There should be no empty lines in a multi-line function call.
Loading history...
166
			// Default update.
167
			array(
168
				'update_info'      => $update,
169
				'step'             => 1,
170
				'update'           => 1,
171
				'heading'          => sprintf( 'Update %s of {update_count}', 1 ),
172
				'percentage'       => $give_updates->percentage,
173
				'total_percentage' => 0,
174
			)
175
		);
176
177
		// Continuously skip update if previous update does not complete yet.
178
		if (
179
			$resume_update['update_info']['id'] !== $update['id'] &&
180
			! give_has_upgrade_completed( $resume_update['update_info']['id'] )
181
		) {
182
			return $update;
183
		}
184
185
		// Set params.
186
		$resume_update['update_info'] = $update;
187
		$give_updates->step           = absint( $resume_update['step'] );
188
		$give_updates->update         = absint( $resume_update['update'] );
189
		$is_parent_update_completed   = $give_updates->is_parent_updates_completed( $update );
190
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
191
192
		// Skip update if dependency update does not complete yet.
193
		if ( empty( $is_parent_update_completed ) ) {
194
			// @todo: set error when you have only one update with invalid dependency
195
			if ( ! is_null( $is_parent_update_completed ) ) {
196
				return $update;
197
			}
198
199
			return false;
200
		}
201
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
202
203
		// Pause upgrade immediately if found following:
204
		// 1. Running update number greater then total update count
205
		// 2. Processing percentage greater then 100%
206
		if( (
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
207
			101 < $resume_update['total_percentage'] ) ||
208
		    ( $give_updates->get_total_db_update_count() < $resume_update['update'] ) ||
209
		    ! in_array( $resume_update['update_info']['id'], $give_updates->get_update_ids() )
210
		) {
211
			if( ! $this->is_paused_process() ){
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
212
				$give_updates->__pause_db_update(true);
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...
213
			}
214
215
			update_option( 'give_upgrade_error', 1, false );
216
217
			$log_data = 'Update Task' . "\n";
218
			$log_data .= "Total update count: {$give_updates->get_total_db_update_count()}\n";
219
			$log_data .= 'Update IDs: ' . print_r( $give_updates->get_update_ids() , true );
0 ignored issues
show
introduced by
The use of function print_r() is discouraged
Loading history...
220
			$log_data .= 'Update: ' . print_r( $resume_update , true );
0 ignored issues
show
introduced by
The use of function print_r() is discouraged
Loading history...
221
222
			Give()->logs->add( 'Update Error', $log_data, 0, 'update' );
223
224
			wp_die();
225
		}
226
227
		// Disable cache.
228
		Give_Cache::disable();
229
230
		try{
231
			// Run update.
232
			if ( is_array( $update['callback'] ) ) {
233
				$update['callback'][0]->$update['callback'][1]();
234
			} else {
235
				$update['callback']();
236
			}
237
		} catch ( Exception $e ){
238
239
			if( ! $this->is_paused_process() ){
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
240
				$give_updates->__pause_db_update(true);
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...
241
			}
242
243
			$log_data = 'Update Task' . "\n";
244
			$log_data .= print_r( $resume_update, true ) . "\n\n";
0 ignored issues
show
introduced by
The use of function print_r() is discouraged
Loading history...
245
			$log_data .= "Error\n {$e->getMessage()}";
246
247
			Give()->logs->add( 'Update Error', $log_data, 0, 'update' );
248
			update_option( 'give_upgrade_error', 1, false );
249
250
			wp_die();
251
		}
252
253
		// Set update info.
254
		$doing_upgrade_args = array(
255
			'update_info'      => $update,
256
			'step'             => ++ $give_updates->step,
257
			'update'           => $give_updates->update,
258
			'heading'          => sprintf( 'Update %s of %s', $give_updates->update, get_option( 'give_db_update_count' ) ),
259
			'percentage'       => $give_updates->percentage,
260
			'total_percentage' => $give_updates->get_db_update_processing_percentage(),
261
		);
262
263
		// Cache upgrade.
264
		update_option( 'give_doing_upgrade', $doing_upgrade_args, false );
265
266
		// Enable cache.
267
		Give_Cache::enable();
268
269
		// Check if current update completed or not.
270
		if ( give_has_upgrade_completed( $update['id'] ) ) {
271
			return false;
272
		}
273
274
		return $update;
275
	}
276
277
	/**
278
	 * Complete
279
	 *
280
	 * Override if applicable, but ensure that the below actions are
281
	 * performed, or, call parent::complete().
282
	 */
283
	public function complete() {
284
		if ( $this->is_paused_process() ) {
285
			return false;
286
		}
287
288
		parent::complete();
289
290
		delete_option( 'give_pause_upgrade' );
291
		delete_option( 'give_upgrade_error' );
292
		delete_option( 'give_db_update_count' );
293
		delete_option( 'give_doing_upgrade' );
294
		add_option( 'give_show_db_upgrade_complete_notice', 1, '', false );
295
296
		// Flush cache.
297
		Give_Cache::flush_cache( true );
298
299
		if ( $cache_keys = Give_Cache::get_options_like( '' ) ) {
300
			Give_Cache::delete( $cache_keys );
301
		}
302
	}
303
304
	/**
305
	 * Get memory limit
306
	 *
307
	 * @return int
308
	 */
309
	protected function get_memory_limit() {
310
		if ( function_exists( 'ini_get' ) ) {
311
			$memory_limit = ini_get( 'memory_limit' );
312
		} else {
313
			// Sensible default.
314
			$memory_limit = '128M';
315
		}
316
317
		if ( ! $memory_limit || '-1' === $memory_limit ) {
318
			// Unlimited, set to 32GB.
319
			$memory_limit = '32000M';
320
		}
321
322
		return intval( $memory_limit ) * 1024 * 1024;
323
	}
324
325
	/**
326
	 * Maybe process queue
327
	 *
328
	 * Checks whether data exists within the queue and that
329
	 * the process is not already running.
330
	 */
331
	public function maybe_handle() {
332
		// Don't lock up other requests while processing
333
		session_write_close();
0 ignored issues
show
introduced by
The use of PHP session function session_write_close() is prohibited.
Loading history...
334
335
		if ( $this->is_process_running() || $this->is_paused_process() ) {
336
			// Background process already running.
337
			wp_die();
338
		}
339
340
		if ( $this->is_queue_empty() ) {
341
			// No data to process.
342
			wp_die();
343
		}
344
345
		check_ajax_referer( $this->identifier, 'nonce' );
346
347
		$this->handle();
348
349
		wp_die();
350
	}
351
352
	/**
353
	 * Handle
354
	 *
355
	 * Pass each queue item to the task handler, while remaining
356
	 * within server memory and time limit constraints.
357
	 */
358
	protected function handle() {
359
		$this->lock_process();
360
361
		do {
362
			$batch = $this->get_batch();
363
364
			foreach ( $batch->data as $key => $value ) {
365
				$task = $this->task( $value );
366
367
				if ( false !== $task ) {
368
					$batch->data[ $key ] = $task;
369
				} else {
370
					unset( $batch->data[ $key ] );
371
				}
372
373
				if ( $this->time_exceeded() || $this->memory_exceeded() ) {
374
					// Batch limits reached.
375
					break;
376
				}
377
			}
378
379
			// Update or delete current batch.
380
			if ( ! empty( $batch->data ) ) {
381
				$this->update( $batch->key, $batch->data );
382
			} else {
383
				$this->delete( $batch->key );
384
			}
385
		} while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
386
387
		$this->unlock_process();
388
389
		// Start next batch or complete process.
390
		if ( ! $this->is_queue_empty() ) {
391
392
			// Dispatch only if ajax works.
393
			if( give_test_ajax_works() ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
394
				$this->dispatch();
395
			}
396
		} else {
397
			$this->complete();
398
		}
399
400
		wp_die();
401
	}
402
403
404
	/**
405
	 * Check if backgound upgrade paused or not.
406
	 *
407
	 * @since 2.0
408
	 * @access public
409
	 * @return bool
410
	 */
411
	public function is_paused_process(){
412
		// Delete cache.
413
		wp_cache_delete( 'give_paused_batches', 'options' );
414
415
		$paused_batches = get_option('give_paused_batches');
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...
416
417
		return ! empty( $paused_batches );
418
	}
419
420
421
	/**
422
	 * Get identifier
423
	 *
424
	 * @since  2.0
425
	 * @access public
426
	 * @return mixed|string
427
	 */
428
	public function get_identifier() {
429
		return $this->identifier;
430
	}
431
432
	/**
433
	 * Get cron identifier
434
	 *
435
	 * @since  2.0
436
	 * @access public
437
	 * @return mixed|string
438
	 */
439
	public function get_cron_identifier() {
440
		return $this->cron_hook_identifier;
441
	}
442
443
444
	/**
445
	 * Flush background update related cache to prevent task to go to stalled state.
446
	 *
447
	 * @since 2.0.3
448
	 */
449
	public static function flush_cache() {
450
451
		$options = array(
452
			'give_completed_upgrades',
453
			'give_doing_upgrade',
454
			'give_paused_batches',
455
			'give_upgrade_error',
456
			'give_db_update_count',
457
			'give_doing_upgrade',
458
			'give_pause_upgrade',
459
			'give_show_db_upgrade_complete_notice',
460
		);
461
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
462
463
		foreach ( $options as $option ) {
464
			wp_cache_delete( $option, 'options' );
465
		}
466
	}
467
}
468