Completed
Push — update/endpoint-pull-immediate... ( b750f8 )
by
unknown
07:46
created

Jetpack_JSON_API_Sync_Checkout_Endpoint::result()   C

Complexity

Conditions 12
Paths 16

Size

Total Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
nc 16
nop 0
dl 0
loc 58
rs 6.4896
c 0
b 0
f 0

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
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
		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 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...
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 ( ! empty( $args['queue'] ) && 'immediate' === $args['queue'] ) {
195
			return $this->immediate_full_sync_pull( $number_of_items );
196
		}
197
		$queue = new Queue( $queue_name );
198
199
		if ( 0 === $queue->size() ) {
200
			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...
201
		}
202
203
		$sender = Sender::get_instance();
204
205
		// try to give ourselves as much time as possible.
206
		set_time_limit( 0 );
207
208
		if ( $args['pop'] ) {
209
			$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...
210
		} else {
211
			// let's delete the checkin state.
212
			if ( $args['force'] ) {
213
				$queue->unlock();
214
			}
215
			$buffer = $this->get_buffer( $queue, $number_of_items );
216
		}
217
		// Check that the $buffer is not checkout out already.
218
		if ( is_wp_error( $buffer ) ) {
219
			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...
220
		}
221
222
		if ( ! is_object( $buffer ) ) {
223
			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...
224
		}
225
226
		Settings::set_is_syncing( true );
227
		list( $items_to_send, $skipped_items_ids ) = $sender->get_items_to_send( $buffer, $args['encode'] );
228
		Settings::set_is_syncing( false );
229
230
		return array(
231
			'buffer_id'      => $buffer->id,
232
			'items'          => $items_to_send,
233
			'skipped_items'  => $skipped_items_ids,
234
			'codec'          => $args['encode'] ? $sender->get_codec()->name() : null,
235
			'sent_timestamp' => time(),
236
		);
237
	}
238
239
	public $items = [];
240
241
	public function jetpack_sync_send_data_listener() {
242
		foreach ( func_get_args()[0] as $key => $item ) {
243
			$items[ $key ] = $item;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$items was never initialized. Although not strictly required by PHP, it is generally a good practice to add $items = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
244
		}
245
	}
246
247
	public function immediate_full_sync_pull( $number_of_items ) {
248
		// try to give ourselves as much time as possible.
249
		set_time_limit( 0 );
250
251
		remove_filter( 'jetpack_sync_send_data', array( 'Automattic\Jetpack\Sync\Actions', 'send_data' ), 10, 6 );
252
		add_filter( 'jetpack_sync_send_data', array( $this, 'jetpack_sync_send_data_listener' ), 10, 6 );
253
		Sender::get_instance()->do_full_sync();
254
		remove_filter( 'jetpack_sync_send_data', array( $this, 'jetpack_sync_send_data_listener' ), 10, 6 );
255
		add_filter( 'jetpack_sync_send_data', array( 'Automattic\Jetpack\Sync\Actions', 'send_data' ), 10, 6 );
256
257
		return array(
258
			'items'          => $this->items,
259
			'codec'          => Sender::get_instance()->get_codec()->name(),
260
			'sent_timestamp' => time(),
261
			'status'         => Actions::get_sync_status(),
262
		);
263
	}
264
265
	protected function get_buffer( $queue, $number_of_items ) {
266
		$start = time();
267
		$max_duration = 5; // this will try to get the buffer
268
269
		$buffer = $queue->checkout( $number_of_items );
270
		$duration = time() - $start;
271
272
		while( is_wp_error( $buffer ) && $duration < $max_duration ) {
273
			sleep( 2 );
274
			$duration = time() - $start;
275
			$buffer = $queue->checkout( $number_of_items );
276
		}
277
278
		if ( $buffer === false ) {
279
			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...
280
		}
281
282
		return $buffer;
283
	}
284
}
285
286
class Jetpack_JSON_API_Sync_Close_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
287
	protected function result() {
288
		$request_body = $this->input();
289
		$queue_name = $this->validate_queue( $request_body['queue'] );
290
291
		if ( is_wp_error( $queue_name ) ) {
292
			return $queue_name;
293
		}
294
295
		if ( ! isset( $request_body['buffer_id'] ) ) {
296
			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...
297
		}
298
299
		if ( ! isset( $request_body['item_ids'] ) || ! is_array( $request_body['item_ids'] ) ) {
300
			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...
301
		}
302
303
		//Limit to A-Z,a-z,0-9,_,-
304
		$request_body ['buffer_id'] = preg_replace( '/[^A-Za-z0-9]/', '', $request_body['buffer_id'] );
305
		$request_body['item_ids'] = array_filter( array_map( array( 'Jetpack_JSON_API_Sync_Close_Endpoint', 'sanitize_item_ids' ), $request_body['item_ids'] ) );
306
307
		$queue = new Queue( $queue_name );
308
309
		$items = $queue->peek_by_id( $request_body['item_ids'] );
310
311
		/** This action is documented in packages/sync/src/modules/Full_Sync.php */
312
		$full_sync_module = Modules::get_module( 'full-sync' );
313
314
		$full_sync_module->update_sent_progress_action( $items );
315
316
		$buffer = new Queue_Buffer( $request_body['buffer_id'], $request_body['item_ids'] );
317
		$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...
318
319
		if ( is_wp_error( $response ) ) {
320
			return $response;
321
		}
322
323
		return array(
324
			'success' => $response,
325
			'status' => Actions::get_sync_status(),
326
		);
327
	}
328
329
	protected static function sanitize_item_ids( $item ) {
330
		// lets not delete any options that don't start with jpsq_sync-
331
		if ( substr( $item, 0, 5 ) !== 'jpsq_' ) {
332
			return null;
333
		}
334
		//Limit to A-Z,a-z,0-9,_,-,.
335
		return preg_replace( '/[^A-Za-z0-9-_.]/', '', $item );
336
	}
337
}
338
339
class Jetpack_JSON_API_Sync_Unlock_Endpoint extends Jetpack_JSON_API_Sync_Endpoint {
340
	protected function result() {
341
		$args = $this->input();
342
343
		if ( ! isset( $args['queue'] ) ) {
344
			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...
345
		}
346
347 View Code Duplication
		if ( ! in_array( $args['queue'], array( 'sync', 'full_sync' ) ) ) {
348
			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...
349
		}
350
351
		$queue = new Queue( $args['queue'] );
352
353
		// False means that there was no lock to delete.
354
		$response = $queue->unlock();
355
		return array(
356
			'success' => $response
357
		);
358
	}
359
}
360
361
class Jetpack_JSON_API_Sync_Object_Id_Range extends Jetpack_JSON_API_Sync_Endpoint {
362
	protected function result() {
363
		$args = $this->query_args();
364
365
		$module_name = $args['sync_module'];
366
		$batch_size  = $args['batch_size'];
367
368
		if ( ! $this->is_valid_sync_module( $module_name ) ) {
369
			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...
370
		}
371
372
		$module = Modules::get_module( $module_name );
373
374
		return array(
375
			'ranges' => $module->get_min_max_object_ids_for_batches( $batch_size ),
376
		);
377
	}
378
379
	protected function is_valid_sync_module( $module_name ) {
380
		return in_array(
381
			$module_name,
382
			array(
383
				'comments',
384
				'posts',
385
				'terms',
386
				'term_relationships',
387
				'users',
388
			),
389
			true
390
		);
391
	}
392
}
393