Completed
Push — master-stable ( 2e27ce...519850 )
by Jeremy
12:36
created

Jetpack_Sync_Module_Full_Sync::start()   F

Complexity

Conditions 14
Paths 448

Size

Total Lines 87
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 14
eloc 35
c 4
b 0
f 0
nc 448
nop 1
dl 0
loc 87
rs 3.4881

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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, and its related class Jetpack_Sync_Module, contain 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 page through the object IDs and enqueue them by firing some monitored actions
11
 * - we load the full objects for those IDs in chunks of Jetpack_Sync_Module::ARRAY_CHUNK_SIZE (to reduce the number of MySQL calls)
12
 * - we fire a trigger for the entire array which the Jetpack_Sync_Listener 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
	const STATUS_OPTION_PREFIX = 'jetpack_sync_full_';
19
	const FULL_SYNC_TIMEOUT = 3600;
20
21
	public function name() {
22
		return 'full-sync';
23
	}
24
25
	function init_full_sync_listeners( $callable ) {
26
		// synthetic actions for full sync
27
		add_action( 'jetpack_full_sync_start', $callable );
28
		add_action( 'jetpack_full_sync_end', $callable );
29
		add_action( 'jetpack_full_sync_cancelled', $callable );
30
	}
31
32
	function init_before_send() {
33
		// this is triggered after actions have been processed on the server
34
		add_action( 'jetpack_sync_processed_actions', array( $this, 'update_sent_progress_action' ) );
35
	}
36
37
	function start( $modules = null ) {
38
		$was_already_running = $this->is_started() && ! $this->is_finished();
39
40
		// remove all evidence of previous full sync items and status
41
		$this->reset_data();
42
43
		if ( $was_already_running ) {
44
			/**
45
			 * Fires when a full sync is cancelled.
46
			 *
47
			 * @since 4.2.0
48
			 */
49
			do_action( 'jetpack_full_sync_cancelled' );
50
		}
51
52
		/**
53
		 * Fires when a full sync begins. This action is serialized
54
		 * and sent to the server so that it knows a full sync is coming.
55
		 *
56
		 * @since 4.2.0
57
		 */
58
		do_action( 'jetpack_full_sync_start' );
59
		$this->update_status_option( 'started', time() );
60
61
		// configure modules
62
		if ( ! is_array( $modules ) ) {
63
			$modules = array();
64
		}
65
66
		// by default, all modules are fully enabled
67
		if ( count( $modules ) === 0 ) {
68
			$default_module_config = true;
69
		} else {
70
			$default_module_config = false;
71
		}
72
73
		// set default configuration, calculate totals, and save configuration if totals > 0
74
		foreach ( Jetpack_Sync_Modules::get_modules() as $module ) {
75
			$module_name = $module->name();
76
			if ( ! isset( $modules[ $module_name ] ) ) {
77
				$modules[ $module_name ] = $default_module_config;
78
			}
79
80
			// check if this module is enabled
81
			if ( ! ( $module_config = $modules[ $module_name ] ) ) {
82
				continue;
83
			}
84
85
			$total_items = $module->estimate_full_sync_actions( $module_config );
86
87
			if ( ! is_null( $total_items ) && $total_items > 0 ) {
88
				$this->update_status_option( "{$module_name}_total", $total_items );
89
				$this->update_status_option( "{$module_name}_config", $module_config );
90
			}
91
		}
92
93
		foreach ( Jetpack_Sync_Modules::get_modules() as $module ) {
94
			$module_name   = $module->name();
95
			$module_config = $modules[ $module_name ];
96
97
			// check if this module is enabled
98
			if ( ! $module_config ) {
99
				continue;
100
			}
101
102
			$items_enqueued = $module->enqueue_full_sync_actions( $module_config );
103
104
			if ( ! is_null( $items_enqueued ) && $items_enqueued > 0 ) {
105
				$this->update_status_option( "{$module_name}_queued", $items_enqueued );
106
			}
107
		}
108
109
		$this->update_status_option( 'queue_finished', time() );
110
111
		$store = new Jetpack_Sync_WP_Replicastore();
112
113
		/**
114
		 * Fires when a full sync ends. This action is serialized
115
		 * and sent to the server with checksums so that we can confirm the
116
		 * sync was successful.
117
		 *
118
		 * @since 4.2.0
119
		 */
120
		do_action( 'jetpack_full_sync_end', $store->checksum_all() );
121
122
		return true;
123
	}
124
125
	function update_sent_progress_action( $actions ) {
126
127
		// quick way to map to first items with an array of arrays
128
		$actions_with_counts = array_count_values( array_map( 'reset', $actions ) );
129
130
		if ( ! $this->is_started() || $this->is_finished() ) {
131
			return;
132
		}
133
134
		if ( isset( $actions_with_counts['jetpack_full_sync_start'] ) ) {
135
			$this->update_status_option( 'sent_started', time() );
136
		}
137
138
		foreach ( Jetpack_Sync_Modules::get_modules() as $module ) {
139
			$module_actions     = $module->get_full_sync_actions();
140
			$status_option_name = "{$module->name()}_sent";
141
			$items_sent         = $this->get_status_option( $status_option_name, 0 );
142
143
			foreach ( $module_actions as $module_action ) {
144
				if ( isset( $actions_with_counts[ $module_action ] ) ) {
145
					$items_sent += $actions_with_counts[ $module_action ];
146
				}
147
			}
148
149
			if ( $items_sent > 0 ) {
150
				$this->update_status_option( $status_option_name, $items_sent );
151
			}	
152
		}
153
154
		if ( isset( $actions_with_counts['jetpack_full_sync_end'] ) ) {
155
			$this->update_status_option( 'finished', time() );
156
		}
157
	}
158
159
	public function is_started() {
160
		return !! $this->get_status_option( 'started' );
161
	}
162
163
	public function is_finished() {
164
		return !! $this->get_status_option( 'finished' );
165
	}
166
167
	public function get_status() {
168
		$status = array(
169
			'started'        => $this->get_status_option( 'started' ),
170
			'queue_finished' => $this->get_status_option( 'queue_finished' ),
171
			'sent_started'   => $this->get_status_option( 'sent_started' ),
172
			'finished'       => $this->get_status_option( 'finished' ),
173
			'sent'           => array(),
174
			'queue'          => array(),
175
			'config'         => array(),
176
			'total'          => array(),
177
		);
178
179
		foreach ( Jetpack_Sync_Modules::get_modules() as $module ) {
180
			$name = $module->name();
181
182
			if ( $total = $this->get_status_option( "{$name}_total" ) ) {
183
				$status[ 'total' ][ $name ] = $total;
184
			}
185
186
			if ( $queued = $this->get_status_option( "{$name}_queued" ) ) {
187
				$status[ 'queue' ][ $name ] = $queued;
188
			}
189
			
190
			if ( $sent = $this->get_status_option( "{$name}_sent" ) ) {
191
				$status[ 'sent' ][ $name ] = $sent;
192
			}
193
194
			if ( $config = $this->get_status_option( "{$name}_config" ) ) {
195
				$status[ 'config' ][ $name ] = $config;
196
			}
197
		}
198
199
		return $status;
200
	}
201
202
	public function clear_status() {
203
		$prefix = self::STATUS_OPTION_PREFIX;
204
		delete_option( "{$prefix}_started" );
205
		delete_option( "{$prefix}_queue_finished" );
206
		delete_option( "{$prefix}_sent_started" );
207
		delete_option( "{$prefix}_finished" );
208
209
		foreach ( Jetpack_Sync_Modules::get_modules() as $module ) {
210
			delete_option( "{$prefix}_{$module->name()}_total" );
211
			delete_option( "{$prefix}_{$module->name()}_queued" );
212
			delete_option( "{$prefix}_{$module->name()}_sent" );
213
			delete_option( "{$prefix}_{$module->name()}_config" );
214
		}
215
	}
216
217
	public function reset_data() {
218
		$this->clear_status();
219
		require_once dirname( __FILE__ ) . '/class.jetpack-sync-listener.php';
220
		$listener = Jetpack_Sync_Listener::get_instance();
221
		$listener->get_full_sync_queue()->reset();
222
	}
223
224
	private function get_status_option( $option, $default = null ) {
225
		$prefix = self::STATUS_OPTION_PREFIX;
226
227
		$value = get_option( "{$prefix}_{$option}", $default );
228
		
229
		if ( ! $value ) {
230
			// don't cast to int if we didn't find a value - we want to preserve null or false as sentinals
231
			return $default;
232
		}
233
234
		return is_numeric( $value ) ? intval( $value ) : $value;
235
	}
236
237
	private function update_status_option( $name, $value ) {
238
		$prefix = self::STATUS_OPTION_PREFIX;
239
		update_option( "{$prefix}_{$name}", $value, false );
240
	}
241
}
242