Completed
Push — instant-search-master ( 8be3b4...336413 )
by
unknown
06:37 queued 10s
created

queue_pull()   B

Complexity

Conditions 7
Paths 13

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
nc 13
nop 3
dl 0
loc 42
rs 8.3146
c 0
b 0
f 0
1
<?php
2
3
use Automattic\Jetpack\Sync\Actions;
4
use Automattic\Jetpack\Sync\Modules;
5
use Automattic\Jetpack\Sync\Queue;
6
use Automattic\Jetpack\Sync\Queue_Buffer;
7
use Automattic\Jetpack\Sync\Replicastore;
8
use Automattic\Jetpack\Sync\Sender;
9
use Automattic\Jetpack\Sync\Settings;
10
11
// POST /sites/%s/sync
12
class Jetpack_JSON_API_Sync_Endpoint extends Jetpack_JSON_API_Endpoint {
13
	protected $needed_capabilities = 'manage_options';
14
15
	protected function validate_call( $_blog_id, $capability, $check_manage_active = true ) {
16
		return parent::validate_call( $_blog_id, $capability, false );
17
	}
18
19
	protected function result() {
20
		$args = $this->input();
21
		$modules = null;
22
23
		// convert list of modules in comma-delimited format into an array
24
		// of "$modulename => true"
25 View Code Duplication
		if ( isset( $args['modules'] ) && ! empty( $args['modules'] ) ) {
26
			$modules = array_map( '__return_true', array_flip( array_map( 'trim', explode( ',', $args['modules'] ) ) ) );
27
		}
28
29 View Code Duplication
		foreach ( array( 'posts', 'comments', 'users' ) as $module_name ) {
30
			if ( 'users' === $module_name && isset( $args[ $module_name ] ) && 'initial' === $args[ $module_name ] ) {
31
				$modules[ 'users' ] = 'initial';
32
			} elseif ( isset( $args[ $module_name ] ) ) {
33
				$ids = explode( ',', $args[ $module_name ] );
34
				if ( count( $ids ) > 0 ) {
35
					$modules[ $module_name ] = $ids;
36
				}
37
			}
38
		}
39
40
		if ( empty( $modules ) ) {
41
			$modules = null;
42
		}
43
		return array( 'scheduled' => Actions::do_full_sync( $modules ) );
44
	}
45
46
	protected function validate_queue( $query ) {
47
		if ( ! isset( $query ) ) {
48
			return new WP_Error( 'invalid_queue', 'Queue name is required', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_queue'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
49
		}
50
51 View Code Duplication
		if ( ! in_array( $query, array( 'sync', 'full_sync', 'immediate' ) ) ) {
52
			return new WP_Error( 'invalid_queue', 'Queue name should be sync, full_sync or immediate', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_queue'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
53
		}
54
		return $query;
55
	}
56
}
57
58
// GET /sites/%s/sync/status
59
class Jetpack_JSON_API_Sync_Status_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
60
	protected function result() {
61
		$args   = $this->query_args();
62
		$fields = isset( $args['fields'] ) ? $args['fields'] : array();
63
		return Actions::get_sync_status( $fields );
64
	}
65
}
66
67
// GET /sites/%s/data-check
68
class Jetpack_JSON_API_Sync_Check_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
69
	protected function result() {
70
		$store = new Replicastore();
71
		return $store->checksum_all();
72
	}
73
}
74
75
// GET /sites/%s/data-histogram
76
class Jetpack_JSON_API_Sync_Histogram_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
77
	protected function result() {
78
		$args = $this->query_args();
79
80
		if ( isset( $args['columns'] ) ) {
81
			$columns = array_map( 'trim', explode( ',', $args['columns'] ) );
82
		} else {
83
			$columns = null; // go with defaults
84
		}
85
86
		$store = new Replicastore();
87
88
		if ( ! isset( $args['strip_non_ascii'] ) ) {
89
			$args['strip_non_ascii'] = true;
90
		}
91
		$histogram = $store->checksum_histogram( $args['object_type'], $args['buckets'], $args['start_id'], $args['end_id'], $columns, $args['strip_non_ascii'], $args['shared_salt'] );
92
93
		return array( 'histogram' => $histogram, 'type' => $store->get_checksum_type() );
94
	}
95
}
96
97
// POST /sites/%s/sync/settings
98
class Jetpack_JSON_API_Sync_Modify_Settings_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
99
	protected function result() {
100
		$args = $this->input();
101
102
		$sync_settings = Settings::get_settings();
103
104
		foreach ( $args as $key => $value ) {
105
			if ( $value !== false ) {
106
				if ( is_numeric( $value ) ) {
107
					$value = (int) $value;
108
				}
109
110
				// special case for sending empty arrays - a string with value 'empty'
111
				if ( $value === 'empty' ) {
112
					$value = array();
113
				}
114
115
				$sync_settings[ $key ] = $value;
116
			}
117
		}
118
119
		Settings::update_settings( $sync_settings );
120
121
		// re-fetch so we see what's really being stored
122
		return Settings::get_settings();
123
	}
124
}
125
126
// GET /sites/%s/sync/settings
127
class Jetpack_JSON_API_Sync_Get_Settings_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
128
	protected function result() {
129
130
		return Settings::get_settings();
131
	}
132
}
133
134
// GET /sites/%s/sync/object
135
class Jetpack_JSON_API_Sync_Object extends Jetpack_JSON_API_Sync_Endpoint {
136
	protected function result() {
137
		$args = $this->query_args();
138
139
		$module_name = $args['module_name'];
140
141
		if ( ! $sync_module = Modules::get_module( $module_name ) ) {
142
			return new WP_Error( 'invalid_module', 'You specified an invalid sync module' );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_module'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
143
		}
144
145
		$object_type = $args['object_type'];
146
		$object_ids  = $args['object_ids'];
147
148
		$codec = Sender::get_instance()->get_codec();
149
150
		Settings::set_is_syncing( true );
151
		$objects = $codec->encode( $sync_module->get_objects_by_id( $object_type, $object_ids ) );
152
		Settings::set_is_syncing( false );
153
154
		return array(
155
			'objects' => $objects,
156
			'codec' => $codec->name(),
157
		);
158
	}
159
}
160
161
class Jetpack_JSON_API_Sync_Now_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
162
	protected function result() {
163
		$args = $this->input();
164
		$queue_name = $this->validate_queue( $args['queue'] );
165
166
		if ( is_wp_error( $queue_name ) ){
167
			return $queue_name;
168
		}
169
170
		$sender = Sender::get_instance();
171
		$response = $sender->do_sync_for_queue( new Queue( $args['queue'] ) );
0 ignored issues
show
Documentation introduced by
new \Automattic\Jetpack\...c\Queue($args['queue']) is of type object<Automattic\Jetpack\Sync\Queue>, but the function expects a object<Automattic\Jetpac...tic\Jetpack\Sync\Queue>.

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...
172
173
		return array(
174
			'response' => $response
175
		);
176
	}
177
}
178
179
class Jetpack_JSON_API_Sync_Checkout_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
180
	protected function result() {
181
		$args       = $this->input();
182
		$queue_name = $this->validate_queue( $args['queue'] );
183
184
		if ( is_wp_error( $queue_name ) ) {
185
			return $queue_name;
186
		}
187
188
		if ( $args['number_of_items'] < 1 || $args['number_of_items'] > 100 ) {
189
			return new WP_Error( 'invalid_number_of_items', 'Number of items needs to be an integer that is larger than 0 and less then 100', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_number_of_items'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
190
		}
191
192
		$number_of_items = absint( $args['number_of_items'] );
193
194
		if ( 'immediate' === $queue_name ) {
195
			return $this->immediate_full_sync_pull( $number_of_items );
196
		}
197
198
		return $this->queue_pull( $queue_name, $number_of_items, $args );
199
	}
200
201
	function queue_pull( $queue_name, $number_of_items, $args ){
202
		$queue = new Queue( $queue_name );
203
204
		if ( 0 === $queue->size() ) {
205
			return new WP_Error( 'queue_size', 'The queue is empty and there is nothing to send', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'queue_size'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
206
		}
207
208
		$sender = Sender::get_instance();
209
210
		// try to give ourselves as much time as possible.
211
		set_time_limit( 0 );
212
213
		if ( $args['pop'] ) {
214
			$buffer = new Queue_Buffer( 'pop', $queue->pop( $number_of_items ) );
0 ignored issues
show
Bug introduced by
It seems like $queue->pop($number_of_items) targeting Automattic\Jetpack\Sync\Queue::pop() can also be of type null or object; however, Automattic\Jetpack\Sync\...e_Buffer::__construct() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
215
		} else {
216
			// let's delete the checkin state.
217
			if ( $args['force'] ) {
218
				$queue->unlock();
219
			}
220
			$buffer = $this->get_buffer( $queue, $number_of_items );
221
		}
222
		// Check that the $buffer is not checkout out already.
223
		if ( is_wp_error( $buffer ) ) {
224
			return new WP_Error( 'buffer_open', "We couldn't get the buffer it is currently checked out", 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'buffer_open'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
225
		}
226
227
		if ( ! is_object( $buffer ) ) {
228
			return new WP_Error( 'buffer_non-object', 'Buffer is not an object', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'buffer_non-object'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
229
		}
230
231
		Settings::set_is_syncing( true );
232
		list( $items_to_send, $skipped_items_ids ) = $sender->get_items_to_send( $buffer, $args['encode'] );
233
		Settings::set_is_syncing( false );
234
235
		return array(
236
			'buffer_id'      => $buffer->id,
237
			'items'          => $items_to_send,
238
			'skipped_items'  => $skipped_items_ids,
239
			'codec'          => $args['encode'] ? $sender->get_codec()->name() : null,
240
			'sent_timestamp' => time(),
241
		);
242
	}
243
244
	public $items = [];
245
246
	public function jetpack_sync_send_data_listener() {
247
		foreach ( func_get_args()[0] as $key => $item ) {
248
			$this->items[ $key ] = $item;
249
		}
250
	}
251
252
	public function immediate_full_sync_pull( $number_of_items ) {
253
		// try to give ourselves as much time as possible.
254
		set_time_limit( 0 );
255
256
		$original_send_data_cb = array( 'Automattic\Jetpack\Sync\Actions', 'send_data' );
257
		$temp_send_data_cb     = array( $this, 'jetpack_sync_send_data_listener' );
258
259
		Sender::get_instance()->set_enqueue_wait_time( 0 );
260
		remove_filter( 'jetpack_sync_send_data', $original_send_data_cb );
261
		add_filter( 'jetpack_sync_send_data', $temp_send_data_cb, 10, 6 );
262
		Sender::get_instance()->do_full_sync();
263
		remove_filter( 'jetpack_sync_send_data', $temp_send_data_cb );
264
		add_filter( 'jetpack_sync_send_data', $original_send_data_cb, 10, 6 );
265
266
		return array(
267
			'items'          => $this->items,
268
			'codec'          => Sender::get_instance()->get_codec()->name(),
269
			'sent_timestamp' => time(),
270
			'status'         => Actions::get_sync_status(),
271
		);
272
	}
273
274
	protected function get_buffer( $queue, $number_of_items ) {
275
		$start = time();
276
		$max_duration = 5; // this will try to get the buffer
277
278
		$buffer = $queue->checkout( $number_of_items );
279
		$duration = time() - $start;
280
281
		while( is_wp_error( $buffer ) && $duration < $max_duration ) {
282
			sleep( 2 );
283
			$duration = time() - $start;
284
			$buffer = $queue->checkout( $number_of_items );
285
		}
286
287
		if ( $buffer === false ) {
288
			return new WP_Error( 'queue_size', 'The queue is empty and there is nothing to send', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'queue_size'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
289
		}
290
291
		return $buffer;
292
	}
293
}
294
295
class Jetpack_JSON_API_Sync_Close_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
296
	protected function result() {
297
		$request_body = $this->input();
298
		$queue_name = $this->validate_queue( $request_body['queue'] );
299
300
		if ( is_wp_error( $queue_name ) ) {
301
			return $queue_name;
302
		}
303
304
		if ( ! isset( $request_body['buffer_id'] ) ) {
305
			return new WP_Error( 'missing_buffer_id', 'Please provide a buffer id', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'missing_buffer_id'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
306
		}
307
308
		if ( ! isset( $request_body['item_ids'] ) || ! is_array( $request_body['item_ids'] ) ) {
309
			return new WP_Error( 'missing_item_ids', 'Please provide a list of item ids in the item_ids argument', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'missing_item_ids'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
310
		}
311
312
		//Limit to A-Z,a-z,0-9,_,-
313
		$request_body ['buffer_id'] = preg_replace( '/[^A-Za-z0-9]/', '', $request_body['buffer_id'] );
314
		$request_body['item_ids'] = array_filter( array_map( array( 'Jetpack_JSON_API_Sync_Close_Endpoint', 'sanitize_item_ids' ), $request_body['item_ids'] ) );
315
316
		$queue = new Queue( $queue_name );
317
318
		$items = $queue->peek_by_id( $request_body['item_ids'] );
319
320
		/** This action is documented in packages/sync/src/modules/Full_Sync.php */
321
		$full_sync_module = Modules::get_module( 'full-sync' );
322
323
		$full_sync_module->update_sent_progress_action( $items );
324
325
		$buffer = new Queue_Buffer( $request_body['buffer_id'], $request_body['item_ids'] );
326
		$response = $queue->close( $buffer, $request_body['item_ids'] );
0 ignored issues
show
Documentation introduced by
$buffer is of type object<Automattic\Jetpack\Sync\Queue_Buffer>, but the function expects a object<Automattic\Jetpac...pack\Sync\Queue_Buffer>.

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...
327
328
		if ( is_wp_error( $response ) ) {
329
			return $response;
330
		}
331
332
		return array(
333
			'success' => $response,
334
			'status' => Actions::get_sync_status(),
335
		);
336
	}
337
338
	protected static function sanitize_item_ids( $item ) {
339
		// lets not delete any options that don't start with jpsq_sync-
340
		if ( substr( $item, 0, 5 ) !== 'jpsq_' ) {
341
			return null;
342
		}
343
		//Limit to A-Z,a-z,0-9,_,-,.
344
		return preg_replace( '/[^A-Za-z0-9-_.]/', '', $item );
345
	}
346
}
347
348
class Jetpack_JSON_API_Sync_Unlock_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
349
	protected function result() {
350
		$args = $this->input();
351
352
		if ( ! isset( $args['queue'] ) ) {
353
			return new WP_Error( 'invalid_queue', 'Queue name is required', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_queue'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
354
		}
355
356 View Code Duplication
		if ( ! in_array( $args['queue'], array( 'sync', 'full_sync' ) ) ) {
357
			return new WP_Error( 'invalid_queue', 'Queue name should be sync or full_sync', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_queue'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
358
		}
359
360
		$queue = new Queue( $args['queue'] );
361
362
		// False means that there was no lock to delete.
363
		$response = $queue->unlock();
364
		return array(
365
			'success' => $response
366
		);
367
	}
368
}
369
370
class Jetpack_JSON_API_Sync_Object_Id_Range extends Jetpack_JSON_API_Sync_Endpoint {
371
	protected function result() {
372
		$args = $this->query_args();
373
374
		$module_name = $args['sync_module'];
375
		$batch_size  = $args['batch_size'];
376
377
		if ( ! $this->is_valid_sync_module( $module_name ) ) {
378
			return new WP_Error( 'invalid_module', 'This sync module cannot be used to calculate a range.', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_module'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
379
		}
380
381
		$module = Modules::get_module( $module_name );
382
383
		return array(
384
			'ranges' => $module->get_min_max_object_ids_for_batches( $batch_size ),
385
		);
386
	}
387
388
	protected function is_valid_sync_module( $module_name ) {
389
		return in_array(
390
			$module_name,
391
			array(
392
				'comments',
393
				'posts',
394
				'terms',
395
				'term_relationships',
396
				'users',
397
			),
398
			true
399
		);
400
	}
401
}
402