Completed
Push — fix/refactor-full-sync-status-... ( d41df7 )
by
unknown
55:42 queued 45:27
created

Jetpack_Sync_Module_Full_Sync::get_status()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 2
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
/**
4
 * This class does a full resync of the database by
5
 * enqueuing an outbound action for every single object
6
 * that we care about.
7
 *
8
 * This class contains a few non-obvious optimisations that should be explained:
9
 * - we fire an action called jetpack_full_sync_start so that WPCOM can erase the contents of the cached database
10
 * - for each object type, we obtain a full list of object IDs to sync via a single API call (hoping that since they're ints, they can all fit in RAM)
11
 * - we load the full objects for those IDs in chunks of Jetpack_Sync_Full::ARRAY_CHUNK_SIZE (to reduce the number of MySQL calls)
12
 * - we fire a trigger for the entire array which the Jetpack_Sync_Sender then serializes and queues.
13
 */
14
15
require_once 'class.jetpack-sync-wp-replicastore.php';
16
17
class Jetpack_Sync_Module_Full_Sync extends Jetpack_Sync_Module {
18
	static $status_option = 'jetpack_full_sync_status';
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $status_option.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
19
	static $transient_timeout = 3600; // an hour
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $transient_timeout.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
20
	static $modules = array(
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $modules.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
21
		'wp_version',
22
		'constants',
23
		'functions',
24
		'options',
25
		'posts',
26
		'comments',
27
		'themes',
28
		'updates',
29
		'users',
30
		'terms',
31
		'network_options',
32
	);
33
34
	private $sender;
35
36
	public function name() {
37
		return 'full-sync';
38
	}
39
40
	function init_listeners( $callable ) {
41
		// synthetic actions for full sync
42
		add_action( 'jetpack_full_sync_start', $callable );
43
		add_action( 'jetpack_full_sync_end', $callable );
44
	}
45
46
	function init_before_send() {
47
		// this is triggered after actions have been processed on the server
48
		add_action( 'jetpack_sync_processed_actions', array( $this, 'update_sent_progress_action' ) );
49
	}
50
51
	function start() {
52
		if( ! $this->should_start_full_sync() ) {
53
			return false;
54
		}
55
		/**
56
		 * Fires when a full sync begins. This action is serialized
57
		 * and sent to the server so that it can clear the replica storage,
58
		 * and/or reset other data.
59
		 *
60
		 * @since 4.2.0
61
		 */
62
		do_action( 'jetpack_full_sync_start' );
63
		$this->set_status_queuing_started();
64
65
		foreach( Jetpack_Sync_Modules::get_modules() as $module ) {
66
			$module->full_sync();
67
		}
68
		if ( is_multisite() ) {
69
			$this->enqueue_all_network_options();
70
		}
71
72
		$this->set_status_queuing_finished();
73
74
		$store = new Jetpack_Sync_WP_Replicastore();
75
		do_action( 'jetpack_full_sync_end', $store->checksum_all() );
76
		return true;
77
	}
78
79
	private function should_start_full_sync() {
80
		$status = $this->get_status();
81
		// We should try sync if we haven't started it yet or if we have finished it.
82
		if( is_null( $status['started'] ) || is_integer( $status['finished'] ) ) {
83
			return true;
84
		}
85
		return false;
86
	}
87
88
	private function get_sender() {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
89
		if ( ! $this->sender ) {
90
			$this->sender = Jetpack_Sync_Sender::getInstance();
91
		}
92
93
		return $this->sender;
94
	}
95
96
	private function enqueue_all_network_options() {
97
		$total = Jetpack_Sync_Modules::get_module( "options" )->full_sync_network();
98
		$this->update_queue_progress( 'network_options', $total );
99
	}
100
101
	function update_sent_progress_action( $actions_sent ) {
102
		$modules_count = array();
103
		$status = $this->get_status();
104
		if ( is_null( $status['started'] ) || $status['finished'] ) {
105
			return;
106
		}
107
108
		if ( in_array( 'jetpack_full_sync_start', $actions_sent ) ) {
109
			$this->set_status_sending_started();
110
			$status['sent_started'] = time();
111
		}
112
113
		foreach( $actions_sent as $action ) {
114
			$module_key = $this->action_to_modules( $action );
115
			if ( $module_key ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $module_key of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
116
				$modules_count[ $module_key ] = isset( $modules_count[ $module_key ] ) ?  $modules_count[ $module_key ] + 1 : 1;
117
			}
118
		}
119
120
		foreach( $modules_count as $module => $count ) {
121
			$status[ 'sent' ][ $module ] = $this->update_sent_progress( $module, $count );
122
		}
123
124
		if ( in_array( 'jetpack_full_sync_end', $actions_sent ) ) {
125
			$this->set_status_sending_finished();
126
			$status['finished'] = time();
127
		}
128
129
		$this->update_status( $status );
130
	}
131
132
	function action_to_modules( $action ) {
133
		switch( $action ) {
134
			case 'jetpack_full_sync_constants':
135
				return 'constants';
136
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
137
138
			case 'jetpack_full_sync_callables':
139
				return 'functions';
140
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
141
142
			case 'jetpack_full_sync_options':
143
				return 'options';
144
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
145
146
			case 'jetpack_full_sync_network_options':
147
				return 'network_options';
148
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
149
150
			case 'jetpack_full_sync_terms':
151
				return 'terms';
152
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
153
154
			case 'jetpack_sync_current_theme_support':
155
				return 'themes';
156
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
157
158
			case 'jetpack_full_sync_users':
159
				return 'users';
160
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
161
162
			case 'jetpack_full_sync_posts':
163
				return 'posts';
164
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
165
166
			case 'jetpack_full_sync_comments':
167
				return 'comments';
168
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
169
170
			case 'jetpack_full_sync_updates':
171
				return 'updates';
172
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
173
174
		}
175
		return null;
176
	}
177
178
	private function set_status_queuing_started() {
179
		$status = $this->initial_status;
180
		$status[ 'started' ] = time();
181
		$this->update_status( $status );
182
	}
183
184
	private function set_status_queuing_finished() {
185
		$this->update_status( array( 'queue_finished' => time() ) );
186
	}
187
188
	// these are called by the Sync Client when it sees that the full sync start/end actions have actually been transmitted
189
	public function set_status_sending_started() {
190
		/**
191
		 * Fires when the full_sync_start action is actually transmitted.
192
		 * This is useful for telling the user the status of full synchronization.
193
		 *
194
		 * @since 4.2.0
195
		 */
196
197
		do_action( 'jetpack_full_sync_start_sent' );
198
199
	}
200
201
	public function set_status_sending_finished() {
202
		/**
203
		 * Fires when the full_sync_end action is actually transmitted.
204
		 * This is useful for telling the user the status of full synchronization.
205
		 *
206
		 * @since 4.2.0
207
		 */
208
		do_action( 'jetpack_full_sync_end_sent' );
209
	}
210
211
	private $initial_status = array(
212
		'started' => null,
213
		'queue_finished' => null,
214
		'sent_started' => null,
215
		'finished' => null,
216
		'sent' => array(),
217
		'queue' => array(),
218
	);
219
220
	public function get_status() {
221
		return get_option( self::$status_option, $this->initial_status );
222
	}
223
224
225
	public function update_status( $status ) {
226
		return update_option(
227
			self::$status_option,
228
			array_merge( $this->get_status(), $status )
229
		);
230
	}
231
232
	private function clear_status() {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
233
		delete_option( self::$status_option );
234
	}
235
236
	public function update_sent_progress( $module, $data ) {
237
		$status = $this->get_status();
238
		if ( isset( $status['sent'][ $module ] ) )  {
239
			return $data + $status['sent'][ $module ];
240
		} else {
241
			return $data;
242
		}
243
	}
244
245
}
246