Completed
Push — ignore/lazy-images-linting-pac... ( 3c044f...b5c515 )
by Jeremy
367:06 queued 352:42
created

Jetpack_Sync_Test_Replicastore::update_option()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
use Automattic\Jetpack\Sync\Replicastore_Interface;
4
use Automattic\Jetpack\Sync\Defaults;
5
6
/**
7
 * A simple in-memory implementation of iJetpack_Sync_Replicastore
8
 * used for development and testing
9
 */
10
class Jetpack_Sync_Test_Replicastore implements Replicastore_Interface {
11
12
	private $posts;
13
	private $post_status;
14
	private $comments;
15
	private $comment_status;
16
	private $options;
17
18
	/**
19
	 * Stores info related to the theme.
20
	 *
21
	 * @var array $theme_info stores theme info.
22
	 */
23
	private $theme_info;
24
	private $meta;
25
	private $meta_filter;
26
	private $constants;
27
	private $updates;
28
	private $callable;
29
	private $network_options;
30
	private $terms;
31
	private $term_relationships;
32
	private $object_terms;
33
	private $users;
34
	private $users_locale;
35
	private $allowed_mime_types;
36
	private $checksum_fields;
37
38
	function __construct() {
39
		$this->reset();
40
	}
41
42
	function reset() {
43
		$this->posts[ get_current_blog_id() ]           = array();
44
		$this->comments[ get_current_blog_id() ]        = array();
45
		$this->options[ get_current_blog_id() ]         = array();
46
		$this->theme_info[ get_current_blog_id() ]         = array();
47
		$this->meta[ get_current_blog_id() ]            = array( 'post' => array(), 'comment' => array() );
48
		$this->constants[ get_current_blog_id() ]       = array();
49
		$this->updates[ get_current_blog_id() ]         = array();
50
		$this->callable[ get_current_blog_id() ]        = array();
51
		$this->network_options[ get_current_blog_id() ] = array();
52
		$this->terms[ get_current_blog_id() ]           = array();
53
		$this->term_relationships[ get_current_blog_id() ] = array();
54
		$this->object_terms[ get_current_blog_id() ]    = array();
55
		$this->users[ get_current_blog_id() ]           = array();
56
		$this->users_locale[ get_current_blog_id() ]    = array();
57
	}
58
59
	function full_sync_start( $config ) {
60
		$this->reset();
61
	}
62
63
	function full_sync_end( $checksum ) {
64
		// noop right now
65
	}
66
67
	function post_count( $status = null, $min_id = null, $max_id = null ) {
68
		return count( $this->get_posts( $status, $min_id, $max_id ) );
69
	}
70
71 View Code Duplication
	function get_posts( $status = null, $min_id = null, $max_id = null ) {
72
		$this->post_status[ get_current_blog_id() ] = $status;
73
74
		$posts = array_filter( array_values( $this->posts[ get_current_blog_id() ] ), array( $this, 'filter_post_status' ) );
75
76
		foreach ( $posts as $i => $post ) {
77
			if ( ( $min_id && $post->ID < $min_id ) || ( $max_id && $post->ID > $max_id ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $min_id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $max_id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
78
				unset( $posts[ $i ] );
79
			}
80
		}
81
82
		return array_values( $posts );
83
	}
84
85
	function posts_checksum( $min_id = null, $max_id = null ) {
86
		return $this->calculate_checksum( $this->posts[ get_current_blog_id() ], 'ID', $min_id, $max_id, Defaults::$default_post_checksum_columns );
87
	}
88
89
	function post_meta_checksum( $min_id = null, $max_id = null ) {
90
		return null;
91
	}
92
93
	function filter_post_status( $post ) {
94
		$matched_status = ! in_array( $post->post_status, array( 'inherit' ) )
95
		                  && ( $this->post_status[ get_current_blog_id() ] ? $post->post_status === $this->post_status[ get_current_blog_id() ] : true );
96
97
		return $matched_status;
98
	}
99
100
	function get_post( $id ) {
101
		return isset( $this->posts[ get_current_blog_id() ][ $id ] ) ? $this->posts[ get_current_blog_id() ][ $id ] : false;
102
	}
103
104
	function upsert_post( $post, $silent = false ) {
105
		$this->posts[ get_current_blog_id() ][ $post->ID ] = $this->cast_to_post( $post );
106
	}
107
108
	function delete_post( $post_id ) {
109
		unset( $this->posts[ get_current_blog_id() ][ $post_id ] );
110
	}
111
112
	function comment_count( $status = null, $min_id = null, $max_id = null ) {
113
		return count( $this->get_comments( $status, $min_id, $max_id ) );
114
	}
115
116 View Code Duplication
	function get_comments( $status = null, $min_id = null, $max_id = null ) {
117
		$this->comment_status[ get_current_blog_id() ] = $status;
118
119
		// valid statuses: 'hold', 'approve', 'spam', 'trash', or 'post-trashed.
120
		$comments = array_filter( array_values( $this->comments[ get_current_blog_id() ] ), array( $this, 'filter_comment_status' ) );
121
122
		foreach ( $comments as $i => $comment ) {
123
			if ( $min_id && $comment->comment_ID < $min_id || $max_id && $comment->comment_ID > $max_id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $min_id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $max_id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
124
				unset( $comments[ $i ] );
125
			}
126
		}
127
128
		return array_values( $comments );
129
	}
130
131
	function comments_checksum( $min_id = null, $max_id = null ) {
132
		return $this->calculate_checksum( array_filter( $this->comments[ get_current_blog_id() ], array( $this, 'is_not_spam' ) ), 'comment_ID', $min_id, $max_id, Defaults::$default_comment_checksum_columns );
133
	}
134
135
	function comment_meta_checksum( $min_id = null, $max_id = null ) {
136
		return null;
137
	}
138
139
	function is_not_spam( $comment ) {
140
		return $comment->comment_approved !== 'spam';
141
	}
142
143
	function filter_comment_status( $comment ) {
144
		switch ( $this->comment_status[ get_current_blog_id() ] ) {
145
			case 'approve':
146
				return '1' === $comment->comment_approved;
147
			case 'hold':
148
				return '0' === $comment->comment_approved;
149
			case 'spam':
150
				return 'spam' === $comment->comment_approved;
151
			case 'trash':
152
				return 'trash' === $comment->comment_approved;
153
			case 'post-trashed':
154
				return 'post-trashed' === $comment->comment_approved;
155
			case 'any':
156
				return true;
157
			case 'all':
158
				return true;
159
			default:
160
				return true;
161
		}
162
	}
163
164
	function get_comment( $id ) {
165
		if ( isset( $this->comments[ get_current_blog_id() ][ $id ] ) ) {
166
			return $this->comments[ get_current_blog_id() ][ $id ];
167
		}
168
169
		return false;
170
	}
171
172
	function upsert_comment( $comment, $silent = false ) {
173
		$this->comments[ get_current_blog_id() ][ $comment->comment_ID ] = $comment;
174
	}
175
176
	function trash_comment( $comment_id ) {
177
		$this->comments[ get_current_blog_id() ][ $comment_id ]->comment_approved = 'trash';
178
	}
179
180
	function spam_comment( $comment_id ) {
181
		$this->comments[ get_current_blog_id() ][ $comment_id ]->comment_approved = 'spam';
182
	}
183
184
	function trashed_post_comments( $post_id, $statuses ) {
185
		$statuses = (array) $statuses;
186
		foreach( $statuses as $comment_id => $status ) {
187
			$this->comments[ get_current_blog_id() ][ $comment_id ]->comment_approved = 'post-trashed';
188
		}
189
	}
190
191
	function untrashed_post_comments( $post_id ) {
192
		$statuses = (array) $this->get_metadata( 'post', $post_id, '_wp_trash_meta_comments_status', true );
193
194
		foreach( $statuses as $comment_id => $status ) {
195
			$this->comments[ get_current_blog_id() ][ $comment_id ]->comment_approved = $status;
196
		}
197
	}
198
199
	function delete_comment( $comment_id ) {
200
		unset( $this->comments[ get_current_blog_id() ][ $comment_id ] );
201
	}
202
203
	function get_option( $option, $default = false ) {
204
		return isset( $this->options[ get_current_blog_id() ][ $option ] ) ? $this->options[ get_current_blog_id() ][ $option ] : $default;
205
	}
206
207
	function update_option( $option, $value ) {
208
		$this->options[ get_current_blog_id() ][ $option ] = $value;
209
	}
210
211
	function delete_option( $option ) {
212
		$this->options[ get_current_blog_id() ][ $option ] = false;
213
	}
214
215
	function options_checksum() {
216
		return strtoupper( dechex( array_reduce( Defaults::$default_options_whitelist, array( $this, 'option_checksum' ), 0 ) ) );
217
	}
218
219
	private function option_checksum( $carry, $option_name ) {
220
		return $carry ^ ( array_key_exists( $option_name, $this->options[ get_current_blog_id() ] ) ? ( sprintf( '%u', crc32( $option_name . $this->options[ get_current_blog_id() ][ $option_name ] ) ) + 0 ) : 0 );
221
	}
222
223
	/**
224
	 * Change the info of the current theme.
225
	 *
226
	 * @access public
227
	 *
228
	 * @param array $theme_info Theme info array.
229
	 */
230
	public function set_theme_info( $theme_info ) {
231
		$this->theme_info[ get_current_blog_id() ] = (object) $theme_info;
232
	}
233
234
	function current_theme_supports( $feature ) {
235
		$theme_supports = $this->get_callable( 'theme_support' );
236
		return isset( $theme_supports[ $feature ] );
237
	}
238
239
	// meta
240
	public function get_metadata( $type, $object_id, $meta_key = '', $single = false ) {
241
242
		$object_id                      = absint( $object_id );
243
		$this->meta_filter[ get_current_blog_id() ]['type']      = $type;
244
		$this->meta_filter[ get_current_blog_id() ]['object_id'] = $object_id;
245
		$this->meta_filter[ get_current_blog_id() ]['meta_key']  = $meta_key;
246
247
		$meta_entries = array_values( array_filter( $this->meta[ get_current_blog_id() ][ $type ], array( $this, 'find_meta' ) ) );
248
249
		if ( count( $meta_entries ) === 0 ) {
250
			// match return signature of WP code
251
			if ( $single ) {
252
				return '';
253
			} else {
254
				return array();
255
			}
256
		}
257
258
		$meta_values = array_map( array( $this, 'get_meta_valued' ), $meta_entries );
259
260
		if ( $single ) {
261
			return $meta_values[0];
262
		}
263
264
		return $meta_values;
265
	}
266
267
	// this is just here to support checksum histograms
268 View Code Duplication
	function get_post_meta_by_id( $meta_id ) {
269
		$matching_metas = array();
270
		$metas = $this->meta[ get_current_blog_id() ]['post'];
271
		foreach ( $metas as $m ) {
272
			if ( $m->meta_id === $meta_id ) {
273
				$matching_metas[] = $m;
274
			}
275
		}
276
		return reset( $matching_metas );
277
	}
278
279
	// this is just here to support checksum histograms
280 View Code Duplication
	function get_comment_meta_by_id( $meta_id ) {
281
		$matching_metas = array();
282
		$metas = $this->meta[ get_current_blog_id() ]['comment'];
283
		foreach ( $metas as $m ) {
284
			if ( $m->meta_id === $meta_id ) {
285
				$matching_metas[] = $m;
286
			}
287
		}
288
		return reset( $matching_metas );
289
	}
290
291
	public function find_meta( $meta ) {
292
		// must match object ID
293
		$match = ( $this->meta_filter[ get_current_blog_id() ]['object_id'] === $meta->object_id );
294
295
		// match key if given
296
		if ( $match && $this->meta_filter[ get_current_blog_id() ]['meta_key'] ) {
297
			$match = ( $meta->meta_key === $this->meta_filter[ get_current_blog_id() ]['meta_key'] );
298
		}
299
300
		return $match;
301
	}
302
303
	public function get_meta_valued( $meta ) {
304
		return $meta->meta_value;
305
	}
306
307
	public function upsert_metadata( $type, $object_id, $meta_key, $meta_value, $meta_id ) {
308
		$this->meta[ get_current_blog_id() ][ $type ][ $meta_id ] = (object) array(
309
			'meta_id'    => $meta_id,
310
			'type'       => $type,
311
			'object_id'  => absint( $object_id ),
312
			'meta_key'   => $meta_key,
313
			'meta_value' => $meta_value,
314
		);
315
	}
316
317
	public function delete_metadata( $type, $object_id, $meta_ids ) {
318
		foreach ( $meta_ids as $meta_id ) {
319
			unset( $this->meta[ get_current_blog_id() ][ $type ][ $meta_id ] );
320
		}
321
	}
322
323
	public function delete_batch_metadata( $type, $object_ids, $meta_key ) {
324
		$meta_ids = array();
325
		foreach ( $this->meta[ get_current_blog_id() ][ $type ] as $meta_id => $meta_data ) {
326
			if (
327
				$meta_data->meta_key === $meta_key &&
328
				in_array( $meta_data->object_id, $object_ids )
329
			) {
330
			$meta_ids[] = $meta_id;
331
			}
332
		}
333
334
		foreach ( $meta_ids as $meta_id ) {
335
			unset( $this->meta[ get_current_blog_id() ][ $type ][ $meta_id ] );
336
		}
337
	}
338
339
340
341
	// constants
342
	public function get_constant( $constant ) {
343
		if ( ! isset( $this->constants[ get_current_blog_id() ][ $constant ] ) ) {
344
			return null;
345
		}
346
347
		return $this->constants[ get_current_blog_id() ][ $constant ];
348
	}
349
350
	public function set_constant( $constant, $value ) {
351
		return $this->constants[ get_current_blog_id() ][ $constant ] = $value;
352
	}
353
354
	// updates
355
	public function get_updates( $type ) {
356
		if ( ! isset( $this->updates[ get_current_blog_id() ][ $type ] ) ) {
357
			return null;
358
		}
359
360
		return $this->updates[ get_current_blog_id() ][ $type ];
361
	}
362
363
	public function set_updates( $type, $updates ) {
364
		$this->updates[ get_current_blog_id() ][ $type ] = $updates;
365
	}
366
367
	// updates
368
	public function get_callable( $function ) {
369
		if ( ! isset( $this->callable[ get_current_blog_id() ][ $function ] ) ) {
370
			return null;
371
		}
372
373
		return $this->callable[ get_current_blog_id() ][ $function ];
374
	}
375
376
	public function set_callable( $name, $value ) {
377
		$this->callable[ get_current_blog_id() ][ $name ] = $value;
378
	}
379
380
	// network options
381
	function get_site_option( $option ) {
382
		return isset( $this->network_options[ get_current_blog_id() ][ $option ] ) ? $this->network_options[ get_current_blog_id() ][ $option ] : false;
383
	}
384
385
	function update_site_option( $option, $value ) {
386
		$this->network_options[ get_current_blog_id() ][ $option ] = $value;
387
	}
388
389
	function delete_site_option( $option ) {
390
		$this->network_options[ get_current_blog_id() ][ $option ] = false;
391
	}
392
393
	// terms
394
	function get_terms( $taxonomy ) {
395
		return isset( $this->terms[ get_current_blog_id() ][ $taxonomy ] ) ? $this->terms[ get_current_blog_id() ][ $taxonomy ] : array();
396
	}
397
398
	function get_term( $taxonomy, $term_id, $term_key = 'term_id' ) {
399
		if ( ! $taxonomy && 'term_taxonomy_id' === $term_key ) {
400
			foreach ( $this->terms[ get_current_blog_id() ] as $tax => $terms_array ) {
401
				$term = $this->get_term( $tax, $term_id, 'term_taxonomy_id' );
402
				if ( $term ) {
403
					return $term;
404
				}
405
			}
406
		}
407
		if ( ! isset( $this->terms[ get_current_blog_id() ][ $taxonomy ] ) ) {
408
			return array();
409
		}
410
		foreach ( $this->terms[ get_current_blog_id() ][ $taxonomy ] as $term_object ) {
411
			switch ( $term_key ) {
412
				case 'term_id':
413
					$term = ( $term_id == $term_object->term_id ) ? $term_object : null;
414
					break;
415
				case 'term_taxonomy_id':
416
					$term = ( $term_id == $term_object->term_taxonomy_id ) ? $term_object : null;
417
					break;
418
				case 'slug':
419
					$term = ( $term_id === $term_object->slug ) ? $term_object : null;
420
					break;
421
			}
422
423
			if ( ! empty( $term ) ) {
424
				return $term;
425
			}
426
		}
427
428
		return array();
429
	}
430
431
	function get_the_terms( $object_id, $taxonomy ) {
432
		$terms = array();
433
		if ( ! isset( $this->object_terms[ get_current_blog_id() ][ $taxonomy ] ) ) {
434
			return false;
435
		}
436
		foreach ( $this->object_terms[ get_current_blog_id() ][ $taxonomy ][ $object_id ] as $term_id ) {
437
			$term_key = is_numeric( $term_id ) ? 'term_id' : 'slug';
438
			$terms[]  = $this->get_term( $taxonomy, $term_id, $term_key );
439
		}
440
441
		return $terms;
442
	}
443
444
	function update_term( $term_object ) {
445
		$taxonomy = $term_object->taxonomy;
446
447
		if ( ! isset( $this->terms[ get_current_blog_id() ][ $taxonomy ] ) ) {
448
			// empty
449
			$this->terms[ get_current_blog_id() ][ $taxonomy ]   = array();
450
			$this->terms[ get_current_blog_id() ][ $taxonomy ][] = $term_object;
451
		}
452
		$terms  = array();
453
		$action = 'none';
454
455
		// Note: array_map might be better for this but didn't want to write a callback
456
		foreach ( $this->terms[ get_current_blog_id() ][ $taxonomy ] as $saved_term_object ) {
457
			if ( $saved_term_object->term_id === $term_object->term_id ) {
458
				$terms[] = $term_object;
459
				$action  = 'updated';
460
			} else {
461
				$terms[] = $saved_term_object;
462
			}
463
		}
464
		if ( 'updated' !== $action ) {
465
			// we should add the tem since we didn't update it.
466
			$terms[] = $term_object;
467
		}
468
		$this->terms[ get_current_blog_id() ][ $taxonomy ] = $terms;
469
	}
470
471
	private function update_term_count( $taxonomy, $term_id ) {
472
		$term_key    = is_numeric( $term_id ) ? 'term_id' : 'slug';
473
		$term_object = $this->get_term( $taxonomy, $term_id, $term_key );
474
		$count       = 0;
475
		foreach ( $this->object_terms[ get_current_blog_id() ][ $taxonomy ] as $object_id => $term_ids ) {
476
			foreach ( $term_ids as $saved_term_id ) {
477
				if ( $saved_term_id === $term_id ) {
478
					$count ++;
479
				}
480
			}
481
		}
482
		if ( empty( $term_object ) ) {
483
			return;
484
		}
485
		$term_object->count = $count;
486
		$this->update_term( $term_object );
487
	}
488
489
	function delete_term( $term_id, $taxonomy ) {
490
		if ( ! isset( $this->terms[ get_current_blog_id() ][ $taxonomy ] ) ) {
491
			// empty
492
			$this->terms[ get_current_blog_id() ][ $taxonomy ] = array();
493
		}
494
		$terms = array();
495
496
		// Note: array_map might be better for this but didn't want to write a callback
497
		foreach ( $this->terms[ get_current_blog_id() ][ $taxonomy ] as $saved_term_object ) {
498
			if ( $saved_term_object->term_id !== $term_id ) {
499
				$terms[] = $saved_term_object;
500
			}
501
		}
502
		$this->terms[ get_current_blog_id() ][ $taxonomy ] = $terms;
503
		if ( empty( $this->terms[ get_current_blog_id() ][ $taxonomy ] ) ) {
504
			unset( $this->terms[ get_current_blog_id() ][ $taxonomy ] );
505
		}
506
	}
507
508
	function delete_object_terms( $object_id, $tt_ids ) {
509
		$saved_data = array();
510
		foreach ( $this->object_terms[ get_current_blog_id() ] as $taxonomy => $taxonomy_object_terms ) {
511
			foreach ( $taxonomy_object_terms as $saved_object_id => $term_ids ) {
512
				foreach ( $term_ids as $saved_term_id ) {
513
					$term = $this->get_term( $taxonomy, $saved_term_id, 'term_id' );
514
					if ( isset( $term->term_taxonomy_id ) && ! in_array( $term->term_taxonomy_id, $tt_ids ) && $object_id === $saved_object_id ) {
515
						$saved_data[ $taxonomy ] [ $saved_object_id ][] = $saved_term_id;
516
					} else if ( isset( $term->term_taxonomy_id ) && in_array( $term->term_taxonomy_id, $tt_ids ) && $object_id === $saved_object_id ) {
517
						$this->update_term_count( $taxonomy, $term->term_id );
518
					}
519
				}
520
			}
521
		}
522
		$this->object_terms[ get_current_blog_id() ] = $saved_data;
523
	}
524
525
	function update_object_terms( $object_id, $taxonomy, $term_ids, $append ) {
526
		if ( $append ) {
527
			$previous_array                                = isset( $this->object_terms[ get_current_blog_id() ][ $taxonomy ] )
528
			                                                 && isset( $this->object_terms[ get_current_blog_id() ][ $taxonomy ][ $object_id ] )
529
				? $this->object_terms[ get_current_blog_id() ][ $taxonomy ][ $object_id ] : array();
530
			$this->object_terms[ get_current_blog_id() ][ $taxonomy ][ $object_id ] = array_merge( $previous_array, $term_ids );
531
		} else {
532
			$this->object_terms[ get_current_blog_id() ][ $taxonomy ][ $object_id ] = $term_ids;
533
		}
534
535
		foreach ( $term_ids as $term_id ) {
0 ignored issues
show
Bug introduced by
The expression $term_ids of type string|integer|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
536
			$this->update_term_count( $taxonomy, $term_id );
537
		}
538
	}
539
540
	function update_term_relationships( $term_relationships ) {
541
		$this->term_relationships[ get_current_blog_id() ][] = $term_relationships;
542
	}
543
544
	function user_count() {
545
		return count( $this->users[ get_current_blog_id() ] );
546
	}
547
548
	function get_user( $user_id ) {
549
		return isset( $this->users[ get_current_blog_id() ][ $user_id ] ) ? $this->users[ get_current_blog_id() ][ $user_id ] : null;
550
	}
551
552
	function upsert_user_locale( $user_id, $user_locale ) {
553
		$this->users_locale[ get_current_blog_id() ][ $user_id ] = $user_locale;
554
	}
555
556
	function delete_user_locale( $user_id ) {
557
		unset( $this->users_locale[ get_current_blog_id() ][ $user_id ] );
558
	}
559
560
	function get_user_locale( $user_id ) {
561
		return isset( $this->users_locale[ get_current_blog_id() ][ $user_id ] ) ? $this->users_locale[ get_current_blog_id() ][ $user_id ] : null;
562
	}
563
564
	function get_allowed_mime_types( $user_id ) {
565
		return isset( $this->allowed_mime_types[ get_current_blog_id() ][ $user_id ] ) ? $this->allowed_mime_types[ get_current_blog_id() ][ $user_id ] : null;
566
	}
567
568
	function upsert_user( $user ) {
569 View Code Duplication
		if ( isset( $user->allowed_mime_types ) ) {
570
			$this->allowed_mime_types[ get_current_blog_id() ][ $user->ID ] = $user->allowed_mime_types;
571
			unset( $user->allowed_mime_types );
572
		}
573
		// when doing a full sync
574 View Code Duplication
		if ( isset( $user->data->allowed_mime_types ) ) {
575
			$this->allowed_mime_types[ get_current_blog_id() ][ $user->ID ] = $user->data->allowed_mime_types;
576
			unset( $user->data->allowed_mime_types );
577
		}
578
579
		if ( isset( $user->data->locale ) ) {
580
			$this->users_locale[ get_current_blog_id() ][ $user->ID ] = $user->data->locale;
581
			unset( $user->data->locale );
582
		}
583
		$this->users[ get_current_blog_id() ][ $user->ID ] = $user;
584
	}
585
586
	function delete_user( $user_id ) {
587
		unset( $this->users[ get_current_blog_id() ][ $user_id ] );
588
	}
589
590
591
	function checksum_all() {
592
		$post_meta_checksum = $this->checksum_histogram( 'post_meta', 1 );
593
		$comment_meta_checksum = $this->checksum_histogram( 'comment_meta', 1 );
594
595
		return array(
596
			'posts'    => $this->posts_checksum(),
597
			'comments' => $this->comments_checksum(),
598
			'post_meta'=> reset( $post_meta_checksum ),
599
			'comment_meta'=> reset( $comment_meta_checksum ),
600
		);
601
	}
602
603
	function object_id( $o ) {
604
		return $o->ID;
605
	}
606
607
	function is_comment( $m ) {
608
		return 'comment' === $m->type;
609
	}
610
611
	function is_post( $m ) {
612
		return 'post' === $m->type;
613
	}
614
615
	function comment_id( $o ) {
616
		return $o->comment_ID;
617
	}
618
619
	function meta_id( $o ) {
620
		return $o->meta_id;
621
	}
622
623
	function checksum_histogram( $object_type, $buckets, $start_id = null, $end_id = null, $fields = null ) {
624
		// divide all IDs into the number of buckets
625
		switch ( $object_type ) {
626 View Code Duplication
			case 'posts':
627
				$posts         = $this->get_posts( null, $start_id, $end_id );
628
				$all_ids      = array_map( array( $this, 'object_id' ), $posts );
629
				$id_field      = 'ID';
0 ignored issues
show
Unused Code introduced by
$id_field is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
630
				$get_function  = 'get_post';
631
632
				if ( empty( $fields ) ) {
633
					$fields = Defaults::$default_post_checksum_columns;
634
				}
635
636
				break;
637 View Code Duplication
			case 'post_meta':
638
				$post_meta = array_filter( $this->meta[ get_current_blog_id() ]['post'], array( $this, 'is_post' ) );
639
				$all_ids  = array_values( array_map( array( $this, 'meta_id' ), $post_meta ) );
640
				$id_field     = 'meta_id';
0 ignored issues
show
Unused Code introduced by
$id_field is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
641
				$get_function = 'get_post_meta_by_id';
642
643
				if ( empty( $fields ) ) {
644
					$fields = Defaults::$default_post_meta_checksum_columns;
645
				}
646
				break;
647 View Code Duplication
			case 'comments':
648
				$comments     = $this->get_comments( null, $start_id, $end_id );
649
				$all_ids  = array_map( array( $this, 'comment_id' ), $comments );
650
				$id_field     = 'comment_ID';
0 ignored issues
show
Unused Code introduced by
$id_field is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
651
				$get_function = 'get_comment';
652
653
				if ( empty( $fields ) ) {
654
					$fields = Defaults::$default_comment_checksum_columns;
655
				}
656
				break;
657 View Code Duplication
			case 'comment_meta':
658
				$comment_meta = array_filter( $this->meta[ get_current_blog_id() ]['comment'], array( $this, 'is_comment' ) );
659
				$all_ids  = array_values( array_map( array( $this, 'meta_id' ), $comment_meta ) );
660
				$id_field     = 'meta_id';
0 ignored issues
show
Unused Code introduced by
$id_field is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
661
				$get_function = 'get_comment_meta_by_id';
662
663
				if ( empty( $fields ) ) {
664
					$fields = Defaults::$default_comment_meta_checksum_columns;
665
				}
666
				break;
667
			default:
668
				return false;
669
		}
670
671
		sort( $all_ids );
672
		$bucket_size = (int) ceil( count( $all_ids ) / $buckets );
673
674
		if ( $bucket_size === 0 ) {
675
			return array();
676
		}
677
678
		$id_chunks   = array_chunk( $all_ids, $bucket_size );
679
		$histogram   = array();
680
681
		foreach ( $id_chunks as $id_chunk ) {
682
			$first_id      = $id_chunk[0];
683
			$last_id_array = array_slice( $id_chunk, -1 );
684
			$last_id       = array_pop( $last_id_array );
685
686
			if ( count( $id_chunk ) === 1 ) {
687
				$key = "{$first_id}";
688
			} else {
689
				$key = "{$first_id}-{$last_id}";
690
			}
691
692
			$objects           = array_map( array( $this, $get_function ), $id_chunk );
693
			$value             = $this->calculate_checksum( $objects, null, null, null, $fields );
694
			$histogram[ $key ] = $value;
695
		}
696
697
		return $histogram;
698
	}
699
700
	function cast_to_post( $object ) {
701
		if ( isset( $object->extra ) ) {
702
			$object->extra = (array) $object->extra;
703
		}
704
		$post = new WP_Post( $object );
705
706
		return $post;
707
	}
708
709
	private function calculate_checksum( $array, $id_field = null, $min_id = null, $max_id = null, $fields = null ) {
710
		$this->checksum_fields[ get_current_blog_id() ] = $fields;
711
712
		if ( $id_field && ( $min_id || $max_id ) ) {
713
			$filtered_array = $array;
714
			foreach ( $filtered_array as $index => $object ) {
715
				if ( ( $min_id && $object->{$id_field} < $min_id ) || ( $max_id && $object->{$id_field} > $max_id ) ) {
716
					unset( $filtered_array[ $index ] );
717
				}
718
			}
719
			$array = $filtered_array;
720
		}
721
722
		return (string) array_sum( array_map( array( $this, 'concat_items' ), $array ) );
723
724
	}
725
726
	public function concat_items( $object ) {
727
		$values = array();
728
		foreach ( $this->checksum_fields[ get_current_blog_id() ] as $field ) {
729
			$values[] = preg_replace( '/[^\x20-\x7E]/','', $object->{ $field } );
730
		}
731
		// array('') is the empty value of the salt.
732
		$item_array = array_merge( array(''), $values );
733
734
		return crc32( implode( '#', $item_array ) );
735
	}
736
737
	public function get_term_relationships() {
738
		return $this->term_relationships[ get_current_blog_id() ];
739
	}
740
741
}
742