GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#936)
by Tom
03:29
created

Scheduled_Backup::get_backups()   C

Complexity

Conditions 7
Paths 2

Size

Total Lines 23
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 23
rs 6.7272
cc 7
eloc 9
nc 2
nop 0
1
<?php
2
3
namespace HM\BackUpWordPress;
4
5
/**
6
 * The Backup Scheduler
7
 *
8
 * Handles everything related to managing and running a backup schedule
9
 *
10
 * @uses Backup
11
 * @uses
12
 */
13
class Scheduled_Backup {
14
15
	/**
16
	 * The unique schedule id
17
	 *
18
	 * @var string
19
	 * @access private
20
	 */
21
	private $id = '';
22
23
	/**
24
	 * The slugified version of the schedule name
25
	 *
26
	 * @var string
27
	 * @access private
28
	 */
29
	private $slug = '';
30
31
	/**
32
	 * The raw schedule options from the database
33
	 *
34
	 * @var array
35
	 * @access private
36
	 */
37
	private $options = array(
38
		'max_backups'   => 3,
39
		'excludes'      => array(),
40
		'type'          => 'complete',
41
		'reoccurrence'  => 'manually'
42
	);
43
44
	/**
45
	 * Setup the schedule object
46
	 * Loads the options from the database and populates properties
47
	 *
48
	 * @param string $id
49
	 *
50
	 * @throws Exception
51
	 */
52
53
	public function __construct( $id ) {
54
55
		// Verify the schedule id
56
		if ( ! is_string( $id ) || ! trim( $id ) ) {
57
			throw new \Exception( 'Argument 1 for ' . __METHOD__ . ' must be a non-empty string' );
58
		}
59
60
		// Store id for later
61
		$this->id = $id;
62
63
		// Load the options
64
		$this->options = array_merge( $this->options, array_filter( (array) get_option( 'hmbkp_schedule_' . $this->get_id() ) ) );
65
66
		if ( defined( 'HMBKP_SCHEDULE_START_TIME' ) && strtotime( 'HMBKP_SCHEDULE_START_TIME' ) ) {
67
			$this->set_schedule_start_time( strtotime( 'HMBKP_SCHEDULE_START_TIME' ) );
0 ignored issues
show
Documentation introduced by
strtotime('HMBKP_SCHEDULE_START_TIME') is of type integer, but the function expects a object<HM\BackUpWordPress\timestamp>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
68
		}
69
70
		// Setup the schedule if it isn't set
71
		if ( ( ! $this->is_cron_scheduled() && $this->get_reoccurrence() !== 'manually' ) ) {
72
			$this->schedule();
73
		}
74
75
		$this->backup_filename = implode( '-', array(
0 ignored issues
show
Bug introduced by
The property backup_filename does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
76
			sanitize_title( str_ireplace( array(
77
				'http://',
78
				'https://',
79
				'www'
80
			), '', home_url() ) ),
81
			$this->get_id(),
82
			$this->get_type(),
83
			current_time( 'Y-m-d-H-i-s' )
84
		) ) . '.zip';
85
86
		$this->database_dump_filename = implode( '-', array(
0 ignored issues
show
Bug introduced by
The property database_dump_filename does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
87
			'database',
88
			sanitize_title( str_ireplace( array( 'http://', 'https://', 'www' ), '', home_url() ) ),
89
			$this->get_id()
90
		) ) . '.sql';
91
92
		$this->status = new Backup_Status( $this->get_id() );
0 ignored issues
show
Bug introduced by
The property status does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
93
94
	}
95
96
	/**
97
	 * Get the id for this schedule
98
	 */
99
	public function get_id() {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
100
		return esc_attr( $this->id );
101
	}
102
103
	/**
104
	 * Get a slugified version of name
105
	 */
106
	public function get_slug() {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
107
108
		// We cache slug in $this to save expensive calls to sanitize_title
109
		if ( ! empty( $this->slug ) ) {
110
			return $this->slug;
111
		}
112
113
		return $this->slug = sanitize_title( $this->get_name() );
114
115
	}
116
117
	/**
118
	 * Returns the given option value
119
	 *
120
	 * @param $option_name
121
	 * @return mixed The option value
122
	 */
123
	public function get_schedule_option( $option_name ) {
124
		if ( isset( $this->options[ $option_name ] ) ) {
125
			return $this->options[ $option_name ];
126
		}
127
	}
128
129
	/**
130
	 * Get the name of this backup schedule
131
	 *
132
	 * @return string
133
	 */
134
	public function get_name() {
135
		return ucwords( $this->get_type() ) . ' ' . $this->get_reoccurrence();
136
	}
137
138
	/**
139
	 * Get the type of backup
140
	 *
141
	 * @return string
142
	 */
143
	public function get_type() {
144
		return $this->options['type'];
145
	}
146
147
	/**
148
	 * Set the type of backup
149
	 *
150
	 * @param string $type
151
	 */
152
	public function set_type( $type ) {
153
		if ( ! isset( $this->options['type'] ) || $this->options['type'] !== $type ) {
154
			$this->options['type'] = $type;
155
		}
156
	}
157
158
	/**
159
	 * Get the exclude rules
160
	 *
161
	 * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be Excludes?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
162
	 */
163
	public function get_excludes() {
164
		return new Excludes( $this->options['excludes'] );
165
	}
166
167
	/**
168
	 * Set the exclude rules
169
	 *
170
	 * @param mixed $excludes A comma separated list or array of exclude rules
0 ignored issues
show
Bug introduced by
There is no parameter named $excludes. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
171
	 * @param bool $append Whether to replace or append to existing rules
172
	 *
173
	 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
174
	 */
175
	public function set_excludes( $exclude_rules, $append = false ) {
176
177
		// Normalize the exclude rules before we save them
178
		$excludes = new Excludes;
179
		$excludes = $excludes->normalize( (array) $exclude_rules );
180
181
		// If these are valid excludes and they are different save them
182
		if ( empty( $this->options['excludes'] ) || $this->options['excludes'] !== $excludes ) {
183
			$this->options['excludes'] = $append && ! empty( $this->options['excludes'] ) ? array_merge( (array) $this->options['excludes'], (array) $excludes ) : (array) $excludes;
184
		}
185
186
	}
187
188
	/**
189
	 * Get the maximum number of backups to keep
190
	 *
191
	 * @return int
192
	 */
193
	public function get_max_backups() {
194
		return (int) $this->options['max_backups'];
195
	}
196
197
	/**
198
	 * Set the maximum number of backups to keep
199
	 *
200
	 * @param int $max
201
	 *
202
	 * @return WP_Error|boolean
0 ignored issues
show
Documentation introduced by
Should the return type not be WP_Error|boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
203
	 */
204
	public function set_max_backups( $max ) {
205
		$this->options['max_backups'] = $max;
206
	}
207
208
	public function get_status() {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
209
		return $this->status;
210
	}
211
212
	/**
213
	 * Back compat with old set_status mathod
214
	 *
215
 	 * @deprecated 3.4 Backup->status->set_status()
216
	 */
217
	public function set_status( $message ) {
218
		_deprecated_function( __FUNCTION__, '3.4', 'Backup->status->set_status()' );
219
		$this->status->set_status( $message );
220
	}
221
222
	/**
223
	 * Get the array of services options for this schedule
224
	 *
225
	 * @param      $service
226
	 * @param null $option
227
	 *
228
	 * @return array
229
	 */
230
	public function get_service_options( $service, $option = null ) {
231
232
		if ( ! is_null( $option ) ) {
233
234
			if ( isset( $this->options[ $service ][ $option ] ) ) {
235
				return $this->options[ $service ][ $option ];
236
			}
237
238
			return array();
239
240
		}
241
242
		if ( isset( $this->options[ $service ] ) ) {
243
			return $this->options[ $service ];
244
		}
245
246
		return array();
247
248
	}
249
250
	/**
251
	 * Set the service options for this schedule
252
	 *
253
	 * @param $service
254
	 * @param array $options
255
	 */
256
	public function set_service_options( $service, Array $options ) {
257
		$this->options[ $service ] = $options;
258
	}
259
260
	/**
261
	 * Get the start time for the schedule
262
	 *
263
	 * @return int timestamp || 0 for manual only schedules
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
264
	 */
265
	public function get_schedule_start_time( $gmt = true ) {
266
267
		if ( 'manually' === $this->get_reoccurrence() ) {
268
			return 0;
269
		}
270
271
		if ( ! $gmt ) {
272
			$offset = get_option( 'gmt_offset' ) * 3600;
273
		} else {
274
			$offset = 0;
275
		}
276
277
		if ( ! empty( $this->options['schedule_start_time'] ) ) {
278
			return $this->options['schedule_start_time'] + $offset;
279
		}
280
281
		$this->set_schedule_start_time( time() );
0 ignored issues
show
Documentation introduced by
time() is of type integer, but the function expects a object<HM\BackUpWordPress\timestamp>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
282
283
		return time() + $offset;
284
285
	}
286
287
	/**
288
	 * Set the schedule start time.
289
	 *
290
	 * @param timestamp $time
291
	 */
292
	public function set_schedule_start_time( $time ) {
293
294
		$this->options['schedule_start_time'] = $time;
295
296
		$this->schedule();
297
298
	}
299
300
	/**
301
	 * Get the schedule reoccurrence
302
	 *
303
	 */
304
	public function get_reoccurrence() {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
305
		return $this->options['reoccurrence'];
306
	}
307
308
	/**
309
	 * Set the schedule reoccurrence
310
	 *
311
	 * @param string $reoccurrence
312
	 *
313
	 * @return \WP_Error|null|boolean
314
	 */
315
	public function set_reoccurrence( $reoccurrence ) {
316
317
		$hmbkp_schedules = cron_schedules();
318
319
		// Check it's valid
320
		if ( ! is_string( $reoccurrence ) || ! trim( $reoccurrence ) || ( ! in_array( $reoccurrence, array_keys( $hmbkp_schedules ) ) ) && 'manually' !== $reoccurrence ) {
321
			return new \WP_Error( 'hmbkp_invalid_argument_error', sprintf( __( 'Argument 1 for %s must be a valid cron recurrence or "manually"', 'backupwordpress' ), __METHOD__ ) );
322
		}
323
324
		// If the recurrence is already set to the same thing then there's no need to continue
325
		if ( isset( $this->options['reoccurrence'] ) && $this->options['reoccurrence'] === $reoccurrence && $this->is_cron_scheduled() ) {
326
			return;
327
		}
328
329
330
		$this->options['reoccurrence'] = $reoccurrence;
331
332
		if ( 'manually' === $reoccurrence ) {
333
			$this->unschedule();
334
335
		} else {
336
			$this->schedule();
337
		}
338
339
		return true;
340
341
	}
342
343
	/**
344
	 * Get the interval between backups
345
	 *
346
	 * @return int
347
	 */
348
	public function get_interval() {
349
350
		$hmbkp_schedules = cron_schedules();
351
352
		if ( 'manually' === $this->get_reoccurrence() ) {
353
			return 0;
354
		}
355
356
		return $hmbkp_schedules[ $this->get_reoccurrence() ]['interval'];
357
358
	}
359
360
	/**
361
	 * Get the next occurrence of this scheduled backup
362
	 *
363
	 */
364
	public function get_next_occurrence( $gmt = true ) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
365
366
		$time = wp_next_scheduled( 'hmbkp_schedule_hook', array( 'id' => $this->get_id() ) );
367
368
		if ( ! $time ) {
369
			$time = 0;
370
		}
371
372
		if ( ! $gmt ) {
373
			$time += get_option( 'gmt_offset' ) * 3600;
374
		}
375
376
		return $time;
377
378
	}
379
380
	public function is_cron_scheduled() {
381
		return (bool) $this->get_next_occurrence();
382
	}
383
384
	/**
385
	 * Schedule the backup cron
386
	 *
387
	 */
388
	public function schedule() {
389
390
		// Clear any existing hooks
391
		$this->unschedule();
392
393
		$schedule_timestamp = $this->get_schedule_start_time();
394
395
		wp_schedule_event( $schedule_timestamp, $this->get_reoccurrence(), 'hmbkp_schedule_hook', array( 'id' => $this->get_id() ) );
396
397
	}
398
399
400
	/**
401
	 * Unschedule the backup cron.
402
	 *
403
	 * @return void
404
	 */
405
	public function unschedule() {
406
		wp_clear_scheduled_hook( 'hmbkp_schedule_hook', array( 'id' => $this->get_id() ) );
407
	}
408
409
	/**
410
	 * Run the backup
411
	 *
412
	 */
413
	public function run() {
414
415
		// Don't run if this schedule is already running
416
		if ( $this->status->is_started() ) {
417
			return;
418
		}
419
420
		// Setup our Site Backup Object
421
		$backup = new Backup( $this->get_backup_filename(), $this->get_database_dump_filename() );
422
		$backup->set_type( $this->get_type() );
423
		$backup->set_excludes( $this->get_excludes() );
424
		$backup->set_status( $this->status );
425
426
		$this->do_action( 'hmbkp_backup_started', $backup );
427
428
		$this->status->start( $this->get_backup_filename(), __( 'Starting backup...', 'backupwordpress' ) );
429
430
		$this->status->set_status( __( 'Deleting old backups...', 'backupwordpress' ) );
431
432
		// Delete old backups now in-case we fatal error during the backup process
433
		$this->delete_old_backups();
434
435
		$backup->run();
436
437
		$errors = array_merge( $backup->errors, $backup->warnings );
438
		$notices = array();
439
		foreach ( $errors as $key => $error ) {
440
			$key = str_replace( array( __NAMESPACE__ . '\\', '_File_Backup_Engine', '_Database_Backup_Engine' ), array( '', '', '' ), $key );
441
			$notices[] = $key . ': ' . implode( ', ', $error );
442
		}
443
		Notices::get_instance()->set_notices( 'backup_errors', $notices );
444
445
		$this->status->set_status( __( 'Deleting old backups...', 'backupwordpress' ) );
446
447
		// Delete old backups again
448
		$this->delete_old_backups();
449
450
		$this->do_action( 'hmbkp_backup_complete', $backup );
451
452
		$this->status->finish();
453
		$this->update_average_schedule_run_time( $this->status->get_start_time(), time() );
454
455
	}
456
457
	public function get_backup_filename() {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
458
459
		if ( $this->status->is_started() ) {
460
			$this->backup_filename = $this->status->get_backup_filename();
461
		}
462
463
		return $this->backup_filename;
464
	}
465
466
	public function get_database_dump_filename() {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
467
		return $this->database_dump_filename;
468
	}
469
470
	/**
471
	 * Hook into the actions fired in the Backup class and set the status
472
	 *
473
	 * @param $action
474
	 */
475
	public function do_action( $action, Backup $backup ) {
476
477
		// Pass the actions to all the services
478
		// Todo should be decoupled into the service class
479
		foreach ( Services::get_services( $this ) as $service ) {
480
			if ( is_wp_error( $service ) ) {
481
				return $service;
482
			}
483
			$service->action( $action, $backup );
484
		}
485
486
	}
487
488
	/**
489
	 * Calculate schedule run time.
490
	 *
491
	 * @param int Timestamp $end
492
	 */
493
	public function update_average_schedule_run_time( $start, $end ) {
494
495
		if ( $end <= $start ) {
496
			// Something went wrong, ignore.
497
			return;
498
		}
499
500
		$diff = (int) abs( $end - $start );
501
502
		if ( isset( $this->options['duration_total'] ) && isset( $this->options['backup_run_count'] ) ) {
503
504
			$this->options['duration_total'] += $diff;
505
			$this->options['backup_run_count'] ++;
506
507
		} else {
508
509
			$this->options['duration_total'] = $diff;
510
			$this->options['backup_run_count'] = 1;
511
512
		}
513
514
		$this->save();
515
	}
516
517
	/**
518
	 * Calculates the average run time for this schedule.
519
	 *
520
	 * @return string
521
	 */
522
	public function get_schedule_average_duration() {
523
524
		$duration = 'Unknown';
525
526
		if ( ! isset( $this->options['duration_total'] ) || ! isset( $this->options['backup_run_count'] ) ) {
527
			return $duration;
528
		}
529
530
		if ( 0 === (int) $this->options['backup_run_count'] ) {
531
			return $duration;
532
		}
533
534
		$average_run_time = (int) $this->options['duration_total'] / (int) $this->options['backup_run_count'];
535
536
		if ( $average_run_time < HOUR_IN_SECONDS ) {
537
538
			$mins = round( $average_run_time / MINUTE_IN_SECONDS );
539
540
			if ( $mins <= 1 ) {
541
				$mins = 1;
542
			}
543
544
			/* translators: min=minute */
545
			$duration = sprintf( _n( '%s min', '%s mins', $mins, 'backupwordpress' ), $mins );
546
547
		} elseif ( $average_run_time < DAY_IN_SECONDS && $average_run_time >= HOUR_IN_SECONDS ) {
548
549
			$hours = round( $average_run_time / HOUR_IN_SECONDS );
550
551
			if ( $hours <= 1 ) {
552
				$hours = 1;
553
			}
554
555
			$duration = sprintf( _n( '%s hour', '%s hours', $hours, 'backupwordpress' ), $hours );
556
		}
557
558
		return $duration;
559
	}
560
561
	/**
562
	 * Get the backups created by this schedule
563
	 *
564
	 * @todo   look into using recursiveDirectoryIterator and recursiveRegexIterator
565
	 * @return string[] - file paths of the backups
566
	 */
567
	public function get_backups() {
568
569
		$files = array();
570
571
		if ( $handle = @opendir( Path::get_path() ) ) {
572
573
			while ( false !== ( $file = readdir( $handle ) ) ) {
574
575
				if ( pathinfo( $file, PATHINFO_EXTENSION ) === 'zip' && strpos( $file, $this->get_id() ) !== false && ( isset( $this->status ) && $this->get_backup_filename() !== $file ) ) {
576
					$files[ @filemtime( trailingslashit( Path::get_path() ) . $file ) ] = trailingslashit( Path::get_path() ) . $file;
577
				}
578
579
			}
580
581
			closedir( $handle );
582
583
		}
584
585
		krsort( $files );
586
587
		return $files;
588
589
	}
590
591
	/**
592
	 * Delete old backups
593
	 *
594
	 * @access private
595
	 */
596
	public function delete_old_backups() {
597
598
		if ( count( $this->get_backups() ) <= $this->get_max_backups() ) {
599
			return;
600
		}
601
602
		array_map( array( $this, 'delete_backup' ), array_slice( $this->get_backups(), $this->get_max_backups() ) );
603
604
	}
605
606
	/**
607
	 * Delete a specific back up file created by this schedule
608
	 *
609
	 * @param string $filepath
610
	 *
611
	 * @return \WP_Error|boolean
612
	 */
613
	public function delete_backup( $filepath ) {
614
615
		// Check that it's a valid filepath
616
		if ( empty( $filepath ) || ! is_string( $filepath ) ) {
617
			return new \WP_Error( 'hmbkp_empty_string_error', sprintf( __( 'Argument 1 for %s must be a non-empty string', 'backupwordpress' ), __METHOD__ ) );
618
		}
619
620
		// Make sure it exists
621
		if ( ! file_exists( $filepath ) ) {
622
			return new \WP_Error( 'hmbkp_file_error', sprintf( __( '%s doesn\'t exist', 'backupwordpress' ), $filepath ) );
623
		}
624
625
		// Make sure it was created by this schedule
626
		if ( strpos( $filepath, $this->get_id() ) === false ) {
627
			return new \WP_Error( 'hmbkp_backup_error', __( 'That backup wasn\'t created by this schedule', 'backupwordpress' ) );
628
		}
629
630
		unlink( $filepath );
631
632
		return true;
633
634
	}
635
636
	/**
637
	 * Delete all back up files created by this schedule
638
	 *
639
	 */
640
	public function delete_backups() {
641
		array_map( array( $this, 'delete_backup' ), $this->get_backups() );
642
	}
643
644
	/**
645
	 * Save the schedules options.
646
	 *
647
	 */
648
	public function save() {
649
650
		// Only save them if they have changed
651
		if ( $this->options !== get_option( 'hmbkp_schedule_' . $this->get_id() ) ) {
652
			update_option( 'hmbkp_schedule_' . $this->get_id(), $this->options );
653
		}
654
655
	}
656
657
	/**
658
	 * Cancel this schedule
659
	 *
660
	 * Cancels the cron job, removes the schedules options
661
	 * and optionally deletes all backups created by
662
	 * this schedule.
663
	 *
664
	 */
665
	public function cancel( $delete_backups = false ) {
666
667
		// Delete the schedule options
668
		delete_option( 'hmbkp_schedule_' . $this->get_id() );
669
670
		// Clear any existing schedules
671
		$this->unschedule();
672
673
		// Delete it's backups
674
		if ( $delete_backups ) {
675
			$this->delete_backups();
676
		}
677
678
	}
679
680
}
681