1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* A base abstraction of a sync module. |
4
|
|
|
* |
5
|
|
|
* @package automattic/jetpack-sync |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace Automattic\Jetpack\Sync\Modules; |
9
|
|
|
|
10
|
|
|
use Automattic\Jetpack\Sync\Listener; |
11
|
|
|
use Automattic\Jetpack\Sync\Replicastore; |
12
|
|
|
use Automattic\Jetpack\Sync\Sender; |
13
|
|
|
use Automattic\Jetpack\Sync\Settings; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Basic methods implemented by Jetpack Sync extensions. |
17
|
|
|
* |
18
|
|
|
* @abstract |
19
|
|
|
*/ |
20
|
|
|
abstract class Module { |
21
|
|
|
/** |
22
|
|
|
* Number of items per chunk when grouping objects for performance reasons. |
23
|
|
|
* |
24
|
|
|
* @access public |
25
|
|
|
* |
26
|
|
|
* @var int |
27
|
|
|
*/ |
28
|
|
|
const ARRAY_CHUNK_SIZE = 10; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Sync module name. |
32
|
|
|
* |
33
|
|
|
* @access public |
34
|
|
|
* |
35
|
|
|
* @return string |
36
|
|
|
*/ |
37
|
|
|
abstract public function name(); |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* The id field in the database. |
41
|
|
|
* |
42
|
|
|
* @access public |
43
|
|
|
* |
44
|
|
|
* @return string |
45
|
|
|
*/ |
46
|
|
|
public function id_field() { |
47
|
|
|
return 'ID'; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* The table in the database. |
52
|
|
|
* |
53
|
|
|
* @access public |
54
|
|
|
* |
55
|
|
|
* @return string|bool |
56
|
|
|
*/ |
57
|
|
|
public function table_name() { |
58
|
|
|
return false; |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
// phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Retrieve a sync object by its ID. |
65
|
|
|
* |
66
|
|
|
* @access public |
67
|
|
|
* |
68
|
|
|
* @param string $object_type Type of the sync object. |
69
|
|
|
* @param int $id ID of the sync object. |
70
|
|
|
* @return mixed Object, or false if the object is invalid. |
71
|
|
|
*/ |
72
|
|
|
public function get_object_by_id( $object_type, $id ) { |
73
|
|
|
return false; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Initialize callables action listeners. |
78
|
|
|
* Override these to set up listeners and set/reset data/defaults. |
79
|
|
|
* |
80
|
|
|
* @access public |
81
|
|
|
* |
82
|
|
|
* @param callable $callable Action handler callable. |
83
|
|
|
*/ |
84
|
|
|
public function init_listeners( $callable ) { |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Initialize module action listeners for full sync. |
89
|
|
|
* |
90
|
|
|
* @access public |
91
|
|
|
* |
92
|
|
|
* @param callable $callable Action handler callable. |
93
|
|
|
*/ |
94
|
|
|
public function init_full_sync_listeners( $callable ) { |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Initialize the module in the sender. |
99
|
|
|
* |
100
|
|
|
* @access public |
101
|
|
|
*/ |
102
|
|
|
public function init_before_send() { |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Set module defaults. |
107
|
|
|
* |
108
|
|
|
* @access public |
109
|
|
|
*/ |
110
|
|
|
public function set_defaults() { |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Perform module cleanup. |
115
|
|
|
* Usually triggered when uninstalling the plugin. |
116
|
|
|
* |
117
|
|
|
* @access public |
118
|
|
|
*/ |
119
|
|
|
public function reset_data() { |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Enqueue the module actions for full sync. |
124
|
|
|
* |
125
|
|
|
* @access public |
126
|
|
|
* |
127
|
|
|
* @param array $config Full sync configuration for this sync module. |
128
|
|
|
* @param int $max_items_to_enqueue Maximum number of items to enqueue. |
129
|
|
|
* @param boolean $state True if full sync has finished enqueueing this module, false otherwise. |
130
|
|
|
* @return array Number of actions enqueued, and next module state. |
131
|
|
|
*/ |
132
|
|
|
public function enqueue_full_sync_actions( $config, $max_items_to_enqueue, $state ) { |
133
|
|
|
// In subclasses, return the number of actions enqueued, and next module state (true == done). |
134
|
|
|
return array( null, true ); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Retrieve an estimated number of actions that will be enqueued. |
139
|
|
|
* |
140
|
|
|
* @access public |
141
|
|
|
* |
142
|
|
|
* @param array $config Full sync configuration for this sync module. |
143
|
|
|
* @return array Number of items yet to be enqueued. |
144
|
|
|
*/ |
145
|
|
|
public function estimate_full_sync_actions( $config ) { |
146
|
|
|
// In subclasses, return the number of items yet to be enqueued. |
147
|
|
|
return null; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
// phpcs:enable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Retrieve the actions that will be sent for this module during a full sync. |
154
|
|
|
* |
155
|
|
|
* @access public |
156
|
|
|
* |
157
|
|
|
* @return array Full sync actions of this module. |
158
|
|
|
*/ |
159
|
|
|
public function get_full_sync_actions() { |
160
|
|
|
return array(); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Get the number of actions that we care about. |
165
|
|
|
* |
166
|
|
|
* @access protected |
167
|
|
|
* |
168
|
|
|
* @param array $action_names Action names we're interested in. |
169
|
|
|
* @param array $actions_to_count Unfiltered list of actions we want to count. |
170
|
|
|
* @return array Number of actions that we're interested in. |
171
|
|
|
*/ |
172
|
|
|
protected function count_actions( $action_names, $actions_to_count ) { |
173
|
|
|
return count( array_intersect( $action_names, $actions_to_count ) ); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* Calculate the checksum of one or more values. |
178
|
|
|
* |
179
|
|
|
* @access protected |
180
|
|
|
* |
181
|
|
|
* @param mixed $values Values to calculate checksum for. |
182
|
|
|
* @return int The checksum. |
183
|
|
|
*/ |
184
|
|
|
protected function get_check_sum( $values ) { |
185
|
|
|
return crc32( wp_json_encode( jetpack_json_wrap( $values ) ) ); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Whether a particular checksum in a set of checksums is valid. |
190
|
|
|
* |
191
|
|
|
* @access protected |
192
|
|
|
* |
193
|
|
|
* @param array $sums_to_check Array of checksums. |
194
|
|
|
* @param string $name Name of the checksum. |
195
|
|
|
* @param int $new_sum Checksum to compare against. |
196
|
|
|
* @return boolean Whether the checksum is valid. |
197
|
|
|
*/ |
198
|
|
|
protected function still_valid_checksum( $sums_to_check, $name, $new_sum ) { |
199
|
|
|
if ( isset( $sums_to_check[ $name ] ) && $sums_to_check[ $name ] === $new_sum ) { |
200
|
|
|
return true; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
return false; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* Enqueue all items of a sync type as an action. |
208
|
|
|
* |
209
|
|
|
* @access protected |
210
|
|
|
* |
211
|
|
|
* @param string $action_name Name of the action. |
212
|
|
|
* @param string $table_name Name of the database table. |
213
|
|
|
* @param string $id_field Name of the ID field in the database. |
214
|
|
|
* @param string $where_sql The SQL WHERE clause to filter to the desired items. |
215
|
|
|
* @param int $max_items_to_enqueue Maximum number of items to enqueue in the same time. |
216
|
|
|
* @param boolean $state Whether enqueueing has finished. |
217
|
|
|
* @return array Array, containing the number of chunks and TRUE, indicating enqueueing has finished. |
218
|
|
|
*/ |
219
|
|
|
protected function enqueue_all_ids_as_action( $action_name, $table_name, $id_field, $where_sql, $max_items_to_enqueue, $state ) { |
220
|
|
|
global $wpdb; |
221
|
|
|
|
222
|
|
|
if ( ! $where_sql ) { |
223
|
|
|
$where_sql = '1 = 1'; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
$items_per_page = 1000; |
227
|
|
|
$page = 1; |
228
|
|
|
$chunk_count = 0; |
229
|
|
|
$previous_interval_end = $state ? $state : '~0'; |
230
|
|
|
$listener = Listener::get_instance(); |
231
|
|
|
|
232
|
|
|
// Count down from max_id to min_id so we get newest posts/comments/etc first. |
233
|
|
|
// phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition, WordPress.DB.PreparedSQL.InterpolatedNotPrepared |
234
|
|
|
while ( $ids = $wpdb->get_col( "SELECT {$id_field} FROM {$table_name} WHERE {$where_sql} AND {$id_field} < {$previous_interval_end} ORDER BY {$id_field} DESC LIMIT {$items_per_page}" ) ) { |
235
|
|
|
// Request posts in groups of N for efficiency. |
236
|
|
|
$chunked_ids = array_chunk( $ids, self::ARRAY_CHUNK_SIZE ); |
237
|
|
|
|
238
|
|
|
// If we hit our row limit, process and return. |
239
|
|
|
if ( $chunk_count + count( $chunked_ids ) >= $max_items_to_enqueue ) { |
240
|
|
|
$remaining_items_count = $max_items_to_enqueue - $chunk_count; |
241
|
|
|
$remaining_items = array_slice( $chunked_ids, 0, $remaining_items_count ); |
242
|
|
|
$remaining_items_with_previous_interval_end = $this->get_chunks_with_preceding_end( $remaining_items, $previous_interval_end ); |
243
|
|
|
$listener->bulk_enqueue_full_sync_actions( $action_name, $remaining_items_with_previous_interval_end ); |
244
|
|
|
|
245
|
|
|
$last_chunk = end( $remaining_items ); |
246
|
|
|
return array( $remaining_items_count + $chunk_count, end( $last_chunk ) ); |
247
|
|
|
} |
248
|
|
|
$chunked_ids_with_previous_end = $this->get_chunks_with_preceding_end( $chunked_ids, $previous_interval_end ); |
249
|
|
|
|
250
|
|
|
$listener->bulk_enqueue_full_sync_actions( $action_name, $chunked_ids_with_previous_end ); |
251
|
|
|
|
252
|
|
|
$chunk_count += count( $chunked_ids ); |
253
|
|
|
$page++; |
254
|
|
|
// The $ids are ordered in descending order. |
255
|
|
|
$previous_interval_end = end( $ids ); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
if ( $wpdb->last_error ) { |
259
|
|
|
// return the values that were passed in so all these chunks get retried. |
260
|
|
|
return array( $max_items_to_enqueue, $state ); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
return array( $chunk_count, true ); |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* Given the Module Full Sync Configuration and Status return the next chunk of items to send. |
268
|
|
|
* |
269
|
|
|
* @param array $config This module Full Sync configuration. |
270
|
|
|
* @param array $status This module Full Sync status. |
271
|
|
|
* @param int $chunk_size Chunk size. |
272
|
|
|
* |
273
|
|
|
* @return array|object|null |
274
|
|
|
*/ |
275
|
|
|
public function get_next_chunk( $config, $status, $chunk_size ) { |
276
|
|
|
global $wpdb; |
277
|
|
|
return $wpdb->get_col( |
278
|
|
|
<<<SQL |
279
|
|
|
SELECT {$this->id_field()} |
280
|
|
|
FROM {$wpdb->{$this->table_name()}} |
281
|
|
|
WHERE {$this->get_where_sql( $config )} |
282
|
|
|
AND {$this->id_field()} < {$status['last_sent']} |
283
|
|
|
ORDER BY {$this->id_field()} |
284
|
|
|
DESC LIMIT {$chunk_size} |
285
|
|
|
SQL |
286
|
|
|
); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* Return the initial last sent object. |
291
|
|
|
* |
292
|
|
|
* @return string|array initial status. |
293
|
|
|
*/ |
294
|
|
|
public function get_initial_last_sent() { |
295
|
|
|
return '~0'; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* Immediately send all items of a sync type as an action. |
300
|
|
|
* |
301
|
|
|
* @access protected |
302
|
|
|
* |
303
|
|
|
* @param string $config Full sync configuration for this module. |
304
|
|
|
* @param array $status the current module full sync status. |
305
|
|
|
* @param float $send_until timestamp until we want this request to send full sync events. |
306
|
|
|
* |
307
|
|
|
* @return array Status, the module full sync status updated. |
308
|
|
|
*/ |
309
|
|
|
public function send_full_sync_actions( $config, $status, $send_until ) { |
310
|
|
|
global $wpdb; |
311
|
|
|
|
312
|
|
|
if ( empty( $status['last_sent'] ) ) { |
313
|
|
|
$status['last_sent'] = $this->get_initial_last_sent(); |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
$limits = Settings::get_setting( 'full_sync_limits' )[ $this->name() ]; |
317
|
|
|
|
318
|
|
|
$chunks_sent = 0; |
319
|
|
|
// phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition |
320
|
|
|
while ( $objects = $this->get_next_chunk( $config, $status, $limits['chunk_size'] ) ) { |
|
|
|
|
321
|
|
|
if ( $chunks_sent++ === $limits['max_chunks'] || microtime( true ) >= $send_until ) { |
322
|
|
|
return $status; |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
$result = $this->send_action( 'jetpack_full_sync_' . $this->name(), array( $objects, $status['last_sent'] ) ); |
326
|
|
|
|
327
|
|
|
if ( is_wp_error( $result ) || $wpdb->last_error ) { |
328
|
|
|
return $status; |
329
|
|
|
} |
330
|
|
|
// The $ids are ordered in descending order. |
331
|
|
|
$status['last_sent'] = end( $objects ); |
332
|
|
|
$status['sent'] += count( $objects ); |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
if ( ! $wpdb->last_error ) { |
336
|
|
|
$status['finished'] = true; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
return $status; |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
|
343
|
|
|
/** |
344
|
|
|
* Immediately sends a single item without firing or enqueuing it |
345
|
|
|
* |
346
|
|
|
* @param string $action_name The action. |
347
|
|
|
* @param array $data The data associated with the action. |
|
|
|
|
348
|
|
|
*/ |
349
|
|
|
public function send_action( $action_name, $data = null ) { |
350
|
|
|
$sender = Sender::get_instance(); |
351
|
|
|
return $sender->send_action( $action_name, $data ); |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
/** |
355
|
|
|
* Retrieve chunk IDs with previous interval end. |
356
|
|
|
* |
357
|
|
|
* @access protected |
358
|
|
|
* |
359
|
|
|
* @param array $chunks All remaining items. |
360
|
|
|
* @param int $previous_interval_end The last item from the previous interval. |
361
|
|
|
* @return array Chunk IDs with the previous interval end. |
362
|
|
|
*/ |
363
|
|
|
protected function get_chunks_with_preceding_end( $chunks, $previous_interval_end ) { |
364
|
|
|
$chunks_with_ends = array(); |
365
|
|
|
foreach ( $chunks as $chunk ) { |
366
|
|
|
$chunks_with_ends[] = array( |
367
|
|
|
'ids' => $chunk, |
368
|
|
|
'previous_end' => $previous_interval_end, |
369
|
|
|
); |
370
|
|
|
// Chunks are ordered in descending order. |
371
|
|
|
$previous_interval_end = end( $chunk ); |
372
|
|
|
} |
373
|
|
|
return $chunks_with_ends; |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
/** |
377
|
|
|
* Get metadata of a particular object type within the designated meta key whitelist. |
378
|
|
|
* |
379
|
|
|
* @access protected |
380
|
|
|
* |
381
|
|
|
* @todo Refactor to use $wpdb->prepare() on the SQL query. |
382
|
|
|
* |
383
|
|
|
* @param array $ids Object IDs. |
384
|
|
|
* @param string $meta_type Meta type. |
385
|
|
|
* @param array $meta_key_whitelist Meta key whitelist. |
386
|
|
|
* @return array Unserialized meta values. |
387
|
|
|
*/ |
388
|
|
|
protected function get_metadata( $ids, $meta_type, $meta_key_whitelist ) { |
389
|
|
|
global $wpdb; |
390
|
|
|
$table = _get_meta_table( $meta_type ); |
391
|
|
|
$id = $meta_type . '_id'; |
392
|
|
|
if ( ! $table ) { |
393
|
|
|
return array(); |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
$private_meta_whitelist_sql = "'" . implode( "','", array_map( 'esc_sql', $meta_key_whitelist ) ) . "'"; |
397
|
|
|
|
398
|
|
|
return array_map( |
399
|
|
|
array( $this, 'unserialize_meta' ), |
400
|
|
|
$wpdb->get_results( |
401
|
|
|
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared |
402
|
|
|
"SELECT $id, meta_key, meta_value, meta_id FROM $table WHERE $id IN ( " . implode( ',', wp_parse_id_list( $ids ) ) . ' )' . |
403
|
|
|
" AND meta_key IN ( $private_meta_whitelist_sql ) ", |
404
|
|
|
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared |
405
|
|
|
OBJECT |
406
|
|
|
) |
407
|
|
|
); |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
/** |
411
|
|
|
* Initialize listeners for the particular meta type. |
412
|
|
|
* |
413
|
|
|
* @access public |
414
|
|
|
* |
415
|
|
|
* @param string $meta_type Meta type. |
416
|
|
|
* @param callable $callable Action handler callable. |
417
|
|
|
*/ |
418
|
|
|
public function init_listeners_for_meta_type( $meta_type, $callable ) { |
419
|
|
|
add_action( "added_{$meta_type}_meta", $callable, 10, 4 ); |
420
|
|
|
add_action( "updated_{$meta_type}_meta", $callable, 10, 4 ); |
421
|
|
|
add_action( "deleted_{$meta_type}_meta", $callable, 10, 4 ); |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
/** |
425
|
|
|
* Initialize meta whitelist handler for the particular meta type. |
426
|
|
|
* |
427
|
|
|
* @access public |
428
|
|
|
* |
429
|
|
|
* @param string $meta_type Meta type. |
430
|
|
|
* @param callable $whitelist_handler Action handler callable. |
431
|
|
|
*/ |
432
|
|
|
public function init_meta_whitelist_handler( $meta_type, $whitelist_handler ) { |
433
|
|
|
add_filter( "jetpack_sync_before_enqueue_added_{$meta_type}_meta", $whitelist_handler ); |
434
|
|
|
add_filter( "jetpack_sync_before_enqueue_updated_{$meta_type}_meta", $whitelist_handler ); |
435
|
|
|
add_filter( "jetpack_sync_before_enqueue_deleted_{$meta_type}_meta", $whitelist_handler ); |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
/** |
439
|
|
|
* Retrieve the term relationships for the specified object IDs. |
440
|
|
|
* |
441
|
|
|
* @access protected |
442
|
|
|
* |
443
|
|
|
* @todo This feels too specific to be in the abstract sync Module class. Move it? |
444
|
|
|
* |
445
|
|
|
* @param array $ids Object IDs. |
446
|
|
|
* @return array Term relationships - object ID and term taxonomy ID pairs. |
447
|
|
|
*/ |
448
|
|
|
protected function get_term_relationships( $ids ) { |
449
|
|
|
global $wpdb; |
450
|
|
|
|
451
|
|
|
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared |
452
|
|
|
return $wpdb->get_results( "SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships WHERE object_id IN ( " . implode( ',', wp_parse_id_list( $ids ) ) . ' )', OBJECT ); |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
/** |
456
|
|
|
* Unserialize the value of a meta object, if necessary. |
457
|
|
|
* |
458
|
|
|
* @access public |
459
|
|
|
* |
460
|
|
|
* @param object $meta Meta object. |
461
|
|
|
* @return object Meta object with possibly unserialized value. |
462
|
|
|
*/ |
463
|
|
|
public function unserialize_meta( $meta ) { |
464
|
|
|
$meta->meta_value = maybe_unserialize( $meta->meta_value ); |
465
|
|
|
return $meta; |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
/** |
469
|
|
|
* Retrieve a set of objects by their IDs. |
470
|
|
|
* |
471
|
|
|
* @access public |
472
|
|
|
* |
473
|
|
|
* @param string $object_type Object type. |
474
|
|
|
* @param array $ids Object IDs. |
475
|
|
|
* @return array Array of objects. |
476
|
|
|
*/ |
477
|
|
|
public function get_objects_by_id( $object_type, $ids ) { |
478
|
|
|
if ( empty( $ids ) || empty( $object_type ) ) { |
479
|
|
|
return array(); |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
$objects = array(); |
483
|
|
|
foreach ( (array) $ids as $id ) { |
484
|
|
|
$object = $this->get_object_by_id( $object_type, $id ); |
485
|
|
|
|
486
|
|
|
// Only add object if we have the object. |
487
|
|
|
if ( $object ) { |
488
|
|
|
$objects[ $id ] = $object; |
489
|
|
|
} |
490
|
|
|
} |
491
|
|
|
|
492
|
|
|
return $objects; |
493
|
|
|
} |
494
|
|
|
|
495
|
|
|
/** |
496
|
|
|
* Gets a list of minimum and maximum object ids for each batch based on the given batch size. |
497
|
|
|
* |
498
|
|
|
* @access public |
499
|
|
|
* |
500
|
|
|
* @param int $batch_size The batch size for objects. |
501
|
|
|
* @param string|bool $where_sql The sql where clause minus 'WHERE', or false if no where clause is needed. |
502
|
|
|
* |
503
|
|
|
* @return array|bool An array of min and max ids for each batch. FALSE if no table can be found. |
504
|
|
|
*/ |
505
|
|
|
public function get_min_max_object_ids_for_batches( $batch_size, $where_sql = false ) { |
506
|
|
|
global $wpdb; |
507
|
|
|
|
508
|
|
|
if ( ! $this->table_name() ) { |
509
|
|
|
return false; |
510
|
|
|
} |
511
|
|
|
|
512
|
|
|
$results = array(); |
513
|
|
|
$table = $wpdb->{$this->table_name()}; |
514
|
|
|
$current_max = 0; |
515
|
|
|
$current_min = 1; |
516
|
|
|
$id_field = $this->id_field(); |
517
|
|
|
$replicastore = new Replicastore(); |
518
|
|
|
|
519
|
|
|
$total = $replicastore->get_min_max_object_id( |
520
|
|
|
$id_field, |
521
|
|
|
$table, |
522
|
|
|
$where_sql, |
|
|
|
|
523
|
|
|
false |
|
|
|
|
524
|
|
|
); |
525
|
|
|
|
526
|
|
|
while ( $total->max > $current_max ) { |
527
|
|
|
$where = $where_sql ? |
528
|
|
|
$where_sql . " AND $id_field > $current_max" : |
529
|
|
|
"$id_field > $current_max"; |
530
|
|
|
$result = $replicastore->get_min_max_object_id( |
531
|
|
|
$id_field, |
532
|
|
|
$table, |
533
|
|
|
$where, |
534
|
|
|
$batch_size |
535
|
|
|
); |
536
|
|
|
if ( empty( $result->min ) && empty( $result->max ) ) { |
537
|
|
|
// Our query produced no min and max. We can assume the min from the previous query, |
538
|
|
|
// and the total max we found in the initial query. |
539
|
|
|
$current_max = (int) $total->max; |
540
|
|
|
$result = (object) array( |
541
|
|
|
'min' => $current_min, |
542
|
|
|
'max' => $current_max, |
543
|
|
|
); |
544
|
|
|
} else { |
545
|
|
|
$current_min = (int) $result->min; |
546
|
|
|
$current_max = (int) $result->max; |
547
|
|
|
} |
548
|
|
|
$results[] = $result; |
549
|
|
|
} |
550
|
|
|
|
551
|
|
|
return $results; |
552
|
|
|
} |
553
|
|
|
|
554
|
|
|
/** |
555
|
|
|
* Return Total number of objects. |
556
|
|
|
* |
557
|
|
|
* @param array $config Full Sync config. |
558
|
|
|
* |
559
|
|
|
* @return int total |
560
|
|
|
*/ |
561
|
|
|
public function total( $config ) { |
562
|
|
|
global $wpdb; |
563
|
|
|
$table = $wpdb->{$this->table_name()}; |
564
|
|
|
$where = $this->get_where_sql( $config ); |
565
|
|
|
|
566
|
|
|
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared |
567
|
|
|
return $wpdb->get_var( "SELECT COUNT(*) FROM $table WHERE $where" ); |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
/** |
571
|
|
|
* Retrieve the WHERE SQL clause based on the module config. |
572
|
|
|
* |
573
|
|
|
* @access public |
574
|
|
|
* |
575
|
|
|
* @param array $config Full sync configuration for this sync module. |
576
|
|
|
* @return string WHERE SQL clause, or `null` if no comments are specified in the module config. |
577
|
|
|
*/ |
578
|
|
|
public function get_where_sql( $config ) { |
579
|
|
|
return '1=1'; |
580
|
|
|
} |
581
|
|
|
|
582
|
|
|
} |
583
|
|
|
|
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: