Completed
Push — fix/refactor-full-sync-status-... ( baeb97...466398 )
by
unknown
63:36 queued 54:01
created

Jetpack_Sync_Module_Full_Sync   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 4

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 0
loc 174
rs 9.8
wmc 31
lcom 2
cbo 4

16 Methods

Rating   Name   Duplication   Size   Complexity  
A name() 0 3 1
A init_listeners() 0 5 1
A init_before_send() 0 4 1
B start() 0 27 4
A should_start_full_sync() 0 8 3
A get_sender() 0 7 2
A enqueue_all_network_options() 0 4 1
D update_sent_progress_action() 0 34 9
A set_status_queuing_started() 0 5 1
A set_status_queuing_finished() 0 3 1
A set_status_sending_started() 0 11 1
A set_status_sending_finished() 0 9 1
A get_status() 0 3 1
A update_status() 0 6 1
A clear_status() 0 3 1
A update_sent_progress() 0 8 2
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
21
	private $sender;
22
23
	public function name() {
24
		return 'full-sync';
25
	}
26
27
	function init_listeners( $callable ) {
28
		// synthetic actions for full sync
29
		add_action( 'jetpack_full_sync_start', $callable );
30
		add_action( 'jetpack_full_sync_end', $callable );
31
	}
32
33
	function init_before_send() {
34
		// this is triggered after actions have been processed on the server
35
		add_action( 'jetpack_sync_processed_actions', array( $this, 'update_sent_progress_action' ) );
36
	}
37
38
	function start() {
39
		if( ! $this->should_start_full_sync() ) {
40
			return false;
41
		}
42
		/**
43
		 * Fires when a full sync begins. This action is serialized
44
		 * and sent to the server so that it can clear the replica storage,
45
		 * and/or reset other data.
46
		 *
47
		 * @since 4.2.0
48
		 */
49
		do_action( 'jetpack_full_sync_start' );
50
		$this->set_status_queuing_started();
51
52
		foreach( Jetpack_Sync_Modules::get_modules() as $module ) {
53
			$module->full_sync();
54
		}
55
		if ( is_multisite() ) {
56
			$this->enqueue_all_network_options();
57
		}
58
59
		$this->set_status_queuing_finished();
60
61
		$store = new Jetpack_Sync_WP_Replicastore();
62
		do_action( 'jetpack_full_sync_end', $store->checksum_all() );
63
		return true;
64
	}
65
66
	private function should_start_full_sync() {
67
		$status = $this->get_status();
68
		// We should try sync if we haven't started it yet or if we have finished it.
69
		if( is_null( $status['started'] ) || is_integer( $status['finished'] ) ) {
70
			return true;
71
		}
72
		return false;
73
	}
74
75
	private function get_sender() {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
76
		if ( ! $this->sender ) {
77
			$this->sender = Jetpack_Sync_Sender::getInstance();
78
		}
79
80
		return $this->sender;
81
	}
82
83
	private function enqueue_all_network_options() {
84
		$total = Jetpack_Sync_Modules::get_module( "options" )->full_sync_network();
85
		$this->update_queue_progress( 'network_options', $total );
86
	}
87
88
	function update_sent_progress_action( $actions ) {
89
		// quick way to map to first items with an array of arrays
90
		$actions_with_counts = array_count_values( array_map( 'reset', $actions ) );
91
92
		$status = $this->get_status();
93
		if ( is_null( $status['started'] ) || $status['finished'] ) {
94
			return;
95
		}
96
97
		if ( isset( $actions_with_counts[ 'jetpack_full_sync_start' ] ) ) {
98
			$this->set_status_sending_started();
99
			$status['sent_started'] = time();
100
		}
101
102
		foreach( Jetpack_Sync_Modules::get_modules() as $module ) {
103
			$module_name = $module->name();
104
			$module_actions = $module->get_full_sync_actions();
105
			foreach( $module_actions as $module_action ) {
106
				if ( isset( $actions_with_counts[ $module_action ] ) ) {
107
					if ( ! isset( $status[ 'sent' ][ $module_name ] ) ) {
108
						$status['sent'][ $module_name ] = 0;	
109
					}
110
					$status['sent'][ $module_name ] += $actions_with_counts[ $module_action ];	
111
				}
112
			}
113
		}
114
115
		if ( isset( $actions_with_counts[ 'jetpack_full_sync_end' ] ) ) {
116
			$this->set_status_sending_finished();
117
			$status['finished'] = time();
118
		}
119
120
		$this->update_status( $status );
121
	}
122
123
	private function set_status_queuing_started() {
124
		$status = $this->initial_status;
125
		$status[ 'started' ] = time();
126
		$this->update_status( $status );
127
	}
128
129
	private function set_status_queuing_finished() {
130
		$this->update_status( array( 'queue_finished' => time() ) );
131
	}
132
133
	// these are called by the Sync Client when it sees that the full sync start/end actions have actually been transmitted
134
	public function set_status_sending_started() {
135
		/**
136
		 * Fires when the full_sync_start action is actually transmitted.
137
		 * This is useful for telling the user the status of full synchronization.
138
		 *
139
		 * @since 4.2.0
140
		 */
141
142
		do_action( 'jetpack_full_sync_start_sent' );
143
144
	}
145
146
	public function set_status_sending_finished() {
147
		/**
148
		 * Fires when the full_sync_end action is actually transmitted.
149
		 * This is useful for telling the user the status of full synchronization.
150
		 *
151
		 * @since 4.2.0
152
		 */
153
		do_action( 'jetpack_full_sync_end_sent' );
154
	}
155
156
	private $initial_status = array(
157
		'started' => null,
158
		'queue_finished' => null,
159
		'sent_started' => null,
160
		'finished' => null,
161
		'sent' => array(),
162
		'queue' => array(),
163
	);
164
165
	public function get_status() {
166
		return get_option( self::$status_option, $this->initial_status );
167
	}
168
169
170
	public function update_status( $status ) {
171
		return update_option(
172
			self::$status_option,
173
			array_merge( $this->get_status(), $status )
174
		);
175
	}
176
177
	private function clear_status() {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
178
		delete_option( self::$status_option );
179
	}
180
181
	public function update_sent_progress( $module, $data ) {
182
		$status = $this->get_status();
183
		if ( isset( $status['sent'][ $module ] ) )  {
184
			return $data + $status['sent'][ $module ];
185
		} else {
186
			return $data;
187
		}
188
	}
189
190
}
191