Completed
Push — add/sync-rest-2 ( d8d9e1...b5bd8a )
by
unknown
64:16 queued 55:22
created

Jetpack_Sync_Full::enqueue_all_constants()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 5
rs 9.4285
cc 1
eloc 4
nc 1
nop 0
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_Client then serializes and queues.
13
 */
14
15
class Jetpack_Sync_Full {
16
	static $array_chunk_size = 5;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $array_chunk_size.

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...
17
	static $status_transient_name = "jp_full_sync_progress";
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $status_transient_name.

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...
18
	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...
19
20
	// singleton functions
21
	private static $instance;
22
23
	public static function getInstance() {
24
		if ( null === self::$instance ) {
25
			self::$instance = new self();
26
		}
27
28
		return self::$instance;
29
	}
30
31
	protected function __construct() {
32
		$this->init();
33
	}
34
35
	function init() {
36
		add_filter( "jetack_sync_before_send_jetpack_full_sync_posts", array( $this, 'expand_post_ids' ) );
37
		add_filter( "jetack_sync_before_send_jetpack_full_sync_comments", array( $this, 'expand_comment_ids' ) );
38
	}
39
40
	function start() {
41
		$this->client = Jetpack_Sync_Client::getInstance();
0 ignored issues
show
Bug introduced by
The property client 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...
42
		do_action( 'jetpack_full_sync_start' );
43
44
		$this->set_status_queuing_started();
45
46
		$this->enqueue_wp_version();
47
		$this->enqueue_all_constants();
48
		$this->enqueue_all_functions();
49
		$this->enqueue_all_options();
50
		$this->enqueue_all_theme_info();
51
		$this->enqueue_all_posts();
52
		$this->enqueue_all_comments();
53
		$this->enqueue_all_updates();
54
55
		$this->set_status_queuing_finished();
56
57
		do_action( 'jp_full_sync_end' );
58
	}
59
60
	private function enqueue_wp_version() {
61
		$this->set_status("wp_version", 0);
62
		global $wp_version;
63
		do_action( 'jetpack_sync_wp_version', $wp_version );
64
		$this->set_status("wp_version", 100);
65
	}
66
67
	private function enqueue_all_constants() {
68
		$this->set_status("constants", 0);
69
		$this->client->force_sync_constants();
70
		$this->set_status("constants", 100);
71
	}
72
73
	private function enqueue_all_functions() {
74
		$this->set_status("functions", 0);
75
		$this->client->force_sync_callables();
76
		$this->set_status("functions", 100);
77
	}
78
79
	private function enqueue_all_options() {
80
		$this->set_status("options", 0);
81
		global $wpdb;
82
83
		// Unfortunately, since our options whitelist includes regexes,
84
		// we need to load all option names and match them against the whitelist.
85
		// This could be pretty awful if we have huge queues, but it's the only way to 
86
		// be sure we're syncing everything that's whitelisted.
87
88
		// As per posts and comments, we do this in ID batches and hope the IDs *AND* names don't exceed RAM
89
90
		// In theory, MySQL has regex support. In practice, I wouldn't want to rely on it being compatible
91
		// with PHP's regexes.
92
93
		// Alternatively, rather than option regexes, we could use wildcards in the option and then just
94
		// use "LIKE" queries here, replacing * with %?
95
96
		$option_names = $wpdb->get_col( "SELECT option_name FROM $wpdb->options" );
97
98
		// filter by client option whitelist
99
		$option_names = array_filter( $option_names, array( $this->client, 'is_whitelisted_option' ) );
100
101
		$counter = 0;
102
		$total = count( $option_names );
103
104
		foreach ( $option_names as $option_name ) {
105
			$this->set_status( "options", ( $counter / $total ) * 100 );
106
			do_action( 'jetpack_full_sync_option', $option_name, get_option( $option_name ) );
107
			$counter += 1;
108
		}
109
110
		$this->set_status("options", 100);
111
	}
112
113 View Code Duplication
	private function enqueue_all_posts() {
114
		$this->set_status("posts", 0);
115
		global $wpdb;
116
117
		// I hope this is never bigger than RAM...
118
		$post_ids = $wpdb->get_col( "SELECT id FROM $wpdb->posts");
119
120
		// Request posts in groups of N for efficiency
121
		$chunked_post_ids = array_chunk( $post_ids, self::$array_chunk_size );
122
123
		$counter = 0;
124
		$total = count( $chunked_post_ids );
125
126
		// Send each chunk as an array of objects
127
		foreach ( $chunked_post_ids as $chunk ) {
128
			$this->set_status( "posts", ( $counter / $total ) * 100 );
129
			do_action( 'jetpack_full_sync_posts', $chunk );
130
			$counter += 1;
131
		}
132
133
		$this->set_status("posts", 100);
134
	}
135
136
	public function expand_post_ids( $args ) {
137
		$post_ids = $args[0];
138
		global $wpdb;
139
140
		$posts = get_posts( array(
141
	 		'include'          => $post_ids,
142
	 		'post_type'        => 'any',
143
	 		'post_status'      => 'any',
144
	 		'suppress_filters' => true ) );
145
146
		$postmetas = $wpdb->get_results( 
147
			"SELECT * FROM $wpdb->postmeta WHERE post_id IN ( " . implode( ',', wp_parse_id_list( $post_ids ) ) . " )", OBJECT 
148
		);
149
150
		return array(
151
			'posts' => $posts,
152
			'postmetas' => $postmetas
153
		);
154
	}
155
156 View Code Duplication
	private function enqueue_all_comments() {
157
		$this->set_status("comments", 0);
158
159
		global $wpdb;
160
161
		$comment_ids = $wpdb->get_col( "SELECT comment_id FROM $wpdb->comments");
162
		$chunked_comment_ids = array_chunk( $comment_ids, self::$array_chunk_size );
163
164
		$counter = 0;
165
		$total = count( $chunked_comment_ids );
166
167
		foreach ( $chunked_comment_ids as $chunk ) {
168
			$this->set_status( "comments", ( $counter / $total ) * 100 );
169
			do_action( 'jetpack_full_sync_comments', $chunk);
170
			$counter += 1;
171
		}
172
173
		$this->set_status("comments", 100);
174
	}
175
176
	public function expand_comment_ids( $args ) {
177
		$comment_ids = $args[0];
178
		return get_comments( array(
179
	 		'include_unapproved' => true,
180
	 		'comment__in' => $comment_ids,
181
 		) );
182
	}
183
184
	// TODO:
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
185
	private function enqueue_all_theme_info() {
186
		$this->set_status("themes", 0);
187
		$this->client->send_theme_info();
188
		$this->set_status("themes", 100);
189
	}
190
191
	private function enqueue_all_updates() {
192
		$this->set_status("updates", 0);
193
		// check for updates
194
		wp_update_plugins();
195
		wp_update_themes();
196
		_maybe_update_core();
197
		$this->set_status("updates", 100);
198
	}
199
	
200
	private function set_status( $name, $percent, $count = 1, $total =1 ) {
201
		set_transient( self::$status_transient_name.'_'.$name, array( 
202
			'phase' => 'preparing', 
203
			'name' => $name, 
204
			'progress' => $percent, 
205
			'count' => $count, 
206
			'total' => $total ),
207
			self::$transient_timeout
208
		);
209
	}
210
211
	private function set_status_queuing_started() {
212
		set_transient( self::$status_transient_name, array( 'phase' => 'queuing started' ), self::$transient_timeout );
213
	}
214
215
	private function set_status_queuing_finished() {
216
		set_transient( self::$status_transient_name, array( 'phase' => 'queuing finished' ), self::$transient_timeout );
217
	}
218
219
	// these are called by the Sync Client when it sees that the full sync start/end actions have actually been transmitted
220
	public function set_status_sending_started() {
221
		set_transient( self::$status_transient_name, array( 'phase' => 'sending started' ), self::$transient_timeout );
222
	}
223
224
	public function set_status_sending_finished() {
225
		set_transient( self::$status_transient_name, array( 'phase' => 'sending finished' ), self::$transient_timeout );
226
	}
227
228
	public function get_status() {
229
		return get_transient( self::$status_transient_name );
230
	}
231
}