PluginProbe
Image Optimizer – Compress Images and Convert to WebP or AVIF / 1.7.4
Image Optimizer – Compress Images and Convert to WebP or AVIF v1.7.4
1.7.7 1.7.6 1.7.5 1.7.4 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.3.0 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 All 33 releases
image-optimization / vendor / woocommerce / action-scheduler / classes / data-stores / ActionScheduler_HybridStore.php

ActionScheduler_HybridStore.php in Image Optimizer – Compress Images and Convert to WebP or AVIF 1.7.4, at vendor/woocommerce/action-scheduler/classes/data-stores/ActionScheduler_HybridStore.php

461 lines 12.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use ActionScheduler_Store as Store;
4 use Action_Scheduler\Migration\Runner;
5 use Action_Scheduler\Migration\Config;
6 use Action_Scheduler\Migration\Controller;
7
8 /**
9 * Class ActionScheduler_HybridStore
10 *
11 * A wrapper around multiple stores that fetches data from both.
12 *
13 * @since 3.0.0
14 */
15 class ActionScheduler_HybridStore extends Store {
16 const DEMARKATION_OPTION = 'action_scheduler_hybrid_store_demarkation';
17
18 /**
19 * Primary store instance.
20 *
21 * @var ActionScheduler_Store
22 */
23 private $primary_store;
24
25 /**
26 * Secondary store instance.
27 *
28 * @var ActionScheduler_Store
29 */
30 private $secondary_store;
31
32 /**
33 * Runner instance.
34 *
35 * @var Action_Scheduler\Migration\Runner
36 */
37 private $migration_runner;
38
39 /**
40 * The dividing line between IDs of actions created
41 * by the primary and secondary stores.
42 *
43 * @var int
44 *
45 * Methods that accept an action ID will compare the ID against
46 * this to determine which store will contain that ID. In almost
47 * all cases, the ID should come from the primary store, but if
48 * client code is bypassing the API functions and fetching IDs
49 * from elsewhere, then there is a chance that an unmigrated ID
50 * might be requested.
51 */
52 private $demarkation_id = 0;
53
54 /**
55 * ActionScheduler_HybridStore constructor.
56 *
57 * @param Config|null $config Migration config object.
58 */
59 public function __construct( ?Config $config = null ) {
60 $this->demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 );
61 if ( empty( $config ) ) {
62 $config = Controller::instance()->get_migration_config_object();
63 }
64 $this->primary_store = $config->get_destination_store();
65 $this->secondary_store = $config->get_source_store();
66 $this->migration_runner = new Runner( $config );
67 }
68
69 /**
70 * Initialize the table data store tables.
71 *
72 * @codeCoverageIgnore
73 */
74 public function init() {
75 add_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10, 2 );
76 $this->primary_store->init();
77 $this->secondary_store->init();
78 remove_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10 );
79 }
80
81 /**
82 * When the actions table is created, set its autoincrement
83 * value to be one higher than the posts table to ensure that
84 * there are no ID collisions.
85 *
86 * @param string $table_name Table name.
87 * @param string $table_suffix Suffix of table name.
88 *
89 * @return void
90 * @codeCoverageIgnore
91 */
92 public function set_autoincrement( $table_name, $table_suffix ) {
93 if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) {
94 if ( empty( $this->demarkation_id ) ) {
95 $this->demarkation_id = $this->set_demarkation_id();
96 }
97
98 /**
99 * Global.
100 *
101 * @var \wpdb $wpdb
102 */
103 global $wpdb;
104
105 /**
106 * A default date of '0000-00-00 00:00:00' is invalid in MySQL 5.7 when configured with
107 * sql_mode including both STRICT_TRANS_TABLES and NO_ZERO_DATE.
108 */
109 $default_date = new DateTime( 'tomorrow' );
110 $null_action = new ActionScheduler_NullAction();
111 $date_gmt = $this->get_scheduled_date_string( $null_action, $default_date );
112 $date_local = $this->get_scheduled_date_string_local( $null_action, $default_date );
113
114 $row_count = $wpdb->insert(
115 $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
116 array(
117 'action_id' => $this->demarkation_id,
118 'hook' => '',
119 'status' => '',
120 'scheduled_date_gmt' => $date_gmt,
121 'scheduled_date_local' => $date_local,
122 'last_attempt_gmt' => $date_gmt,
123 'last_attempt_local' => $date_local,
124 )
125 );
126 if ( $row_count > 0 ) {
127 $wpdb->delete(
128 $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
129 array( 'action_id' => $this->demarkation_id )
130 );
131 }
132 }
133 }
134
135 /**
136 * Store the demarkation id in WP options.
137 *
138 * @param int $id The ID to set as the demarkation point between the two stores
139 * Leave null to use the next ID from the WP posts table.
140 *
141 * @return int The new ID.
142 *
143 * @codeCoverageIgnore
144 */
145 private function set_demarkation_id( $id = null ) {
146 if ( empty( $id ) ) {
147 /**
148 * Global.
149 *
150 * @var \wpdb $wpdb
151 */
152 global $wpdb;
153
154 $id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" );
155 $id++;
156 }
157 update_option( self::DEMARKATION_OPTION, $id );
158
159 return $id;
160 }
161
162 /**
163 * Find the first matching action from the secondary store.
164 * If it exists, migrate it to the primary store immediately.
165 * After it migrates, the secondary store will logically contain
166 * the next matching action, so return the result thence.
167 *
168 * @param string $hook Action's hook.
169 * @param array $params Action's arguments.
170 *
171 * @return string
172 */
173 public function find_action( $hook, $params = array() ) {
174 $found_unmigrated_action = $this->secondary_store->find_action( $hook, $params );
175 if ( ! empty( $found_unmigrated_action ) ) {
176 $this->migrate( array( $found_unmigrated_action ) );
177 }
178
179 return $this->primary_store->find_action( $hook, $params );
180 }
181
182 /**
183 * Find actions matching the query in the secondary source first.
184 * If any are found, migrate them immediately. Then the secondary
185 * store will contain the canonical results.
186 *
187 * @param array $query Query arguments.
188 * @param string $query_type Whether to select or count the results. Default, select.
189 *
190 * @return int[]
191 */
192 public function query_actions( $query = array(), $query_type = 'select' ) {
193 $found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' );
194 if ( ! empty( $found_unmigrated_actions ) ) {
195 $this->migrate( $found_unmigrated_actions );
196 }
197
198 return $this->primary_store->query_actions( $query, $query_type );
199 }
200
201 /**
202 * Get a count of all actions in the store, grouped by status
203 *
204 * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
205 */
206 public function action_counts() {
207 $unmigrated_actions_count = $this->secondary_store->action_counts();
208 $migrated_actions_count = $this->primary_store->action_counts();
209 $actions_count_by_status = array();
210
211 foreach ( $this->get_status_labels() as $status_key => $status_label ) {
212
213 $count = 0;
214
215 if ( isset( $unmigrated_actions_count[ $status_key ] ) ) {
216 $count += $unmigrated_actions_count[ $status_key ];
217 }
218
219 if ( isset( $migrated_actions_count[ $status_key ] ) ) {
220 $count += $migrated_actions_count[ $status_key ];
221 }
222
223 $actions_count_by_status[ $status_key ] = $count;
224 }
225
226 $actions_count_by_status = array_filter( $actions_count_by_status );
227
228 return $actions_count_by_status;
229 }
230
231 /**
232 * If any actions would have been claimed by the secondary store,
233 * migrate them immediately, then ask the primary store for the
234 * canonical claim.
235 *
236 * @param int $max_actions Maximum number of actions to claim.
237 * @param null|DateTime $before_date Latest timestamp of actions to claim.
238 * @param string[] $hooks Hook of actions to claim.
239 * @param string $group Group of actions to claim.
240 *
241 * @return ActionScheduler_ActionClaim
242 */
243 public function stake_claim( $max_actions = 10, ?DateTime $before_date = null, $hooks = array(), $group = '' ) {
244 $claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
245
246 $claimed_actions = $claim->get_actions();
247 if ( ! empty( $claimed_actions ) ) {
248 $this->migrate( $claimed_actions );
249 }
250
251 $this->secondary_store->release_claim( $claim );
252
253 return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
254 }
255
256 /**
257 * Migrate a list of actions to the table data store.
258 *
259 * @param array $action_ids List of action IDs.
260 */
261 private function migrate( $action_ids ) {
262 $this->migration_runner->migrate_actions( $action_ids );
263 }
264
265 /**
266 * Save an action to the primary store.
267 *
268 * @param ActionScheduler_Action $action Action object to be saved.
269 * @param DateTime|null $date Optional. Schedule date. Default null.
270 *
271 * @return int The action ID
272 */
273 public function save_action( ActionScheduler_Action $action, ?DateTime $date = null ) {
274 return $this->primary_store->save_action( $action, $date );
275 }
276
277 /**
278 * Retrieve an existing action whether migrated or not.
279 *
280 * @param int $action_id Action ID.
281 */
282 public function fetch_action( $action_id ) {
283 $store = $this->get_store_from_action_id( $action_id, true );
284 if ( $store ) {
285 return $store->fetch_action( $action_id );
286 } else {
287 return new ActionScheduler_NullAction();
288 }
289 }
290
291 /**
292 * Cancel an existing action whether migrated or not.
293 *
294 * @param int $action_id Action ID.
295 */
296 public function cancel_action( $action_id ) {
297 $store = $this->get_store_from_action_id( $action_id );
298 if ( $store ) {
299 $store->cancel_action( $action_id );
300 }
301 }
302
303 /**
304 * Delete an existing action whether migrated or not.
305 *
306 * @param int $action_id Action ID.
307 */
308 public function delete_action( $action_id ) {
309 $store = $this->get_store_from_action_id( $action_id );
310 if ( $store ) {
311 $store->delete_action( $action_id );
312 }
313 }
314
315 /**
316 * Get the schedule date an existing action whether migrated or not.
317 *
318 * @param int $action_id Action ID.
319 */
320 public function get_date( $action_id ) {
321 $store = $this->get_store_from_action_id( $action_id );
322 if ( $store ) {
323 return $store->get_date( $action_id );
324 } else {
325 return null;
326 }
327 }
328
329 /**
330 * Mark an existing action as failed whether migrated or not.
331 *
332 * @param int $action_id Action ID.
333 */
334 public function mark_failure( $action_id ) {
335 $store = $this->get_store_from_action_id( $action_id );
336 if ( $store ) {
337 $store->mark_failure( $action_id );
338 }
339 }
340
341 /**
342 * Log the execution of an existing action whether migrated or not.
343 *
344 * @param int $action_id Action ID.
345 */
346 public function log_execution( $action_id ) {
347 $store = $this->get_store_from_action_id( $action_id );
348 if ( $store ) {
349 $store->log_execution( $action_id );
350 }
351 }
352
353 /**
354 * Mark an existing action complete whether migrated or not.
355 *
356 * @param int $action_id Action ID.
357 */
358 public function mark_complete( $action_id ) {
359 $store = $this->get_store_from_action_id( $action_id );
360 if ( $store ) {
361 $store->mark_complete( $action_id );
362 }
363 }
364
365 /**
366 * Get an existing action status whether migrated or not.
367 *
368 * @param int $action_id Action ID.
369 */
370 public function get_status( $action_id ) {
371 $store = $this->get_store_from_action_id( $action_id );
372 if ( $store ) {
373 return $store->get_status( $action_id );
374 }
375 return null;
376 }
377
378 /**
379 * Return which store an action is stored in.
380 *
381 * @param int $action_id ID of the action.
382 * @param bool $primary_first Optional flag indicating search the primary store first.
383 * @return ActionScheduler_Store
384 */
385 protected function get_store_from_action_id( $action_id, $primary_first = false ) {
386 if ( $primary_first ) {
387 $stores = array(
388 $this->primary_store,
389 $this->secondary_store,
390 );
391 } elseif ( $action_id < $this->demarkation_id ) {
392 $stores = array(
393 $this->secondary_store,
394 $this->primary_store,
395 );
396 } else {
397 $stores = array(
398 $this->primary_store,
399 );
400 }
401
402 foreach ( $stores as $store ) {
403 $action = $store->fetch_action( $action_id );
404 if ( ! is_a( $action, 'ActionScheduler_NullAction' ) ) {
405 return $store;
406 }
407 }
408 return null;
409 }
410
411 /**
412 * * * * * * * * * * * * * * * * * * * * * * * * * * *
413 * All claim-related functions should operate solely
414 * on the primary store.
415 * * * * * * * * * * * * * * * * * * * * * * * * * * *
416 */
417
418 /**
419 * Get the claim count from the table data store.
420 */
421 public function get_claim_count() {
422 return $this->primary_store->get_claim_count();
423 }
424
425 /**
426 * Retrieve the claim ID for an action from the table data store.
427 *
428 * @param int $action_id Action ID.
429 */
430 public function get_claim_id( $action_id ) {
431 return $this->primary_store->get_claim_id( $action_id );
432 }
433
434 /**
435 * Release a claim in the table data store.
436 *
437 * @param ActionScheduler_ActionClaim $claim Claim object.
438 */
439 public function release_claim( ActionScheduler_ActionClaim $claim ) {
440 $this->primary_store->release_claim( $claim );
441 }
442
443 /**
444 * Release claims on an action in the table data store.
445 *
446 * @param int $action_id Action ID.
447 */
448 public function unclaim_action( $action_id ) {
449 $this->primary_store->unclaim_action( $action_id );
450 }
451
452 /**
453 * Retrieve a list of action IDs by claim.
454 *
455 * @param int $claim_id Claim ID.
456 */
457 public function find_actions_by_claim_id( $claim_id ) {
458 return $this->primary_store->find_actions_by_claim_id( $claim_id );
459 }
460 }
461