Completed
Push — update/aag-views ( bf67f2...b39db8 )
by
unknown
24:45 queued 15:23
created

Jetpack_Sync_WP_Replicastore::checksum_histogram()   C

Complexity

Conditions 9
Paths 25

Size

Total Lines 58
Code Lines 40

Duplication

Lines 12
Ratio 20.69 %

Importance

Changes 3
Bugs 0 Features 2
Metric Value
cc 9
eloc 40
c 3
b 0
f 2
nc 25
nop 4
dl 12
loc 58
rs 6.9928

How to fix   Long Method   

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
require_once 'interface.jetpack-sync-replicastore.php';
4
5
/**
6
 * An implementation of iJetpack_Sync_Replicastore which returns data stored in a WordPress.org DB.
7
 * This is useful to compare values in the local WP DB to values in the synced replica store
8
 */
9
class Jetpack_Sync_WP_Replicastore implements iJetpack_Sync_Replicastore {
10
11
12
	public function reset() {
13
		global $wpdb;
14
15
		$wpdb->query( "DELETE FROM $wpdb->posts" );
16
		$wpdb->query( "DELETE FROM $wpdb->comments" );
17
18
		// also need to delete terms from cache
19
		$term_ids = $wpdb->get_col( "SELECT term_id FROM $wpdb->terms" );
20
		foreach ( $term_ids as $term_id ) {
21
			wp_cache_delete( $term_id, 'terms' );
22
		}
23
24
		$wpdb->query( "DELETE FROM $wpdb->terms" );
25
26
		$wpdb->query( "DELETE FROM $wpdb->term_taxonomy" );
27
		$wpdb->query( "DELETE FROM $wpdb->term_relationships" );
28
29
		// callables and constants
30
		$wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE 'jetpack_%'" );
31
		$wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key NOT LIKE '\_%'" );
32
	}
33
34
	function full_sync_start() {
35
		$this->reset();
36
	}
37
38
	function full_sync_end( $checksum ) {
39
		// noop right now
40
	}
41
42 View Code Duplication
	public function post_count( $status = null, $min_id = null, $max_id = null ) {
43
		global $wpdb;
44
45
		$where = "";
0 ignored issues
show
Unused Code introduced by
$where 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...
46
47
		if ( $status ) {
48
			$where = "post_status = '" . esc_sql( $status ) . "'";
49
		} else {
50
			$where = "1=1";
51
		}
52
53
		if ( $min_id != null ) {
54
			$where .= " AND ID >= " . intval( $min_id );
55
		}
56
57
		if ( $max_id != null ) {
58
			$where .= " AND ID <= " . intval( $max_id );
59
		}
60
61
		return $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts WHERE $where" );
62
	}
63
64
	public function get_posts( $status = null, $min_id = null, $max_id = null ) {
65
		$args = array( 'orderby' => 'ID', 'posts_per_page' => -1 );
66
67
		if ( $status ) {
68
			$args['post_status'] = $status;
69
		} else {
70
			$args['post_status'] = 'any';
71
		}
72
73
		return get_posts( $args );
74
	}
75
76
	public function get_post( $id ) {
77
		return get_post( $id );
78
	}
79
80
	public function upsert_post( $post, $silent = false ) {
81
		global $wpdb;
82
83
		// reject the post if it's not a WP_Post
84
		if ( ! $post instanceof WP_Post ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
85
			return;
86
		}
87
88
		$post = $post->to_array();
89
90
		// reject posts without an ID
91
		if ( ! isset( $post['ID'] ) ) {
92
			return;
93
		}
94
95
		$now     = current_time( 'mysql' );
96
		$now_gmt = get_gmt_from_date( $now );
97
98
		$defaults = array(
99
			'ID'                    => 0,
100
			'post_author'           => '0',
101
			'post_content'          => '',
102
			'post_content_filtered' => '',
103
			'post_title'            => '',
104
			'post_name'             => '',
105
			'post_excerpt'          => '',
106
			'post_status'           => 'draft',
107
			'post_type'             => 'post',
108
			'comment_status'        => 'closed',
109
			'comment_count'         => '0',
110
			'ping_status'           => '',
111
			'post_password'         => '',
112
			'to_ping'               => '',
113
			'pinged'                => '',
114
			'post_parent'           => 0,
115
			'menu_order'            => 0,
116
			'guid'                  => '',
117
			'post_date'             => $now,
118
			'post_date_gmt'         => $now_gmt,
119
			'post_modified'         => $now,
120
			'post_modified_gmt'     => $now_gmt,
121
		);
122
123
		$post = array_intersect_key( $post, $defaults );
124
125
		$post = sanitize_post( $post, 'db' );
126
127
		unset( $post['filter'] );
128
129
		$exists = $wpdb->get_var( $wpdb->prepare( "SELECT EXISTS( SELECT 1 FROM $wpdb->posts WHERE ID = %d )", $post['ID'] ) );
130
131
		if ( $exists ) {
132
			$wpdb->update( $wpdb->posts, $post, array( 'ID' => $post['ID'] ) );
133
		} else {
134
			$wpdb->insert( $wpdb->posts, $post );
135
		}
136
137
		clean_post_cache( $post['ID'] );
138
	}
139
140
	public function delete_post( $post_id ) {
141
		wp_delete_post( $post_id, true );
142
	}
143
144
	public function posts_checksum( $min_id = null, $max_id = null ) {
145
		global $wpdb;
146
147
		$where_sql = Jetpack_Sync_Defaults::get_blacklisted_post_types_sql();
148
149
		if ( $min_id !== null ) {
150
			$min_id = intval( $min_id );
151
			$where_sql .= " AND ID >= $min_id";
152
		}
153
154
		if ( $max_id !== null ) {
155
			$max_id = intval( $max_id );
156
			$where_sql .= " AND ID <= $max_id";
157
		}
158
159
		$query = <<<ENDSQL
160
			SELECT CONV(BIT_XOR(CRC32(CONCAT(ID,post_modified))), 10, 16)
161
				FROM $wpdb->posts
162
				WHERE $where_sql
163
ENDSQL;
164
165
		return $wpdb->get_var( $query );
166
	}
167
168 View Code Duplication
	public function comment_count( $status = null, $min_id = null, $max_id = null ) {
169
		global $wpdb;
170
171
		$comment_approved = $this->comment_status_to_approval_value( $status );
172
173
		if ( $comment_approved !== false ) {
174
			$where = "comment_approved = '" . esc_sql( $comment_approved ) . "'";
175
		} else {
176
			$where = "1=1";
177
		}
178
179
		if ( $min_id != null ) {
180
			$where .= " AND comment_ID >= " . intval( $min_id );
181
		}
182
183
		if ( $max_id != null ) {
184
			$where .= " AND comment_ID <= " . intval( $max_id );
185
		}	
186
	
187
		return $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->comments WHERE $where" );
188
	}
189
190
	private function comment_status_to_approval_value( $status ) {
191
		switch ( $status ) {
192
			case 'approve':
193
				return "1";
194
			case 'hold':
195
				return "0";
196
			case 'spam':
197
				return 'spam';
198
			case 'trash':
199
				return 'trash';
200
			case 'any':
201
				return false;
202
			case 'all':
203
				return false;
204
			default:
205
				return false;
206
		}
207
	}
208
209
	public function get_comments( $status = null, $min_id = null, $max_id = null ) {
210
		$args = array( 'orderby' => 'ID', 'status' => 'all' );
211
212
		if ( $status ) {
213
			$args['status'] = $status;
214
		}
215
216
		return get_comments( $args );
217
	}
218
219
	public function get_comment( $id ) {
220
		return WP_Comment::get_instance( $id );
221
	}
222
223
	public function upsert_comment( $comment ) {
224
		global $wpdb, $wp_version;
225
226
		if ( version_compare( $wp_version, '4.4', '<' ) ) {
227
			$comment = (array) $comment;
228
		} else {
229
			// WP 4.4 introduced the WP_Comment Class
230
			$comment = $comment->to_array();
231
		}
232
233
		// filter by fields on comment table
234
		$comment_fields_whitelist = array(
235
			'comment_ID',
236
			'comment_post_ID',
237
			'comment_author',
238
			'comment_author_email',
239
			'comment_author_url',
240
			'comment_author_IP',
241
			'comment_date',
242
			'comment_date_gmt',
243
			'comment_content',
244
			'comment_karma',
245
			'comment_approved',
246
			'comment_agent',
247
			'comment_type',
248
			'comment_parent',
249
			'user_id'
250
		);
251
252
		foreach ( $comment as $key => $value ) {
253
			if ( ! in_array( $key, $comment_fields_whitelist ) ) {
254
				unset( $comment[ $key ] );
255
			}
256
		}
257
258
		$exists = $wpdb->get_var(
259
			$wpdb->prepare(
260
				"SELECT EXISTS( SELECT 1 FROM $wpdb->comments WHERE comment_ID = %d )",
261
				$comment['comment_ID']
262
			)
263
		);
264
265
		if ( $exists ) {
266
			$wpdb->update( $wpdb->comments, $comment, array( 'comment_ID' => $comment['comment_ID'] ) );
267
		} else {
268
			$wpdb->insert( $wpdb->comments, $comment );
269
		}
270
271
		wp_update_comment_count( $comment['comment_post_ID'] );
272
	}
273
274
	public function trash_comment( $comment_id ) {
275
		wp_delete_comment( $comment_id );
276
	}
277
278
	public function delete_comment( $comment_id ) {
279
		wp_delete_comment( $comment_id, true );
280
	}
281
282
	public function spam_comment( $comment_id ) {
283
		wp_spam_comment( $comment_id );
284
	}
285
286
	public function comments_checksum( $min_id = null, $max_id = null ) {
287
		global $wpdb;
288
289
		$where_sql = "1=1";
290
291
		if ( $min_id !== null ) {
292
			$min_id = intval( $min_id );
293
			$where_sql .= " AND comment_ID >= $min_id";
294
		}
295
296
		if ( $max_id !== null ) {
297
			$max_id = intval( $max_id );
298
			$where_sql .= " AND comment_ID <= $max_id";
299
		}
300
301
		$query = <<<ENDSQL
302
			SELECT CONV(BIT_XOR(CRC32(CONCAT(comment_ID,comment_content))), 10, 16) 
303
			  FROM $wpdb->comments
304
			  WHERE $where_sql
305
ENDSQL;
306
307
		return $wpdb->get_var( $query );
308
	}
309
310
	public function options_checksum() {
311
		global $wpdb;
312
313
		$options_whitelist = "'" . implode( "', '", Jetpack_Sync_Defaults::$default_options_whitelist ) . "'";
0 ignored issues
show
Bug introduced by
The property default_options_whitelist cannot be accessed from this context as it is declared private in class Jetpack_Sync_Defaults.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
314
		$query = <<<ENDSQL
315
			SELECT CONV(BIT_XOR(CRC32(CONCAT(option_name,option_value))), 10, 16) FROM $wpdb->options WHERE option_name IN ( $options_whitelist ) 
316
ENDSQL;
317
318
		return $wpdb->get_var( $query );
319
	}
320
	
321
322
	public function update_option( $option, $value ) {
323
		return update_option( $option, $value );
324
	}
325
326
	public function get_option( $option, $default = false ) {
327
		return get_option( $option, $default );
328
	}
329
330
	public function delete_option( $option ) {
331
		return delete_option( $option );
332
	}
333
334
	public function set_theme_support( $theme_support ) {
335
		// noop
336
	}
337
338
	public function current_theme_supports( $feature ) {
339
		return current_theme_supports( $feature );
340
	}
341
342
	public function get_metadata( $type, $object_id, $meta_key = '', $single = false ) {
343
		return get_metadata( $type, $object_id, $meta_key, $single );
344
	}
345
346
	/**
347
	 *
348
	 * Stores remote meta key/values alongside an ID mapping key
349
	 *
350
	 * @param $type
351
	 * @param $object_id
352
	 * @param $meta_key
353
	 * @param $meta_value
354
	 * @param $meta_id
355
	 *
356
	 * @return bool
357
	 */
358
	public function upsert_metadata( $type, $object_id, $meta_key, $meta_value, $meta_id ) {
359
360
		$table = _get_meta_table( $type );
361
		if ( ! $table ) {
362
			return false;
363
		}
364
365
		global $wpdb;
366
367
		$exists = $wpdb->get_var( $wpdb->prepare(
368
			"SELECT EXISTS( SELECT 1 FROM $table WHERE meta_id = %d )",
369
			$meta_id
370
		) );
371
372
		if ( $exists ) {
373
			$wpdb->update( $table, array( 'meta_key'   => $meta_key,
374
			                              'meta_value' => serialize( $meta_value )
375
			), array( 'meta_id' => $meta_id ) );
376
		} else {
377
			$object_id_field = $type . '_id';
378
			$wpdb->insert( $table, array( 'meta_id'        => $meta_id,
379
			                              $object_id_field => $object_id,
380
			                              'meta_key'       => $meta_key,
381
			                              'meta_value'     => serialize( $meta_value )
382
			) );
383
		}
384
385
		wp_cache_delete( $object_id, $type . '_meta' );
386
387
		return true;
388
	}
389
390
	public function delete_metadata( $type, $object_id, $meta_ids ) {
391
		global $wpdb;
392
393
		$table = _get_meta_table( $type );
394
		if ( ! $table ) {
395
			return false;
396
		}
397
398
		foreach ( $meta_ids as $meta_id ) {
399
			$wpdb->query( $wpdb->prepare( "DELETE FROM $table WHERE meta_id = %d", $meta_id ) );
400
		}
401
402
		// if we don't have an object ID what do we do - invalidate ALL meta?
403
		if ( $object_id ) {
404
			wp_cache_delete( $object_id, $type . '_meta' );
405
		}
406
	}
407
408
	// constants
409
	public function get_constant( $constant ) {
410
		$value = get_option( 'jetpack_constant_' . $constant );
411
412
		if ( $value ) {
413
			return $value;
414
		}
415
416
		return null;
417
	}
418
419
	public function set_constant( $constant, $value ) {
420
		update_option( 'jetpack_constant_' . $constant, $value );
421
	}
422
423
	public function get_updates( $type ) {
424
		$all_updates = get_option( 'jetpack_updates', array() );
425
426
		if ( isset( $all_updates[ $type ] ) ) {
427
			return $all_updates[ $type ];
428
		} else {
429
			return null;
430
		}
431
	}
432
433
	public function set_updates( $type, $updates ) {
434
		$all_updates          = get_option( 'jetpack_updates', array() );
435
		$all_updates[ $type ] = $updates;
436
		update_option( 'jetpack_updates', $all_updates );
437
	}
438
439
	// functions
440
	public function get_callable( $name ) {
441
		$value = get_option( 'jetpack_' . $name );
442
443
		if ( $value ) {
444
			return $value;
445
		}
446
447
		return null;
448
	}
449
450
	public function set_callable( $name, $value ) {
451
		update_option( 'jetpack_' . $name, $value );
452
	}
453
454
	// network options
455
	public function get_site_option( $option ) {
456
		return get_option( 'jetpack_network_' . $option );
457
	}
458
459
	public function update_site_option( $option, $value ) {
460
		return update_option( 'jetpack_network_' . $option, $value );
461
	}
462
463
	public function delete_site_option( $option ) {
464
		return delete_option( 'jetpack_network_' . $option );
465
	}
466
467
	// terms
468
	// terms
469
	public function get_terms( $taxonomy ) {
470
		return get_terms( $taxonomy );
471
	}
472
473
	public function get_term( $taxonomy, $term_id, $is_term_id = true ) {
474
		$t = $this->ensure_taxonomy( $taxonomy );
475
		if ( ! $t || is_wp_error( $t ) ) {
476
			return $t;
477
		}
478
479
		return get_term( $term_id, $taxonomy );
480
	}
481
482
	private function ensure_taxonomy( $taxonomy ) {
483
		if ( ! taxonomy_exists( $taxonomy ) ) {
484
			// try re-registering synced taxonomies
485
			$taxonomies = $this->get_callable( 'taxonomies' );
486
			if ( ! isset( $taxonomies[ $taxonomy ] ) ) {
487
				// doesn't exist, or somehow hasn't been synced
488
				return new WP_Error( 'invalid_taxonomy', "The taxonomy '$taxonomy' doesn't exist" );
489
			}
490
			$t = $taxonomies[ $taxonomy ];
491
492
			return register_taxonomy(
493
				$taxonomy,
494
				$t->object_type,
495
				(array) $t
496
			);
497
		}
498
499
		return true;
500
	}
501
502
	public function get_the_terms( $object_id, $taxonomy ) {
503
		return get_the_terms( $object_id, $taxonomy );
504
	}
505
506
	public function update_term( $term_object ) {
507
		$taxonomy = $term_object->taxonomy;
508
		global $wpdb;
509
		$exists = $wpdb->get_var( $wpdb->prepare(
510
			"SELECT EXISTS( SELECT 1 FROM $wpdb->terms WHERE term_id = %d )",
511
			$term_object->term_id
512
		) );
513
		if ( ! $exists ) {
514
			$term_object   = sanitize_term( clone( $term_object ), $taxonomy, 'db' );
515
			$term          = array(
516
				'term_id'    => $term_object->term_id,
517
				'name'       => $term_object->name,
518
				'slug'       => $term_object->slug,
519
				'term_group' => $term_object->term_group,
520
			);
521
			$term_taxonomy = array(
522
				'term_taxonomy_id' => $term_object->term_taxonomy_id,
523
				'term_id'          => $term_object->term_id,
524
				'taxonomy'         => $term_object->taxonomy,
525
				'description'      => $term_object->description,
526
				'parent'           => (int) $term_object->parent,
527
				'count'            => (int) $term_object->count,
528
			);
529
			$wpdb->insert( $wpdb->terms, $term );
530
			$wpdb->insert( $wpdb->term_taxonomy, $term_taxonomy );
531
532
//			clean_term_cache( $term_object->term_id, $taxonomy );
533
534
			return true;
535
		}
536
537
		return wp_update_term( $term_object->term_id, $taxonomy, (array) $term_object );
538
	}
539
540
	public function delete_term( $term_id, $taxonomy ) {
541
		return wp_delete_term( $term_id, $taxonomy );
542
	}
543
544
	public function update_object_terms( $object_id, $taxonomy, $terms, $append ) {
545
		wp_set_object_terms( $object_id, $terms, $taxonomy, $append );
546
	}
547
548
	public function delete_object_terms( $object_id, $tt_ids ) {
549
		global $wpdb;
550
551
		if ( is_array( $tt_ids ) && ! empty( $tt_ids ) ) {
552
			$taxonomies = array();
553
			foreach ( $tt_ids as $tt_id ) {
554
				$term                            = get_term_by( 'term_taxonomy_id', $tt_id );
555
				$taxonomies[ $term->taxonomy ][] = $tt_id;
556
			}
557
			$in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'";
558
559
			/**
560
			 * Fires immediately before an object-term relationship is deleted.
561
			 *
562
			 * @since 2.9.0
563
			 *
564
			 * @param int $object_id Object ID.
565
			 * @param array $tt_ids An array of term taxonomy IDs.
566
			 */
567
			do_action( 'delete_term_relationships', $object_id, $tt_ids );
568
			$deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
569
			foreach ( $taxonomies as $taxonomy => $taxonomy_tt_ids ) {
570
				wp_cache_delete( $object_id, $taxonomy . '_relationships' );
571
				/**
572
				 * Fires immediately after an object-term relationship is deleted.
573
				 *
574
				 * @since 2.9.0
575
				 *
576
				 * @param int $object_id Object ID.
577
				 * @param array $tt_ids An array of term taxonomy IDs.
578
				 */
579
				do_action( 'deleted_term_relationships', $object_id, $taxonomy_tt_ids );
580
				wp_update_term_count( $taxonomy_tt_ids, $taxonomy );
581
			}
582
583
			return (bool) $deleted;
584
		}
585
586
		return false;
587
	}
588
589
	// users
590
	public function user_count() {
591
592
	}
593
594
	public function get_user( $user_id ) {
595
		return WP_User::get_instance( $user_id );
596
	}
597
598
	public function upsert_user( $user ) {
599
		$this->invalid_call();
600
	}
601
602
	public function delete_user( $user_id ) {
603
		$this->invalid_call();
604
	}
605
606
	public function get_allowed_mime_types( $user_id ) {
607
608
	}
609
610
	public function checksum_all() {
611
		return array(
612
			'posts'    => $this->posts_checksum(),
613
			'comments' => $this->comments_checksum(),
614
			'options' => $this->options_checksum(),
615
		);
616
	}
617
618
	function checksum_histogram( $object_type, $buckets, $start_id = null, $end_id = null ) {
619
		global $wpdb;
620
621
		$wpdb->queries = array();
622
623
		switch( $object_type ) {
624 View Code Duplication
			case "posts":
625
				$object_count = $this->post_count( null, $start_id, $end_id );
626
				$object_table = $wpdb->posts;
627
				$id_field = 'ID';
628
				$checksum_method = array( $this, 'posts_checksum' );
629
				break;
630 View Code Duplication
			case "comments":
631
				$object_count = $this->comment_count( null, $start_id, $end_id );
632
				$object_table = $wpdb->comments;
633
				$id_field = 'comment_ID';
634
				$checksum_method = array( $this, 'comments_checksum' );
635
				break;
636
			default:
637
				return false;
638
		}
639
640
		$bucket_size = intval( ceil( $object_count / $buckets ) );
641
		$query_offset = 0;
642
		$histogram = array();
643
644
		$where = "1=1";
645
646
		if ( $start_id ) {
647
			$where .= " AND $id_field >= " . intval( $start_id );
648
		}
649
650
		if ( $end_id ) {
651
			$where .= " AND $id_field <= " . intval( $end_id );
652
		}
653
654
		do {
655
			list( $first_id, $last_id ) = $wpdb->get_row( 
656
				"SELECT MIN($id_field) as min_id, MAX($id_field) as max_id FROM ( SELECT $id_field FROM $object_table WHERE $where ORDER BY $id_field ASC LIMIT $query_offset, $bucket_size ) as ids", 
657
				ARRAY_N 
658
			);
659
660
			// get the checksum value
661
			$value = call_user_func( $checksum_method, $first_id, $last_id );
662
663
			if ( $first_id === null || $last_id === null ) {
664
				break;
665
			} elseif ( $first_id === $last_id ) {
666
				$histogram[$first_id] = $value;
667
			} else {
668
				$histogram["{$first_id}-{$last_id}"] = $value;
669
			}
670
671
			$query_offset += $bucket_size;
672
		} while ( true );
673
674
		return $histogram;
675
	}
676
677
	private function invalid_call() {
678
		$backtrace = debug_backtrace();
679
		$caller    = $backtrace[1]['function'];
680
		throw new Exception( "This function $caller is not supported on the WP Replicastore" );
681
	}
682
}
683