Passed
Pull Request — master (#284)
by Brian
06:18
created
includes/libraries/action-scheduler/action-scheduler.php 1 patch
Indentation   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -27,27 +27,27 @@
 block discarded – undo
27 27
 
28 28
 if ( ! function_exists( 'action_scheduler_register_3_dot_1_dot_4' ) ) {
29 29
 
30
-	if ( ! class_exists( 'ActionScheduler_Versions' ) ) {
31
-		require_once( 'classes/ActionScheduler_Versions.php' );
32
-		add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 );
33
-	}
30
+    if ( ! class_exists( 'ActionScheduler_Versions' ) ) {
31
+        require_once( 'classes/ActionScheduler_Versions.php' );
32
+        add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 );
33
+    }
34 34
 
35
-	add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_1_dot_4', 0, 0 );
35
+    add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_1_dot_4', 0, 0 );
36 36
 
37
-	function action_scheduler_register_3_dot_1_dot_4() {
38
-		$versions = ActionScheduler_Versions::instance();
39
-		$versions->register( '3.1.4', 'action_scheduler_initialize_3_dot_1_dot_4' );
40
-	}
37
+    function action_scheduler_register_3_dot_1_dot_4() {
38
+        $versions = ActionScheduler_Versions::instance();
39
+        $versions->register( '3.1.4', 'action_scheduler_initialize_3_dot_1_dot_4' );
40
+    }
41 41
 
42
-	function action_scheduler_initialize_3_dot_1_dot_4() {
43
-		require_once( 'classes/abstracts/ActionScheduler.php' );
44
-		ActionScheduler::init( __FILE__ );
45
-	}
42
+    function action_scheduler_initialize_3_dot_1_dot_4() {
43
+        require_once( 'classes/abstracts/ActionScheduler.php' );
44
+        ActionScheduler::init( __FILE__ );
45
+    }
46 46
 
47
-	// Support usage in themes - load this version if no plugin has loaded a version yet.
48
-	if ( did_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler' ) ) {
49
-		action_scheduler_initialize_3_dot_1_dot_4();
50
-		do_action( 'action_scheduler_pre_theme_init' );
51
-		ActionScheduler_Versions::initialize_latest_version();
52
-	}
47
+    // Support usage in themes - load this version if no plugin has loaded a version yet.
48
+    if ( did_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler' ) ) {
49
+        action_scheduler_initialize_3_dot_1_dot_4();
50
+        do_action( 'action_scheduler_pre_theme_init' );
51
+        ActionScheduler_Versions::initialize_latest_version();
52
+    }
53 53
 }
Please login to merge, or discard this patch.
libraries/action-scheduler/classes/ActionScheduler_FatalErrorMonitor.php 1 patch
Indentation   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -4,52 +4,52 @@
 block discarded – undo
4 4
  * Class ActionScheduler_FatalErrorMonitor
5 5
  */
6 6
 class ActionScheduler_FatalErrorMonitor {
7
-	/** @var ActionScheduler_ActionClaim */
8
-	private $claim = NULL;
9
-	/** @var ActionScheduler_Store */
10
-	private $store = NULL;
11
-	private $action_id = 0;
7
+    /** @var ActionScheduler_ActionClaim */
8
+    private $claim = NULL;
9
+    /** @var ActionScheduler_Store */
10
+    private $store = NULL;
11
+    private $action_id = 0;
12 12
 
13
-	public function __construct( ActionScheduler_Store $store ) {
14
-		$this->store = $store;
15
-	}
13
+    public function __construct( ActionScheduler_Store $store ) {
14
+        $this->store = $store;
15
+    }
16 16
 
17
-	public function attach( ActionScheduler_ActionClaim $claim ) {
18
-		$this->claim = $claim;
19
-		add_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
20
-		add_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0, 1 );
21
-		add_action( 'action_scheduler_after_execute',  array( $this, 'untrack_action' ), 0, 0 );
22
-		add_action( 'action_scheduler_execution_ignored',  array( $this, 'untrack_action' ), 0, 0 );
23
-		add_action( 'action_scheduler_failed_execution',  array( $this, 'untrack_action' ), 0, 0 );
24
-	}
17
+    public function attach( ActionScheduler_ActionClaim $claim ) {
18
+        $this->claim = $claim;
19
+        add_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
20
+        add_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0, 1 );
21
+        add_action( 'action_scheduler_after_execute',  array( $this, 'untrack_action' ), 0, 0 );
22
+        add_action( 'action_scheduler_execution_ignored',  array( $this, 'untrack_action' ), 0, 0 );
23
+        add_action( 'action_scheduler_failed_execution',  array( $this, 'untrack_action' ), 0, 0 );
24
+    }
25 25
 
26
-	public function detach() {
27
-		$this->claim = NULL;
28
-		$this->untrack_action();
29
-		remove_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
30
-		remove_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0 );
31
-		remove_action( 'action_scheduler_after_execute',  array( $this, 'untrack_action' ), 0 );
32
-		remove_action( 'action_scheduler_execution_ignored',  array( $this, 'untrack_action' ), 0 );
33
-		remove_action( 'action_scheduler_failed_execution',  array( $this, 'untrack_action' ), 0 );
34
-	}
26
+    public function detach() {
27
+        $this->claim = NULL;
28
+        $this->untrack_action();
29
+        remove_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
30
+        remove_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0 );
31
+        remove_action( 'action_scheduler_after_execute',  array( $this, 'untrack_action' ), 0 );
32
+        remove_action( 'action_scheduler_execution_ignored',  array( $this, 'untrack_action' ), 0 );
33
+        remove_action( 'action_scheduler_failed_execution',  array( $this, 'untrack_action' ), 0 );
34
+    }
35 35
 
36
-	public function track_current_action( $action_id ) {
37
-		$this->action_id = $action_id;
38
-	}
36
+    public function track_current_action( $action_id ) {
37
+        $this->action_id = $action_id;
38
+    }
39 39
 
40
-	public function untrack_action() {
41
-		$this->action_id = 0;
42
-	}
40
+    public function untrack_action() {
41
+        $this->action_id = 0;
42
+    }
43 43
 
44
-	public function handle_unexpected_shutdown() {
45
-		if ( $error = error_get_last() ) {
46
-			if ( in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ) ) ) {
47
-				if ( !empty($this->action_id) ) {
48
-					$this->store->mark_failure( $this->action_id );
49
-					do_action( 'action_scheduler_unexpected_shutdown', $this->action_id, $error );
50
-				}
51
-			}
52
-			$this->store->release_claim( $this->claim );
53
-		}
54
-	}
44
+    public function handle_unexpected_shutdown() {
45
+        if ( $error = error_get_last() ) {
46
+            if ( in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ) ) ) {
47
+                if ( !empty($this->action_id) ) {
48
+                    $this->store->mark_failure( $this->action_id );
49
+                    do_action( 'action_scheduler_unexpected_shutdown', $this->action_id, $error );
50
+                }
51
+            }
52
+            $this->store->release_claim( $this->claim );
53
+        }
54
+    }
55 55
 }
Please login to merge, or discard this patch.
libraries/action-scheduler/classes/ActionScheduler_wcSystemStatus.php 1 patch
Indentation   +120 added lines, -120 removed lines patch added patch discarded remove patch
@@ -5,95 +5,95 @@  discard block
 block discarded – undo
5 5
  */
6 6
 class ActionScheduler_wcSystemStatus {
7 7
 
8
-	/**
9
-	 * The active data stores
10
-	 *
11
-	 * @var ActionScheduler_Store
12
-	 */
13
-	protected $store;
14
-
15
-	function __construct( $store ) {
16
-		$this->store = $store;
17
-	}
18
-
19
-	/**
20
-	 * Display action data, including number of actions grouped by status and the oldest & newest action in each status.
21
-	 *
22
-	 * Helpful to identify issues, like a clogged queue.
23
-	 */
24
-	public function render() {
25
-		$action_counts     = $this->store->action_counts();
26
-		$status_labels     = $this->store->get_status_labels();
27
-		$oldest_and_newest = $this->get_oldest_and_newest( array_keys( $status_labels ) );
28
-
29
-		$this->get_template( $status_labels, $action_counts, $oldest_and_newest );
30
-	}
31
-
32
-	/**
33
-	 * Get oldest and newest scheduled dates for a given set of statuses.
34
-	 *
35
-	 * @param array $status_keys Set of statuses to find oldest & newest action for.
36
-	 * @return array
37
-	 */
38
-	protected function get_oldest_and_newest( $status_keys ) {
39
-
40
-		$oldest_and_newest = array();
41
-
42
-		foreach ( $status_keys as $status ) {
43
-			$oldest_and_newest[ $status ] = array(
44
-				'oldest' => '–',
45
-				'newest' => '–',
46
-			);
47
-
48
-			if ( 'in-progress' === $status ) {
49
-				continue;
50
-			}
51
-
52
-			$oldest_and_newest[ $status ]['oldest'] = $this->get_action_status_date( $status, 'oldest' );
53
-			$oldest_and_newest[ $status ]['newest'] = $this->get_action_status_date( $status, 'newest' );
54
-		}
55
-
56
-		return $oldest_and_newest;
57
-	}
58
-
59
-	/**
60
-	 * Get oldest or newest scheduled date for a given status.
61
-	 *
62
-	 * @param string $status Action status label/name string.
63
-	 * @param string $date_type Oldest or Newest.
64
-	 * @return DateTime
65
-	 */
66
-	protected function get_action_status_date( $status, $date_type = 'oldest' ) {
67
-
68
-		$order = 'oldest' === $date_type ? 'ASC' : 'DESC';
69
-
70
-		$action = $this->store->query_actions( array(
71
-			'claimed'  => false,
72
-			'status'   => $status,
73
-			'per_page' => 1,
74
-			'order'    => $order,
75
-		) );
76
-
77
-		if ( ! empty( $action ) ) {
78
-			$date_object = $this->store->get_date( $action[0] );
79
-			$action_date = $date_object->format( 'Y-m-d H:i:s O' );
80
-		} else {
81
-			$action_date = '–';
82
-		}
83
-
84
-		return $action_date;
85
-	}
86
-
87
-	/**
88
-	 * Get oldest or newest scheduled date for a given status.
89
-	 *
90
-	 * @param array $status_labels Set of statuses to find oldest & newest action for.
91
-	 * @param array $action_counts Number of actions grouped by status.
92
-	 * @param array $oldest_and_newest Date of the oldest and newest action with each status.
93
-	 */
94
-	protected function get_template( $status_labels, $action_counts, $oldest_and_newest ) {
95
-		$as_version = ActionScheduler_Versions::instance()->latest_version();
96
-		?>
8
+    /**
9
+     * The active data stores
10
+     *
11
+     * @var ActionScheduler_Store
12
+     */
13
+    protected $store;
14
+
15
+    function __construct( $store ) {
16
+        $this->store = $store;
17
+    }
18
+
19
+    /**
20
+     * Display action data, including number of actions grouped by status and the oldest & newest action in each status.
21
+     *
22
+     * Helpful to identify issues, like a clogged queue.
23
+     */
24
+    public function render() {
25
+        $action_counts     = $this->store->action_counts();
26
+        $status_labels     = $this->store->get_status_labels();
27
+        $oldest_and_newest = $this->get_oldest_and_newest( array_keys( $status_labels ) );
28
+
29
+        $this->get_template( $status_labels, $action_counts, $oldest_and_newest );
30
+    }
31
+
32
+    /**
33
+     * Get oldest and newest scheduled dates for a given set of statuses.
34
+     *
35
+     * @param array $status_keys Set of statuses to find oldest & newest action for.
36
+     * @return array
37
+     */
38
+    protected function get_oldest_and_newest( $status_keys ) {
39
+
40
+        $oldest_and_newest = array();
41
+
42
+        foreach ( $status_keys as $status ) {
43
+            $oldest_and_newest[ $status ] = array(
44
+                'oldest' => '–',
45
+                'newest' => '–',
46
+            );
47
+
48
+            if ( 'in-progress' === $status ) {
49
+                continue;
50
+            }
51
+
52
+            $oldest_and_newest[ $status ]['oldest'] = $this->get_action_status_date( $status, 'oldest' );
53
+            $oldest_and_newest[ $status ]['newest'] = $this->get_action_status_date( $status, 'newest' );
54
+        }
55
+
56
+        return $oldest_and_newest;
57
+    }
58
+
59
+    /**
60
+     * Get oldest or newest scheduled date for a given status.
61
+     *
62
+     * @param string $status Action status label/name string.
63
+     * @param string $date_type Oldest or Newest.
64
+     * @return DateTime
65
+     */
66
+    protected function get_action_status_date( $status, $date_type = 'oldest' ) {
67
+
68
+        $order = 'oldest' === $date_type ? 'ASC' : 'DESC';
69
+
70
+        $action = $this->store->query_actions( array(
71
+            'claimed'  => false,
72
+            'status'   => $status,
73
+            'per_page' => 1,
74
+            'order'    => $order,
75
+        ) );
76
+
77
+        if ( ! empty( $action ) ) {
78
+            $date_object = $this->store->get_date( $action[0] );
79
+            $action_date = $date_object->format( 'Y-m-d H:i:s O' );
80
+        } else {
81
+            $action_date = '–';
82
+        }
83
+
84
+        return $action_date;
85
+    }
86
+
87
+    /**
88
+     * Get oldest or newest scheduled date for a given status.
89
+     *
90
+     * @param array $status_labels Set of statuses to find oldest & newest action for.
91
+     * @param array $action_counts Number of actions grouped by status.
92
+     * @param array $oldest_and_newest Date of the oldest and newest action with each status.
93
+     */
94
+    protected function get_template( $status_labels, $action_counts, $oldest_and_newest ) {
95
+        $as_version = ActionScheduler_Versions::instance()->latest_version();
96
+        ?>
97 97
 
98 98
 		<table class="wc_status_table widefat" cellspacing="0">
99 99
 			<thead>
@@ -114,39 +114,39 @@  discard block
 block discarded – undo
114 114
 			</thead>
115 115
 			<tbody>
116 116
 				<?php
117
-				foreach ( $action_counts as $status => $count ) {
118
-					// WC uses the 3rd column for export, so we need to display more data in that (hidden when viewed as part of the table) and add an empty 2nd column.
119
-					printf(
120
-						'<tr><td>%1$s</td><td>&nbsp;</td><td>%2$s<span style="display: none;">, Oldest: %3$s, Newest: %4$s</span></td><td>%3$s</td><td>%4$s</td></tr>',
121
-						esc_html( $status_labels[ $status ] ),
122
-						number_format_i18n( $count ),
123
-						$oldest_and_newest[ $status ]['oldest'],
124
-						$oldest_and_newest[ $status ]['newest']
125
-					);
126
-				}
127
-				?>
117
+                foreach ( $action_counts as $status => $count ) {
118
+                    // WC uses the 3rd column for export, so we need to display more data in that (hidden when viewed as part of the table) and add an empty 2nd column.
119
+                    printf(
120
+                        '<tr><td>%1$s</td><td>&nbsp;</td><td>%2$s<span style="display: none;">, Oldest: %3$s, Newest: %4$s</span></td><td>%3$s</td><td>%4$s</td></tr>',
121
+                        esc_html( $status_labels[ $status ] ),
122
+                        number_format_i18n( $count ),
123
+                        $oldest_and_newest[ $status ]['oldest'],
124
+                        $oldest_and_newest[ $status ]['newest']
125
+                    );
126
+                }
127
+                ?>
128 128
 			</tbody>
129 129
 		</table>
130 130
 
131 131
 		<?php
132
-	}
133
-
134
-	/**
135
-	 * is triggered when invoking inaccessible methods in an object context.
136
-	 *
137
-	 * @param string $name
138
-	 * @param array  $arguments
139
-	 *
140
-	 * @return mixed
141
-	 * @link https://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
142
-	 */
143
-	public function __call( $name, $arguments ) {
144
-		switch ( $name ) {
145
-			case 'print':
146
-				_deprecated_function( __CLASS__ . '::print()', '2.2.4', __CLASS__ . '::render()' );
147
-				return call_user_func_array( array( $this, 'render' ), $arguments );
148
-		}
149
-
150
-		return null;
151
-	}
132
+    }
133
+
134
+    /**
135
+     * is triggered when invoking inaccessible methods in an object context.
136
+     *
137
+     * @param string $name
138
+     * @param array  $arguments
139
+     *
140
+     * @return mixed
141
+     * @link https://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
142
+     */
143
+    public function __call( $name, $arguments ) {
144
+        switch ( $name ) {
145
+            case 'print':
146
+                _deprecated_function( __CLASS__ . '::print()', '2.2.4', __CLASS__ . '::render()' );
147
+                return call_user_func_array( array( $this, 'render' ), $arguments );
148
+        }
149
+
150
+        return null;
151
+    }
152 152
 }
Please login to merge, or discard this patch.
classes/data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php 1 patch
Indentation   +44 added lines, -44 removed lines patch added patch discarded remove patch
@@ -5,54 +5,54 @@
 block discarded – undo
5 5
  * @codeCoverageIgnore
6 6
  */
7 7
 class ActionScheduler_wpPostStore_PostStatusRegistrar {
8
-	public function register() {
9
-		register_post_status( ActionScheduler_Store::STATUS_RUNNING, array_merge( $this->post_status_args(), $this->post_status_running_labels() ) );
10
-		register_post_status( ActionScheduler_Store::STATUS_FAILED, array_merge( $this->post_status_args(), $this->post_status_failed_labels() ) );
11
-	}
8
+    public function register() {
9
+        register_post_status( ActionScheduler_Store::STATUS_RUNNING, array_merge( $this->post_status_args(), $this->post_status_running_labels() ) );
10
+        register_post_status( ActionScheduler_Store::STATUS_FAILED, array_merge( $this->post_status_args(), $this->post_status_failed_labels() ) );
11
+    }
12 12
 
13
-	/**
14
-	 * Build the args array for the post type definition
15
-	 *
16
-	 * @return array
17
-	 */
18
-	protected function post_status_args() {
19
-		$args = array(
20
-			'public'                    => false,
21
-			'exclude_from_search'       => false,
22
-			'show_in_admin_all_list'    => true,
23
-			'show_in_admin_status_list' => true,
24
-		);
13
+    /**
14
+     * Build the args array for the post type definition
15
+     *
16
+     * @return array
17
+     */
18
+    protected function post_status_args() {
19
+        $args = array(
20
+            'public'                    => false,
21
+            'exclude_from_search'       => false,
22
+            'show_in_admin_all_list'    => true,
23
+            'show_in_admin_status_list' => true,
24
+        );
25 25
 
26
-		return apply_filters( 'action_scheduler_post_status_args', $args );
27
-	}
26
+        return apply_filters( 'action_scheduler_post_status_args', $args );
27
+    }
28 28
 
29
-	/**
30
-	 * Build the args array for the post type definition
31
-	 *
32
-	 * @return array
33
-	 */
34
-	protected function post_status_failed_labels() {
35
-		$labels = array(
36
-			'label'       => _x( 'Failed', 'post', 'action-scheduler' ),
37
-			/* translators: %s: count */
38
-			'label_count' => _n_noop( 'Failed <span class="count">(%s)</span>', 'Failed <span class="count">(%s)</span>', 'action-scheduler' ),
39
-		);
29
+    /**
30
+     * Build the args array for the post type definition
31
+     *
32
+     * @return array
33
+     */
34
+    protected function post_status_failed_labels() {
35
+        $labels = array(
36
+            'label'       => _x( 'Failed', 'post', 'action-scheduler' ),
37
+            /* translators: %s: count */
38
+            'label_count' => _n_noop( 'Failed <span class="count">(%s)</span>', 'Failed <span class="count">(%s)</span>', 'action-scheduler' ),
39
+        );
40 40
 
41
-		return apply_filters( 'action_scheduler_post_status_failed_labels', $labels );
42
-	}
41
+        return apply_filters( 'action_scheduler_post_status_failed_labels', $labels );
42
+    }
43 43
 
44
-	/**
45
-	 * Build the args array for the post type definition
46
-	 *
47
-	 * @return array
48
-	 */
49
-	protected function post_status_running_labels() {
50
-		$labels = array(
51
-			'label'       => _x( 'In-Progress', 'post', 'action-scheduler' ),
52
-			/* translators: %s: count */
53
-			'label_count' => _n_noop( 'In-Progress <span class="count">(%s)</span>', 'In-Progress <span class="count">(%s)</span>', 'action-scheduler' ),
54
-		);
44
+    /**
45
+     * Build the args array for the post type definition
46
+     *
47
+     * @return array
48
+     */
49
+    protected function post_status_running_labels() {
50
+        $labels = array(
51
+            'label'       => _x( 'In-Progress', 'post', 'action-scheduler' ),
52
+            /* translators: %s: count */
53
+            'label_count' => _n_noop( 'In-Progress <span class="count">(%s)</span>', 'In-Progress <span class="count">(%s)</span>', 'action-scheduler' ),
54
+        );
55 55
 
56
-		return apply_filters( 'action_scheduler_post_status_running_labels', $labels );
57
-	}
56
+        return apply_filters( 'action_scheduler_post_status_running_labels', $labels );
57
+    }
58 58
 }
Please login to merge, or discard this patch.
action-scheduler/classes/data-stores/ActionScheduler_HybridStore.php 1 patch
Indentation   +360 added lines, -360 removed lines patch added patch discarded remove patch
@@ -13,368 +13,368 @@
 block discarded – undo
13 13
  * @since 3.0.0
14 14
  */
15 15
 class ActionScheduler_HybridStore extends Store {
16
-	const DEMARKATION_OPTION = 'action_scheduler_hybrid_store_demarkation';
17
-
18
-	private $primary_store;
19
-	private $secondary_store;
20
-	private $migration_runner;
21
-
22
-	/**
23
-	 * @var int The dividing line between IDs of actions created
24
-	 *          by the primary and secondary stores.
25
-	 *
26
-	 * Methods that accept an action ID will compare the ID against
27
-	 * this to determine which store will contain that ID. In almost
28
-	 * all cases, the ID should come from the primary store, but if
29
-	 * client code is bypassing the API functions and fetching IDs
30
-	 * from elsewhere, then there is a chance that an unmigrated ID
31
-	 * might be requested.
32
-	 */
33
-	private $demarkation_id = 0;
34
-
35
-	/**
36
-	 * ActionScheduler_HybridStore constructor.
37
-	 *
38
-	 * @param Config $config Migration config object.
39
-	 */
40
-	public function __construct( Config $config = null ) {
41
-		$this->demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 );
42
-		if ( empty( $config ) ) {
43
-			$config = Controller::instance()->get_migration_config_object();
44
-		}
45
-		$this->primary_store    = $config->get_destination_store();
46
-		$this->secondary_store  = $config->get_source_store();
47
-		$this->migration_runner = new Runner( $config );
48
-	}
49
-
50
-	/**
51
-	 * Initialize the table data store tables.
52
-	 *
53
-	 * @codeCoverageIgnore
54
-	 */
55
-	public function init() {
56
-		add_action( 'action_scheduler/created_table', [ $this, 'set_autoincrement' ], 10, 2 );
57
-		$this->primary_store->init();
58
-		$this->secondary_store->init();
59
-		remove_action( 'action_scheduler/created_table', [ $this, 'set_autoincrement' ], 10 );
60
-	}
61
-
62
-	/**
63
-	 * When the actions table is created, set its autoincrement
64
-	 * value to be one higher than the posts table to ensure that
65
-	 * there are no ID collisions.
66
-	 *
67
-	 * @param string $table_name
68
-	 * @param string $table_suffix
69
-	 *
70
-	 * @return void
71
-	 * @codeCoverageIgnore
72
-	 */
73
-	public function set_autoincrement( $table_name, $table_suffix ) {
74
-		if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) {
75
-			if ( empty( $this->demarkation_id ) ) {
76
-				$this->demarkation_id = $this->set_demarkation_id();
77
-			}
78
-			/** @var \wpdb $wpdb */
79
-			global $wpdb;
80
-			$wpdb->insert(
81
-				$wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
82
-				[
83
-					'action_id' => $this->demarkation_id,
84
-					'hook'      => '',
85
-					'status'    => '',
86
-				]
87
-			);
88
-			$wpdb->delete(
89
-				$wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
90
-				[ 'action_id' => $this->demarkation_id ]
91
-			);
92
-		}
93
-	}
94
-
95
-	/**
96
-	 * Store the demarkation id in WP options.
97
-	 *
98
-	 * @param int $id The ID to set as the demarkation point between the two stores
99
-	 *                Leave null to use the next ID from the WP posts table.
100
-	 *
101
-	 * @return int The new ID.
102
-	 *
103
-	 * @codeCoverageIgnore
104
-	 */
105
-	private function set_demarkation_id( $id = null ) {
106
-		if ( empty( $id ) ) {
107
-			/** @var \wpdb $wpdb */
108
-			global $wpdb;
109
-			$id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" );
110
-			$id ++;
111
-		}
112
-		update_option( self::DEMARKATION_OPTION, $id );
113
-
114
-		return $id;
115
-	}
116
-
117
-	/**
118
-	 * Find the first matching action from the secondary store.
119
-	 * If it exists, migrate it to the primary store immediately.
120
-	 * After it migrates, the secondary store will logically contain
121
-	 * the next matching action, so return the result thence.
122
-	 *
123
-	 * @param string $hook
124
-	 * @param array  $params
125
-	 *
126
-	 * @return string
127
-	 */
128
-	public function find_action( $hook, $params = [] ) {
129
-		$found_unmigrated_action = $this->secondary_store->find_action( $hook, $params );
130
-		if ( ! empty( $found_unmigrated_action ) ) {
131
-			$this->migrate( [ $found_unmigrated_action ] );
132
-		}
133
-
134
-		return $this->primary_store->find_action( $hook, $params );
135
-	}
136
-
137
-	/**
138
-	 * Find actions matching the query in the secondary source first.
139
-	 * If any are found, migrate them immediately. Then the secondary
140
-	 * store will contain the canonical results.
141
-	 *
142
-	 * @param array $query
143
-	 * @param string $query_type Whether to select or count the results. Default, select.
144
-	 *
145
-	 * @return int[]
146
-	 */
147
-	public function query_actions( $query = [], $query_type = 'select' ) {
148
-		$found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' );
149
-		if ( ! empty( $found_unmigrated_actions ) ) {
150
-			$this->migrate( $found_unmigrated_actions );
151
-		}
152
-
153
-		return $this->primary_store->query_actions( $query, $query_type );
154
-	}
155
-
156
-	/**
157
-	 * Get a count of all actions in the store, grouped by status
158
-	 *
159
-	 * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
160
-	 */
161
-	public function action_counts() {
162
-		$unmigrated_actions_count = $this->secondary_store->action_counts();
163
-		$migrated_actions_count   = $this->primary_store->action_counts();
164
-		$actions_count_by_status  = array();
165
-
166
-		foreach ( $this->get_status_labels() as $status_key => $status_label ) {
167
-
168
-			$count = 0;
169
-
170
-			if ( isset( $unmigrated_actions_count[ $status_key ] ) ) {
171
-				$count += $unmigrated_actions_count[ $status_key ];
172
-			}
173
-
174
-			if ( isset( $migrated_actions_count[ $status_key ] ) ) {
175
-				$count += $migrated_actions_count[ $status_key ];
176
-			}
177
-
178
-			$actions_count_by_status[ $status_key ] = $count;
179
-		}
180
-
181
-		$actions_count_by_status = array_filter( $actions_count_by_status );
182
-
183
-		return $actions_count_by_status;
184
-	}
185
-
186
-	/**
187
-	 * If any actions would have been claimed by the secondary store,
188
-	 * migrate them immediately, then ask the primary store for the
189
-	 * canonical claim.
190
-	 *
191
-	 * @param int           $max_actions
192
-	 * @param DateTime|null $before_date
193
-	 *
194
-	 * @return ActionScheduler_ActionClaim
195
-	 */
196
-	public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
197
-		$claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
198
-
199
-		$claimed_actions = $claim->get_actions();
200
-		if ( ! empty( $claimed_actions ) ) {
201
-			$this->migrate( $claimed_actions );
202
-		}
203
-
204
-		$this->secondary_store->release_claim( $claim );
205
-
206
-		return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
207
-	}
208
-
209
-	/**
210
-	 * Migrate a list of actions to the table data store.
211
-	 *
212
-	 * @param array $action_ids List of action IDs.
213
-	 */
214
-	private function migrate( $action_ids ) {
215
-		$this->migration_runner->migrate_actions( $action_ids );
216
-	}
217
-
218
-	/**
219
-	 * Save an action to the primary store.
220
-	 *
221
-	 * @param ActionScheduler_Action $action Action object to be saved.
222
-	 * @param DateTime               $date Optional. Schedule date. Default null.
223
-	 */
224
-	public function save_action( ActionScheduler_Action $action, DateTime $date = null ) {
225
-		return $this->primary_store->save_action( $action, $date );
226
-	}
227
-
228
-	/**
229
-	 * Retrieve an existing action whether migrated or not.
230
-	 *
231
-	 * @param int $action_id Action ID.
232
-	 */
233
-	public function fetch_action( $action_id ) {
234
-		if ( $action_id < $this->demarkation_id ) {
235
-			return $this->secondary_store->fetch_action( $action_id );
236
-		} else {
237
-			return $this->primary_store->fetch_action( $action_id );
238
-		}
239
-	}
240
-
241
-	/**
242
-	 * Cancel an existing action whether migrated or not.
243
-	 *
244
-	 * @param int $action_id Action ID.
245
-	 */
246
-	public function cancel_action( $action_id ) {
247
-		if ( $action_id < $this->demarkation_id ) {
248
-			$this->secondary_store->cancel_action( $action_id );
249
-		} else {
250
-			$this->primary_store->cancel_action( $action_id );
251
-		}
252
-	}
253
-
254
-	/**
255
-	 * Delete an existing action whether migrated or not.
256
-	 *
257
-	 * @param int $action_id Action ID.
258
-	 */
259
-	public function delete_action( $action_id ) {
260
-		if ( $action_id < $this->demarkation_id ) {
261
-			$this->secondary_store->delete_action( $action_id );
262
-		} else {
263
-			$this->primary_store->delete_action( $action_id );
264
-		}
265
-	}
266
-
267
-	/**
268
-	 * Get the schedule date an existing action whether migrated or not.
269
-	 *
270
-	 * @param int $action_id Action ID.
271
-	 */
272
-	public function get_date( $action_id ) {
273
-		if ( $action_id < $this->demarkation_id ) {
274
-			return $this->secondary_store->get_date( $action_id );
275
-		} else {
276
-			return $this->primary_store->get_date( $action_id );
277
-		}
278
-	}
279
-
280
-	/**
281
-	 * Mark an existing action as failed whether migrated or not.
282
-	 *
283
-	 * @param int $action_id Action ID.
284
-	 */
285
-	public function mark_failure( $action_id ) {
286
-		if ( $action_id < $this->demarkation_id ) {
287
-			$this->secondary_store->mark_failure( $action_id );
288
-		} else {
289
-			$this->primary_store->mark_failure( $action_id );
290
-		}
291
-	}
292
-
293
-	/**
294
-	 * Log the execution of an existing action whether migrated or not.
295
-	 *
296
-	 * @param int $action_id Action ID.
297
-	 */
298
-	public function log_execution( $action_id ) {
299
-		if ( $action_id < $this->demarkation_id ) {
300
-			$this->secondary_store->log_execution( $action_id );
301
-		} else {
302
-			$this->primary_store->log_execution( $action_id );
303
-		}
304
-	}
305
-
306
-	/**
307
-	 * Mark an existing action complete whether migrated or not.
308
-	 *
309
-	 * @param int $action_id Action ID.
310
-	 */
311
-	public function mark_complete( $action_id ) {
312
-		if ( $action_id < $this->demarkation_id ) {
313
-			$this->secondary_store->mark_complete( $action_id );
314
-		} else {
315
-			$this->primary_store->mark_complete( $action_id );
316
-		}
317
-	}
318
-
319
-	/**
320
-	 * Get an existing action status whether migrated or not.
321
-	 *
322
-	 * @param int $action_id Action ID.
323
-	 */
324
-	public function get_status( $action_id ) {
325
-		if ( $action_id < $this->demarkation_id ) {
326
-			return $this->secondary_store->get_status( $action_id );
327
-		} else {
328
-			return $this->primary_store->get_status( $action_id );
329
-		}
330
-	}
331
-
332
-
333
-	/* * * * * * * * * * * * * * * * * * * * * * * * * * *
16
+    const DEMARKATION_OPTION = 'action_scheduler_hybrid_store_demarkation';
17
+
18
+    private $primary_store;
19
+    private $secondary_store;
20
+    private $migration_runner;
21
+
22
+    /**
23
+     * @var int The dividing line between IDs of actions created
24
+     *          by the primary and secondary stores.
25
+     *
26
+     * Methods that accept an action ID will compare the ID against
27
+     * this to determine which store will contain that ID. In almost
28
+     * all cases, the ID should come from the primary store, but if
29
+     * client code is bypassing the API functions and fetching IDs
30
+     * from elsewhere, then there is a chance that an unmigrated ID
31
+     * might be requested.
32
+     */
33
+    private $demarkation_id = 0;
34
+
35
+    /**
36
+     * ActionScheduler_HybridStore constructor.
37
+     *
38
+     * @param Config $config Migration config object.
39
+     */
40
+    public function __construct( Config $config = null ) {
41
+        $this->demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 );
42
+        if ( empty( $config ) ) {
43
+            $config = Controller::instance()->get_migration_config_object();
44
+        }
45
+        $this->primary_store    = $config->get_destination_store();
46
+        $this->secondary_store  = $config->get_source_store();
47
+        $this->migration_runner = new Runner( $config );
48
+    }
49
+
50
+    /**
51
+     * Initialize the table data store tables.
52
+     *
53
+     * @codeCoverageIgnore
54
+     */
55
+    public function init() {
56
+        add_action( 'action_scheduler/created_table', [ $this, 'set_autoincrement' ], 10, 2 );
57
+        $this->primary_store->init();
58
+        $this->secondary_store->init();
59
+        remove_action( 'action_scheduler/created_table', [ $this, 'set_autoincrement' ], 10 );
60
+    }
61
+
62
+    /**
63
+     * When the actions table is created, set its autoincrement
64
+     * value to be one higher than the posts table to ensure that
65
+     * there are no ID collisions.
66
+     *
67
+     * @param string $table_name
68
+     * @param string $table_suffix
69
+     *
70
+     * @return void
71
+     * @codeCoverageIgnore
72
+     */
73
+    public function set_autoincrement( $table_name, $table_suffix ) {
74
+        if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) {
75
+            if ( empty( $this->demarkation_id ) ) {
76
+                $this->demarkation_id = $this->set_demarkation_id();
77
+            }
78
+            /** @var \wpdb $wpdb */
79
+            global $wpdb;
80
+            $wpdb->insert(
81
+                $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
82
+                [
83
+                    'action_id' => $this->demarkation_id,
84
+                    'hook'      => '',
85
+                    'status'    => '',
86
+                ]
87
+            );
88
+            $wpdb->delete(
89
+                $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
90
+                [ 'action_id' => $this->demarkation_id ]
91
+            );
92
+        }
93
+    }
94
+
95
+    /**
96
+     * Store the demarkation id in WP options.
97
+     *
98
+     * @param int $id The ID to set as the demarkation point between the two stores
99
+     *                Leave null to use the next ID from the WP posts table.
100
+     *
101
+     * @return int The new ID.
102
+     *
103
+     * @codeCoverageIgnore
104
+     */
105
+    private function set_demarkation_id( $id = null ) {
106
+        if ( empty( $id ) ) {
107
+            /** @var \wpdb $wpdb */
108
+            global $wpdb;
109
+            $id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" );
110
+            $id ++;
111
+        }
112
+        update_option( self::DEMARKATION_OPTION, $id );
113
+
114
+        return $id;
115
+    }
116
+
117
+    /**
118
+     * Find the first matching action from the secondary store.
119
+     * If it exists, migrate it to the primary store immediately.
120
+     * After it migrates, the secondary store will logically contain
121
+     * the next matching action, so return the result thence.
122
+     *
123
+     * @param string $hook
124
+     * @param array  $params
125
+     *
126
+     * @return string
127
+     */
128
+    public function find_action( $hook, $params = [] ) {
129
+        $found_unmigrated_action = $this->secondary_store->find_action( $hook, $params );
130
+        if ( ! empty( $found_unmigrated_action ) ) {
131
+            $this->migrate( [ $found_unmigrated_action ] );
132
+        }
133
+
134
+        return $this->primary_store->find_action( $hook, $params );
135
+    }
136
+
137
+    /**
138
+     * Find actions matching the query in the secondary source first.
139
+     * If any are found, migrate them immediately. Then the secondary
140
+     * store will contain the canonical results.
141
+     *
142
+     * @param array $query
143
+     * @param string $query_type Whether to select or count the results. Default, select.
144
+     *
145
+     * @return int[]
146
+     */
147
+    public function query_actions( $query = [], $query_type = 'select' ) {
148
+        $found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' );
149
+        if ( ! empty( $found_unmigrated_actions ) ) {
150
+            $this->migrate( $found_unmigrated_actions );
151
+        }
152
+
153
+        return $this->primary_store->query_actions( $query, $query_type );
154
+    }
155
+
156
+    /**
157
+     * Get a count of all actions in the store, grouped by status
158
+     *
159
+     * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
160
+     */
161
+    public function action_counts() {
162
+        $unmigrated_actions_count = $this->secondary_store->action_counts();
163
+        $migrated_actions_count   = $this->primary_store->action_counts();
164
+        $actions_count_by_status  = array();
165
+
166
+        foreach ( $this->get_status_labels() as $status_key => $status_label ) {
167
+
168
+            $count = 0;
169
+
170
+            if ( isset( $unmigrated_actions_count[ $status_key ] ) ) {
171
+                $count += $unmigrated_actions_count[ $status_key ];
172
+            }
173
+
174
+            if ( isset( $migrated_actions_count[ $status_key ] ) ) {
175
+                $count += $migrated_actions_count[ $status_key ];
176
+            }
177
+
178
+            $actions_count_by_status[ $status_key ] = $count;
179
+        }
180
+
181
+        $actions_count_by_status = array_filter( $actions_count_by_status );
182
+
183
+        return $actions_count_by_status;
184
+    }
185
+
186
+    /**
187
+     * If any actions would have been claimed by the secondary store,
188
+     * migrate them immediately, then ask the primary store for the
189
+     * canonical claim.
190
+     *
191
+     * @param int           $max_actions
192
+     * @param DateTime|null $before_date
193
+     *
194
+     * @return ActionScheduler_ActionClaim
195
+     */
196
+    public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
197
+        $claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
198
+
199
+        $claimed_actions = $claim->get_actions();
200
+        if ( ! empty( $claimed_actions ) ) {
201
+            $this->migrate( $claimed_actions );
202
+        }
203
+
204
+        $this->secondary_store->release_claim( $claim );
205
+
206
+        return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
207
+    }
208
+
209
+    /**
210
+     * Migrate a list of actions to the table data store.
211
+     *
212
+     * @param array $action_ids List of action IDs.
213
+     */
214
+    private function migrate( $action_ids ) {
215
+        $this->migration_runner->migrate_actions( $action_ids );
216
+    }
217
+
218
+    /**
219
+     * Save an action to the primary store.
220
+     *
221
+     * @param ActionScheduler_Action $action Action object to be saved.
222
+     * @param DateTime               $date Optional. Schedule date. Default null.
223
+     */
224
+    public function save_action( ActionScheduler_Action $action, DateTime $date = null ) {
225
+        return $this->primary_store->save_action( $action, $date );
226
+    }
227
+
228
+    /**
229
+     * Retrieve an existing action whether migrated or not.
230
+     *
231
+     * @param int $action_id Action ID.
232
+     */
233
+    public function fetch_action( $action_id ) {
234
+        if ( $action_id < $this->demarkation_id ) {
235
+            return $this->secondary_store->fetch_action( $action_id );
236
+        } else {
237
+            return $this->primary_store->fetch_action( $action_id );
238
+        }
239
+    }
240
+
241
+    /**
242
+     * Cancel an existing action whether migrated or not.
243
+     *
244
+     * @param int $action_id Action ID.
245
+     */
246
+    public function cancel_action( $action_id ) {
247
+        if ( $action_id < $this->demarkation_id ) {
248
+            $this->secondary_store->cancel_action( $action_id );
249
+        } else {
250
+            $this->primary_store->cancel_action( $action_id );
251
+        }
252
+    }
253
+
254
+    /**
255
+     * Delete an existing action whether migrated or not.
256
+     *
257
+     * @param int $action_id Action ID.
258
+     */
259
+    public function delete_action( $action_id ) {
260
+        if ( $action_id < $this->demarkation_id ) {
261
+            $this->secondary_store->delete_action( $action_id );
262
+        } else {
263
+            $this->primary_store->delete_action( $action_id );
264
+        }
265
+    }
266
+
267
+    /**
268
+     * Get the schedule date an existing action whether migrated or not.
269
+     *
270
+     * @param int $action_id Action ID.
271
+     */
272
+    public function get_date( $action_id ) {
273
+        if ( $action_id < $this->demarkation_id ) {
274
+            return $this->secondary_store->get_date( $action_id );
275
+        } else {
276
+            return $this->primary_store->get_date( $action_id );
277
+        }
278
+    }
279
+
280
+    /**
281
+     * Mark an existing action as failed whether migrated or not.
282
+     *
283
+     * @param int $action_id Action ID.
284
+     */
285
+    public function mark_failure( $action_id ) {
286
+        if ( $action_id < $this->demarkation_id ) {
287
+            $this->secondary_store->mark_failure( $action_id );
288
+        } else {
289
+            $this->primary_store->mark_failure( $action_id );
290
+        }
291
+    }
292
+
293
+    /**
294
+     * Log the execution of an existing action whether migrated or not.
295
+     *
296
+     * @param int $action_id Action ID.
297
+     */
298
+    public function log_execution( $action_id ) {
299
+        if ( $action_id < $this->demarkation_id ) {
300
+            $this->secondary_store->log_execution( $action_id );
301
+        } else {
302
+            $this->primary_store->log_execution( $action_id );
303
+        }
304
+    }
305
+
306
+    /**
307
+     * Mark an existing action complete whether migrated or not.
308
+     *
309
+     * @param int $action_id Action ID.
310
+     */
311
+    public function mark_complete( $action_id ) {
312
+        if ( $action_id < $this->demarkation_id ) {
313
+            $this->secondary_store->mark_complete( $action_id );
314
+        } else {
315
+            $this->primary_store->mark_complete( $action_id );
316
+        }
317
+    }
318
+
319
+    /**
320
+     * Get an existing action status whether migrated or not.
321
+     *
322
+     * @param int $action_id Action ID.
323
+     */
324
+    public function get_status( $action_id ) {
325
+        if ( $action_id < $this->demarkation_id ) {
326
+            return $this->secondary_store->get_status( $action_id );
327
+        } else {
328
+            return $this->primary_store->get_status( $action_id );
329
+        }
330
+    }
331
+
332
+
333
+    /* * * * * * * * * * * * * * * * * * * * * * * * * * *
334 334
 	 * All claim-related functions should operate solely
335 335
 	 * on the primary store.
336 336
 	 * * * * * * * * * * * * * * * * * * * * * * * * * * */
337 337
 
338
-	/**
339
-	 * Get the claim count from the table data store.
340
-	 */
341
-	public function get_claim_count() {
342
-		return $this->primary_store->get_claim_count();
343
-	}
344
-
345
-	/**
346
-	 * Retrieve the claim ID for an action from the table data store.
347
-	 *
348
-	 * @param int $action_id Action ID.
349
-	 */
350
-	public function get_claim_id( $action_id ) {
351
-		return $this->primary_store->get_claim_id( $action_id );
352
-	}
353
-
354
-	/**
355
-	 * Release a claim in the table data store.
356
-	 *
357
-	 * @param ActionScheduler_ActionClaim $claim Claim object.
358
-	 */
359
-	public function release_claim( ActionScheduler_ActionClaim $claim ) {
360
-		$this->primary_store->release_claim( $claim );
361
-	}
362
-
363
-	/**
364
-	 * Release claims on an action in the table data store.
365
-	 *
366
-	 * @param int $action_id Action ID.
367
-	 */
368
-	public function unclaim_action( $action_id ) {
369
-		$this->primary_store->unclaim_action( $action_id );
370
-	}
371
-
372
-	/**
373
-	 * Retrieve a list of action IDs by claim.
374
-	 *
375
-	 * @param int $claim_id Claim ID.
376
-	 */
377
-	public function find_actions_by_claim_id( $claim_id ) {
378
-		return $this->primary_store->find_actions_by_claim_id( $claim_id );
379
-	}
338
+    /**
339
+     * Get the claim count from the table data store.
340
+     */
341
+    public function get_claim_count() {
342
+        return $this->primary_store->get_claim_count();
343
+    }
344
+
345
+    /**
346
+     * Retrieve the claim ID for an action from the table data store.
347
+     *
348
+     * @param int $action_id Action ID.
349
+     */
350
+    public function get_claim_id( $action_id ) {
351
+        return $this->primary_store->get_claim_id( $action_id );
352
+    }
353
+
354
+    /**
355
+     * Release a claim in the table data store.
356
+     *
357
+     * @param ActionScheduler_ActionClaim $claim Claim object.
358
+     */
359
+    public function release_claim( ActionScheduler_ActionClaim $claim ) {
360
+        $this->primary_store->release_claim( $claim );
361
+    }
362
+
363
+    /**
364
+     * Release claims on an action in the table data store.
365
+     *
366
+     * @param int $action_id Action ID.
367
+     */
368
+    public function unclaim_action( $action_id ) {
369
+        $this->primary_store->unclaim_action( $action_id );
370
+    }
371
+
372
+    /**
373
+     * Retrieve a list of action IDs by claim.
374
+     *
375
+     * @param int $claim_id Claim ID.
376
+     */
377
+    public function find_actions_by_claim_id( $claim_id ) {
378
+        return $this->primary_store->find_actions_by_claim_id( $claim_id );
379
+    }
380 380
 }
Please login to merge, or discard this patch.
libraries/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php 1 patch
Indentation   +134 added lines, -134 removed lines patch added patch discarded remove patch
@@ -9,138 +9,138 @@
 block discarded – undo
9 9
  */
10 10
 class ActionScheduler_DBLogger extends ActionScheduler_Logger {
11 11
 
12
-	/**
13
-	 * Add a record to an action log.
14
-	 *
15
-	 * @param int      $action_id Action ID.
16
-	 * @param string   $message Message to be saved in the log entry.
17
-	 * @param DateTime $date Timestamp of the log entry.
18
-	 *
19
-	 * @return int     The log entry ID.
20
-	 */
21
-	public function log( $action_id, $message, DateTime $date = null ) {
22
-		if ( empty( $date ) ) {
23
-			$date = as_get_datetime_object();
24
-		} else {
25
-			$date = clone $date;
26
-		}
27
-
28
-		$date_gmt = $date->format( 'Y-m-d H:i:s' );
29
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
30
-		$date_local = $date->format( 'Y-m-d H:i:s' );
31
-
32
-		/** @var \wpdb $wpdb */
33
-		global $wpdb;
34
-		$wpdb->insert( $wpdb->actionscheduler_logs, [
35
-			'action_id'      => $action_id,
36
-			'message'        => $message,
37
-			'log_date_gmt'   => $date_gmt,
38
-			'log_date_local' => $date_local,
39
-		], [ '%d', '%s', '%s', '%s' ] );
40
-
41
-		return $wpdb->insert_id;
42
-	}
43
-
44
-	/**
45
-	 * Retrieve an action log entry.
46
-	 *
47
-	 * @param int $entry_id Log entry ID.
48
-	 *
49
-	 * @return ActionScheduler_LogEntry
50
-	 */
51
-	public function get_entry( $entry_id ) {
52
-		/** @var \wpdb $wpdb */
53
-		global $wpdb;
54
-		$entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );
55
-
56
-		return $this->create_entry_from_db_record( $entry );
57
-	}
58
-
59
-	/**
60
-	 * Create an action log entry from a database record.
61
-	 *
62
-	 * @param object $record Log entry database record object.
63
-	 *
64
-	 * @return ActionScheduler_LogEntry
65
-	 */
66
-	private function create_entry_from_db_record( $record ) {
67
-		if ( empty( $record ) ) {
68
-			return new ActionScheduler_NullLogEntry();
69
-		}
70
-
71
-		$date = as_get_datetime_object( $record->log_date_gmt );
72
-
73
-		return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date );
74
-	}
75
-
76
-	/**
77
-	 * Retrieve the an action's log entries from the database.
78
-	 *
79
-	 * @param int $action_id Action ID.
80
-	 *
81
-	 * @return ActionScheduler_LogEntry[]
82
-	 */
83
-	public function get_logs( $action_id ) {
84
-		/** @var \wpdb $wpdb */
85
-		global $wpdb;
86
-
87
-		$records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );
88
-
89
-		return array_map( [ $this, 'create_entry_from_db_record' ], $records );
90
-	}
91
-
92
-	/**
93
-	 * Initialize the data store.
94
-	 *
95
-	 * @codeCoverageIgnore
96
-	 */
97
-	public function init() {
98
-
99
-		$table_maker = new ActionScheduler_LoggerSchema();
100
-		$table_maker->register_tables();
101
-
102
-		parent::init();
103
-
104
-		add_action( 'action_scheduler_deleted_action', [ $this, 'clear_deleted_action_logs' ], 10, 1 );
105
-	}
106
-
107
-	/**
108
-	 * Delete the action logs for an action.
109
-	 *
110
-	 * @param int $action_id Action ID.
111
-	 */
112
-	public function clear_deleted_action_logs( $action_id ) {
113
-		/** @var \wpdb $wpdb */
114
-		global $wpdb;
115
-		$wpdb->delete( $wpdb->actionscheduler_logs, [ 'action_id' => $action_id, ], [ '%d' ] );
116
-	}
117
-
118
-	/**
119
-	 * Bulk add cancel action log entries.
120
-	 *
121
-	 * @param array $action_ids List of action ID.
122
-	 */
123
-	public function bulk_log_cancel_actions( $action_ids ) {
124
-		if ( empty( $action_ids ) ) {
125
-			return;
126
-		}
127
-
128
-		/** @var \wpdb $wpdb */
129
-		global $wpdb;
130
-		$date     = as_get_datetime_object();
131
-		$date_gmt = $date->format( 'Y-m-d H:i:s' );
132
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
133
-		$date_local = $date->format( 'Y-m-d H:i:s' );
134
-		$message    = __( 'action canceled', 'action-scheduler' );
135
-		$format     = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';
136
-		$sql_query  = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";
137
-		$value_rows = [];
138
-
139
-		foreach ( $action_ids as $action_id ) {
140
-			$value_rows[] = $wpdb->prepare( $format, $action_id );
141
-		}
142
-		$sql_query .= implode( ',', $value_rows );
143
-
144
-		$wpdb->query( $sql_query );
145
-	}
12
+    /**
13
+     * Add a record to an action log.
14
+     *
15
+     * @param int      $action_id Action ID.
16
+     * @param string   $message Message to be saved in the log entry.
17
+     * @param DateTime $date Timestamp of the log entry.
18
+     *
19
+     * @return int     The log entry ID.
20
+     */
21
+    public function log( $action_id, $message, DateTime $date = null ) {
22
+        if ( empty( $date ) ) {
23
+            $date = as_get_datetime_object();
24
+        } else {
25
+            $date = clone $date;
26
+        }
27
+
28
+        $date_gmt = $date->format( 'Y-m-d H:i:s' );
29
+        ActionScheduler_TimezoneHelper::set_local_timezone( $date );
30
+        $date_local = $date->format( 'Y-m-d H:i:s' );
31
+
32
+        /** @var \wpdb $wpdb */
33
+        global $wpdb;
34
+        $wpdb->insert( $wpdb->actionscheduler_logs, [
35
+            'action_id'      => $action_id,
36
+            'message'        => $message,
37
+            'log_date_gmt'   => $date_gmt,
38
+            'log_date_local' => $date_local,
39
+        ], [ '%d', '%s', '%s', '%s' ] );
40
+
41
+        return $wpdb->insert_id;
42
+    }
43
+
44
+    /**
45
+     * Retrieve an action log entry.
46
+     *
47
+     * @param int $entry_id Log entry ID.
48
+     *
49
+     * @return ActionScheduler_LogEntry
50
+     */
51
+    public function get_entry( $entry_id ) {
52
+        /** @var \wpdb $wpdb */
53
+        global $wpdb;
54
+        $entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );
55
+
56
+        return $this->create_entry_from_db_record( $entry );
57
+    }
58
+
59
+    /**
60
+     * Create an action log entry from a database record.
61
+     *
62
+     * @param object $record Log entry database record object.
63
+     *
64
+     * @return ActionScheduler_LogEntry
65
+     */
66
+    private function create_entry_from_db_record( $record ) {
67
+        if ( empty( $record ) ) {
68
+            return new ActionScheduler_NullLogEntry();
69
+        }
70
+
71
+        $date = as_get_datetime_object( $record->log_date_gmt );
72
+
73
+        return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date );
74
+    }
75
+
76
+    /**
77
+     * Retrieve the an action's log entries from the database.
78
+     *
79
+     * @param int $action_id Action ID.
80
+     *
81
+     * @return ActionScheduler_LogEntry[]
82
+     */
83
+    public function get_logs( $action_id ) {
84
+        /** @var \wpdb $wpdb */
85
+        global $wpdb;
86
+
87
+        $records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );
88
+
89
+        return array_map( [ $this, 'create_entry_from_db_record' ], $records );
90
+    }
91
+
92
+    /**
93
+     * Initialize the data store.
94
+     *
95
+     * @codeCoverageIgnore
96
+     */
97
+    public function init() {
98
+
99
+        $table_maker = new ActionScheduler_LoggerSchema();
100
+        $table_maker->register_tables();
101
+
102
+        parent::init();
103
+
104
+        add_action( 'action_scheduler_deleted_action', [ $this, 'clear_deleted_action_logs' ], 10, 1 );
105
+    }
106
+
107
+    /**
108
+     * Delete the action logs for an action.
109
+     *
110
+     * @param int $action_id Action ID.
111
+     */
112
+    public function clear_deleted_action_logs( $action_id ) {
113
+        /** @var \wpdb $wpdb */
114
+        global $wpdb;
115
+        $wpdb->delete( $wpdb->actionscheduler_logs, [ 'action_id' => $action_id, ], [ '%d' ] );
116
+    }
117
+
118
+    /**
119
+     * Bulk add cancel action log entries.
120
+     *
121
+     * @param array $action_ids List of action ID.
122
+     */
123
+    public function bulk_log_cancel_actions( $action_ids ) {
124
+        if ( empty( $action_ids ) ) {
125
+            return;
126
+        }
127
+
128
+        /** @var \wpdb $wpdb */
129
+        global $wpdb;
130
+        $date     = as_get_datetime_object();
131
+        $date_gmt = $date->format( 'Y-m-d H:i:s' );
132
+        ActionScheduler_TimezoneHelper::set_local_timezone( $date );
133
+        $date_local = $date->format( 'Y-m-d H:i:s' );
134
+        $message    = __( 'action canceled', 'action-scheduler' );
135
+        $format     = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';
136
+        $sql_query  = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";
137
+        $value_rows = [];
138
+
139
+        foreach ( $action_ids as $action_id ) {
140
+            $value_rows[] = $wpdb->prepare( $format, $action_id );
141
+        }
142
+        $sql_query .= implode( ',', $value_rows );
143
+
144
+        $wpdb->query( $sql_query );
145
+    }
146 146
 }
Please login to merge, or discard this patch.
classes/data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php 1 patch
Indentation   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -5,22 +5,22 @@
 block discarded – undo
5 5
  * @codeCoverageIgnore
6 6
  */
7 7
 class ActionScheduler_wpPostStore_TaxonomyRegistrar {
8
-	public function register() {
9
-		register_taxonomy( ActionScheduler_wpPostStore::GROUP_TAXONOMY, ActionScheduler_wpPostStore::POST_TYPE, $this->taxonomy_args() );
10
-	}
8
+    public function register() {
9
+        register_taxonomy( ActionScheduler_wpPostStore::GROUP_TAXONOMY, ActionScheduler_wpPostStore::POST_TYPE, $this->taxonomy_args() );
10
+    }
11 11
 
12
-	protected function taxonomy_args() {
13
-		$args = array(
14
-			'label' => __( 'Action Group', 'action-scheduler' ),
15
-			'public' => false,
16
-			'hierarchical' => false,
17
-			'show_admin_column' => true,
18
-			'query_var' => false,
19
-			'rewrite' => false,
20
-		);
12
+    protected function taxonomy_args() {
13
+        $args = array(
14
+            'label' => __( 'Action Group', 'action-scheduler' ),
15
+            'public' => false,
16
+            'hierarchical' => false,
17
+            'show_admin_column' => true,
18
+            'query_var' => false,
19
+            'rewrite' => false,
20
+        );
21 21
 
22
-		$args = apply_filters( 'action_scheduler_taxonomy_args', $args );
23
-		return $args;
24
-	}
22
+        $args = apply_filters( 'action_scheduler_taxonomy_args', $args );
23
+        return $args;
24
+    }
25 25
 }
26
- 
27 26
\ No newline at end of file
27
+    
28 28
\ No newline at end of file
Please login to merge, or discard this patch.
classes/data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php 1 patch
Indentation   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -5,46 +5,46 @@
 block discarded – undo
5 5
  * @codeCoverageIgnore
6 6
  */
7 7
 class ActionScheduler_wpPostStore_PostTypeRegistrar {
8
-	public function register() {
9
-		register_post_type( ActionScheduler_wpPostStore::POST_TYPE, $this->post_type_args() );
10
-	}
8
+    public function register() {
9
+        register_post_type( ActionScheduler_wpPostStore::POST_TYPE, $this->post_type_args() );
10
+    }
11 11
 
12
-	/**
13
-	 * Build the args array for the post type definition
14
-	 *
15
-	 * @return array
16
-	 */
17
-	protected function post_type_args() {
18
-		$args = array(
19
-			'label' => __( 'Scheduled Actions', 'action-scheduler' ),
20
-			'description' => __( 'Scheduled actions are hooks triggered on a cetain date and time.', 'action-scheduler' ),
21
-			'public' => false,
22
-			'map_meta_cap' => true,
23
-			'hierarchical' => false,
24
-			'supports' => array('title', 'editor','comments'),
25
-			'rewrite' => false,
26
-			'query_var' => false,
27
-			'can_export' => true,
28
-			'ep_mask' => EP_NONE,
29
-			'labels' => array(
30
-				'name' => __( 'Scheduled Actions', 'action-scheduler' ),
31
-				'singular_name' => __( 'Scheduled Action', 'action-scheduler' ),
32
-				'menu_name' => _x( 'Scheduled Actions', 'Admin menu name', 'action-scheduler' ),
33
-				'add_new' => __( 'Add', 'action-scheduler' ),
34
-				'add_new_item' => __( 'Add New Scheduled Action', 'action-scheduler' ),
35
-				'edit' => __( 'Edit', 'action-scheduler' ),
36
-				'edit_item' => __( 'Edit Scheduled Action', 'action-scheduler' ),
37
-				'new_item' => __( 'New Scheduled Action', 'action-scheduler' ),
38
-				'view' => __( 'View Action', 'action-scheduler' ),
39
-				'view_item' => __( 'View Action', 'action-scheduler' ),
40
-				'search_items' => __( 'Search Scheduled Actions', 'action-scheduler' ),
41
-				'not_found' => __( 'No actions found', 'action-scheduler' ),
42
-				'not_found_in_trash' => __( 'No actions found in trash', 'action-scheduler' ),
43
-			),
44
-		);
12
+    /**
13
+     * Build the args array for the post type definition
14
+     *
15
+     * @return array
16
+     */
17
+    protected function post_type_args() {
18
+        $args = array(
19
+            'label' => __( 'Scheduled Actions', 'action-scheduler' ),
20
+            'description' => __( 'Scheduled actions are hooks triggered on a cetain date and time.', 'action-scheduler' ),
21
+            'public' => false,
22
+            'map_meta_cap' => true,
23
+            'hierarchical' => false,
24
+            'supports' => array('title', 'editor','comments'),
25
+            'rewrite' => false,
26
+            'query_var' => false,
27
+            'can_export' => true,
28
+            'ep_mask' => EP_NONE,
29
+            'labels' => array(
30
+                'name' => __( 'Scheduled Actions', 'action-scheduler' ),
31
+                'singular_name' => __( 'Scheduled Action', 'action-scheduler' ),
32
+                'menu_name' => _x( 'Scheduled Actions', 'Admin menu name', 'action-scheduler' ),
33
+                'add_new' => __( 'Add', 'action-scheduler' ),
34
+                'add_new_item' => __( 'Add New Scheduled Action', 'action-scheduler' ),
35
+                'edit' => __( 'Edit', 'action-scheduler' ),
36
+                'edit_item' => __( 'Edit Scheduled Action', 'action-scheduler' ),
37
+                'new_item' => __( 'New Scheduled Action', 'action-scheduler' ),
38
+                'view' => __( 'View Action', 'action-scheduler' ),
39
+                'view_item' => __( 'View Action', 'action-scheduler' ),
40
+                'search_items' => __( 'Search Scheduled Actions', 'action-scheduler' ),
41
+                'not_found' => __( 'No actions found', 'action-scheduler' ),
42
+                'not_found_in_trash' => __( 'No actions found in trash', 'action-scheduler' ),
43
+            ),
44
+        );
45 45
 
46
-		$args = apply_filters('action_scheduler_post_type_args', $args);
47
-		return $args;
48
-	}
46
+        $args = apply_filters('action_scheduler_post_type_args', $args);
47
+        return $args;
48
+    }
49 49
 }
50
- 
51 50
\ No newline at end of file
51
+    
52 52
\ No newline at end of file
Please login to merge, or discard this patch.
libraries/action-scheduler/classes/data-stores/ActionScheduler_DBStore.php 1 patch
Indentation   +833 added lines, -833 removed lines patch added patch discarded remove patch
@@ -9,837 +9,837 @@
 block discarded – undo
9 9
  */
10 10
 class ActionScheduler_DBStore extends ActionScheduler_Store {
11 11
 
12
-	/** @var int */
13
-	protected static $max_args_length = 8000;
14
-
15
-	/** @var int */
16
-	protected static $max_index_length = 191;
17
-
18
-	/**
19
-	 * Initialize the data store
20
-	 *
21
-	 * @codeCoverageIgnore
22
-	 */
23
-	public function init() {
24
-		$table_maker = new ActionScheduler_StoreSchema();
25
-		$table_maker->register_tables();
26
-	}
27
-
28
-	/**
29
-	 * Save an action.
30
-	 *
31
-	 * @param ActionScheduler_Action $action Action object.
32
-	 * @param DateTime               $date Optional schedule date. Default null.
33
-	 *
34
-	 * @return int Action ID.
35
-	 */
36
-	public function save_action( ActionScheduler_Action $action, \DateTime $date = null ) {
37
-		try {
38
-
39
-			$this->validate_action( $action );
40
-
41
-			/** @var \wpdb $wpdb */
42
-			global $wpdb;
43
-			$data = [
44
-				'hook'                 => $action->get_hook(),
45
-				'status'               => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ),
46
-				'scheduled_date_gmt'   => $this->get_scheduled_date_string( $action, $date ),
47
-				'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ),
48
-				'schedule'             => serialize( $action->get_schedule() ),
49
-				'group_id'             => $this->get_group_id( $action->get_group() ),
50
-			];
51
-			$args = wp_json_encode( $action->get_args() );
52
-			if ( strlen( $args ) <= static::$max_index_length ) {
53
-				$data['args'] = $args;
54
-			} else {
55
-				$data['args']          = $this->hash_args( $args );
56
-				$data['extended_args'] = $args;
57
-			}
58
-
59
-			$table_name = ! empty( $wpdb->actionscheduler_actions ) ? $wpdb->actionscheduler_actions : $wpdb->prefix . 'actionscheduler_actions';
60
-			$wpdb->insert( $table_name, $data );
61
-			$action_id = $wpdb->insert_id;
62
-
63
-			if ( is_wp_error( $action_id ) ) {
64
-				throw new RuntimeException( $action_id->get_error_message() );
65
-			}
66
-			elseif ( empty( $action_id ) ) {
67
-				throw new RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
68
-			}
69
-
70
-			do_action( 'action_scheduler_stored_action', $action_id );
71
-
72
-			return $action_id;
73
-		} catch ( \Exception $e ) {
74
-			/* translators: %s: error message */
75
-			throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
76
-		}
77
-	}
78
-
79
-	/**
80
-	 * Generate a hash from json_encoded $args using MD5 as this isn't for security.
81
-	 *
82
-	 * @param string $args JSON encoded action args.
83
-	 * @return string
84
-	 */
85
-	protected function hash_args( $args ) {
86
-		return md5( $args );
87
-	}
88
-
89
-	/**
90
-	 * Get action args query param value from action args.
91
-	 *
92
-	 * @param array $args Action args.
93
-	 * @return string
94
-	 */
95
-	protected function get_args_for_query( $args ) {
96
-		$encoded = wp_json_encode( $args );
97
-		if ( strlen( $encoded ) <= static::$max_index_length ) {
98
-			return $encoded;
99
-		}
100
-		return $this->hash_args( $encoded );
101
-	}
102
-	/**
103
-	 * Get a group's ID based on its name/slug.
104
-	 *
105
-	 * @param string $slug The string name of a group.
106
-	 * @param bool $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group.
107
-	 *
108
-	 * @return int The group's ID, if it exists or is created, or 0 if it does not exist and is not created.
109
-	 */
110
-	protected function get_group_id( $slug, $create_if_not_exists = true ) {
111
-		if ( empty( $slug ) ) {
112
-			return 0;
113
-		}
114
-		/** @var \wpdb $wpdb */
115
-		global $wpdb;
116
-		$group_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT group_id FROM {$wpdb->actionscheduler_groups} WHERE slug=%s", $slug ) );
117
-		if ( empty( $group_id ) && $create_if_not_exists ) {
118
-			$group_id = $this->create_group( $slug );
119
-		}
120
-
121
-		return $group_id;
122
-	}
123
-
124
-	/**
125
-	 * Create an action group.
126
-	 *
127
-	 * @param string $slug Group slug.
128
-	 *
129
-	 * @return int Group ID.
130
-	 */
131
-	protected function create_group( $slug ) {
132
-		/** @var \wpdb $wpdb */
133
-		global $wpdb;
134
-		$wpdb->insert( $wpdb->actionscheduler_groups, [ 'slug' => $slug ] );
135
-
136
-		return (int) $wpdb->insert_id;
137
-	}
138
-
139
-	/**
140
-	 * Retrieve an action.
141
-	 *
142
-	 * @param int $action_id Action ID.
143
-	 *
144
-	 * @return ActionScheduler_Action
145
-	 */
146
-	public function fetch_action( $action_id ) {
147
-		/** @var \wpdb $wpdb */
148
-		global $wpdb;
149
-		$data = $wpdb->get_row( $wpdb->prepare(
150
-			"SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d",
151
-			$action_id
152
-		) );
153
-
154
-		if ( empty( $data ) ) {
155
-			return $this->get_null_action();
156
-		}
157
-
158
-		if ( ! empty( $data->extended_args ) ) {
159
-			$data->args = $data->extended_args;
160
-			unset( $data->extended_args );
161
-		}
162
-
163
-		try {
164
-			$action = $this->make_action_from_db_record( $data );
165
-		} catch ( ActionScheduler_InvalidActionException $exception ) {
166
-			do_action( 'action_scheduler_failed_fetch_action', $action_id, $exception );
167
-			return $this->get_null_action();
168
-		}
169
-
170
-		return $action;
171
-	}
172
-
173
-	/**
174
-	 * Create a null action.
175
-	 *
176
-	 * @return ActionScheduler_NullAction
177
-	 */
178
-	protected function get_null_action() {
179
-		return new ActionScheduler_NullAction();
180
-	}
181
-
182
-	/**
183
-	 * Create an action from a database record.
184
-	 *
185
-	 * @param object $data Action database record.
186
-	 *
187
-	 * @return ActionScheduler_Action|ActionScheduler_CanceledAction|ActionScheduler_FinishedAction
188
-	 */
189
-	protected function make_action_from_db_record( $data ) {
190
-
191
-		$hook     = $data->hook;
192
-		$args     = json_decode( $data->args, true );
193
-		$schedule = unserialize( $data->schedule );
194
-
195
-		$this->validate_args( $args, $data->action_id );
196
-		$this->validate_schedule( $schedule, $data->action_id );
197
-
198
-		if ( empty( $schedule ) ) {
199
-			$schedule = new ActionScheduler_NullSchedule();
200
-		}
201
-		$group = $data->group ? $data->group : '';
202
-
203
-		return ActionScheduler::factory()->get_stored_action( $data->status, $data->hook, $args, $schedule, $group );
204
-	}
205
-
206
-	/**
207
-	 * Find an action.
208
-	 *
209
-	 * @param string $hook Action hook.
210
-	 * @param array  $params Parameters of the action to find.
211
-	 *
212
-	 * @return string|null ID of the next action matching the criteria or NULL if not found.
213
-	 */
214
-	public function find_action( $hook, $params = [] ) {
215
-		$params = wp_parse_args( $params, [
216
-			'args'   => null,
217
-			'status' => self::STATUS_PENDING,
218
-			'group'  => '',
219
-		] );
220
-
221
-		/** @var wpdb $wpdb */
222
-		global $wpdb;
223
-		$query = "SELECT a.action_id FROM {$wpdb->actionscheduler_actions} a";
224
-		$args  = [];
225
-		if ( ! empty( $params[ 'group' ] ) ) {
226
-			$query  .= " INNER JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id AND g.slug=%s";
227
-			$args[] = $params[ 'group' ];
228
-		}
229
-		$query  .= " WHERE a.hook=%s";
230
-		$args[] = $hook;
231
-		if ( ! is_null( $params[ 'args' ] ) ) {
232
-			$query  .= " AND a.args=%s";
233
-			$args[] = $this->get_args_for_query( $params[ 'args' ] );
234
-		}
235
-
236
-		$order = 'ASC';
237
-		if ( ! empty( $params[ 'status' ] ) ) {
238
-			$query  .= " AND a.status=%s";
239
-			$args[] = $params[ 'status' ];
240
-
241
-			if ( self::STATUS_PENDING == $params[ 'status' ] ) {
242
-				$order = 'ASC'; // Find the next action that matches.
243
-			} else {
244
-				$order = 'DESC'; // Find the most recent action that matches.
245
-			}
246
-		}
247
-
248
-		$query .= " ORDER BY scheduled_date_gmt $order LIMIT 1";
249
-
250
-		$query = $wpdb->prepare( $query, $args );
251
-
252
-		$id = $wpdb->get_var( $query );
253
-
254
-		return $id;
255
-	}
256
-
257
-	/**
258
-	 * Returns the SQL statement to query (or count) actions.
259
-	 *
260
-	 * @param array  $query Filtering options.
261
-	 * @param string $select_or_count  Whether the SQL should select and return the IDs or just the row count.
262
-	 *
263
-	 * @return string SQL statement already properly escaped.
264
-	 */
265
-	protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
266
-
267
-		if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
268
-			throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) );
269
-		}
270
-
271
-		$query = wp_parse_args( $query, [
272
-			'hook'             => '',
273
-			'args'             => null,
274
-			'date'             => null,
275
-			'date_compare'     => '<=',
276
-			'modified'         => null,
277
-			'modified_compare' => '<=',
278
-			'group'            => '',
279
-			'status'           => '',
280
-			'claimed'          => null,
281
-			'per_page'         => 5,
282
-			'offset'           => 0,
283
-			'orderby'          => 'date',
284
-			'order'            => 'ASC',
285
-		] );
286
-
287
-		/** @var \wpdb $wpdb */
288
-		global $wpdb;
289
-		$sql  = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
290
-		$sql .= " FROM {$wpdb->actionscheduler_actions} a";
291
-		$sql_params = [];
292
-
293
-		if ( ! empty( $query[ 'group' ] ) || 'group' === $query[ 'orderby' ] ) {
294
-			$sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id";
295
-		}
296
-
297
-		$sql .= " WHERE 1=1";
298
-
299
-		if ( ! empty( $query[ 'group' ] ) ) {
300
-			$sql          .= " AND g.slug=%s";
301
-			$sql_params[] = $query[ 'group' ];
302
-		}
303
-
304
-		if ( $query[ 'hook' ] ) {
305
-			$sql          .= " AND a.hook=%s";
306
-			$sql_params[] = $query[ 'hook' ];
307
-		}
308
-		if ( ! is_null( $query[ 'args' ] ) ) {
309
-			$sql          .= " AND a.args=%s";
310
-			$sql_params[] = $this->get_args_for_query( $query[ 'args' ] );
311
-		}
312
-
313
-		if ( $query[ 'status' ] ) {
314
-			$sql          .= " AND a.status=%s";
315
-			$sql_params[] = $query[ 'status' ];
316
-		}
317
-
318
-		if ( $query[ 'date' ] instanceof \DateTime ) {
319
-			$date = clone $query[ 'date' ];
320
-			$date->setTimezone( new \DateTimeZone( 'UTC' ) );
321
-			$date_string  = $date->format( 'Y-m-d H:i:s' );
322
-			$comparator   = $this->validate_sql_comparator( $query[ 'date_compare' ] );
323
-			$sql          .= " AND a.scheduled_date_gmt $comparator %s";
324
-			$sql_params[] = $date_string;
325
-		}
326
-
327
-		if ( $query[ 'modified' ] instanceof \DateTime ) {
328
-			$modified = clone $query[ 'modified' ];
329
-			$modified->setTimezone( new \DateTimeZone( 'UTC' ) );
330
-			$date_string  = $modified->format( 'Y-m-d H:i:s' );
331
-			$comparator   = $this->validate_sql_comparator( $query[ 'modified_compare' ] );
332
-			$sql          .= " AND a.last_attempt_gmt $comparator %s";
333
-			$sql_params[] = $date_string;
334
-		}
335
-
336
-		if ( $query[ 'claimed' ] === true ) {
337
-			$sql .= " AND a.claim_id != 0";
338
-		} elseif ( $query[ 'claimed' ] === false ) {
339
-			$sql .= " AND a.claim_id = 0";
340
-		} elseif ( ! is_null( $query[ 'claimed' ] ) ) {
341
-			$sql          .= " AND a.claim_id = %d";
342
-			$sql_params[] = $query[ 'claimed' ];
343
-		}
344
-
345
-		if ( ! empty( $query['search'] ) ) {
346
-			$sql .= " AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s";
347
-			for( $i = 0; $i < 3; $i++ ) {
348
-				$sql_params[] = sprintf( '%%%s%%', $query['search'] );
349
-			}
350
-
351
-			$search_claim_id = (int) $query['search'];
352
-			if ( $search_claim_id ) {
353
-				$sql .= ' OR a.claim_id = %d';
354
-				$sql_params[] = $search_claim_id;
355
-			}
356
-
357
-			$sql .= ')';
358
-		}
359
-
360
-		if ( 'select' === $select_or_count ) {
361
-			switch ( $query['orderby'] ) {
362
-				case 'hook':
363
-					$orderby = 'a.hook';
364
-					break;
365
-				case 'group':
366
-					$orderby = 'g.slug';
367
-					break;
368
-				case 'modified':
369
-					$orderby = 'a.last_attempt_gmt';
370
-					break;
371
-				case 'date':
372
-				default:
373
-					$orderby = 'a.scheduled_date_gmt';
374
-					break;
375
-			}
376
-			if ( strtoupper( $query[ 'order' ] ) == 'ASC' ) {
377
-				$order = 'ASC';
378
-			} else {
379
-				$order = 'DESC';
380
-			}
381
-			$sql .= " ORDER BY $orderby $order";
382
-			if ( $query[ 'per_page' ] > 0 ) {
383
-				$sql          .= " LIMIT %d, %d";
384
-				$sql_params[] = $query[ 'offset' ];
385
-				$sql_params[] = $query[ 'per_page' ];
386
-			}
387
-		}
388
-
389
-		if ( ! empty( $sql_params ) ) {
390
-			$sql = $wpdb->prepare( $sql, $sql_params );
391
-		}
392
-
393
-		return $sql;
394
-	}
395
-
396
-	/**
397
-	 * Query for action count of list of action IDs.
398
-	 *
399
-	 * @param array  $query Query parameters.
400
-	 * @param string $query_type Whether to select or count the results. Default, select.
401
-	 *
402
-	 * @return null|string|array The IDs of actions matching the query
403
-	 */
404
-	public function query_actions( $query = [], $query_type = 'select' ) {
405
-		/** @var wpdb $wpdb */
406
-		global $wpdb;
407
-
408
-		$sql = $this->get_query_actions_sql( $query, $query_type );
409
-
410
-		return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
411
-	}
412
-
413
-	/**
414
-	 * Get a count of all actions in the store, grouped by status.
415
-	 *
416
-	 * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
417
-	 */
418
-	public function action_counts() {
419
-		global $wpdb;
420
-
421
-		$sql  = "SELECT a.status, count(a.status) as 'count'";
422
-		$sql .= " FROM {$wpdb->actionscheduler_actions} a";
423
-		$sql .= " GROUP BY a.status";
424
-
425
-		$actions_count_by_status = array();
426
-		$action_stati_and_labels = $this->get_status_labels();
427
-
428
-		foreach ( $wpdb->get_results( $sql ) as $action_data ) {
429
-			// Ignore any actions with invalid status
430
-			if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) {
431
-				$actions_count_by_status[ $action_data->status ] = $action_data->count;
432
-			}
433
-		}
434
-
435
-		return $actions_count_by_status;
436
-	}
437
-
438
-	/**
439
-	 * Cancel an action.
440
-	 *
441
-	 * @param int $action_id Action ID.
442
-	 *
443
-	 * @return void
444
-	 */
445
-	public function cancel_action( $action_id ) {
446
-		/** @var \wpdb $wpdb */
447
-		global $wpdb;
448
-
449
-		$updated = $wpdb->update(
450
-			$wpdb->actionscheduler_actions,
451
-			[ 'status' => self::STATUS_CANCELED ],
452
-			[ 'action_id' => $action_id ],
453
-			[ '%s' ],
454
-			[ '%d' ]
455
-		);
456
-		if ( empty( $updated ) ) {
457
-			/* translators: %s: action ID */
458
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
459
-		}
460
-		do_action( 'action_scheduler_canceled_action', $action_id );
461
-	}
462
-
463
-	/**
464
-	 * Cancel pending actions by hook.
465
-	 *
466
-	 * @since 3.0.0
467
-	 *
468
-	 * @param string $hook Hook name.
469
-	 *
470
-	 * @return void
471
-	 */
472
-	public function cancel_actions_by_hook( $hook ) {
473
-		$this->bulk_cancel_actions( [ 'hook' => $hook ] );
474
-	}
475
-
476
-	/**
477
-	 * Cancel pending actions by group.
478
-	 *
479
-	 * @param string $group Group slug.
480
-	 *
481
-	 * @return void
482
-	 */
483
-	public function cancel_actions_by_group( $group ) {
484
-		$this->bulk_cancel_actions( [ 'group' => $group ] );
485
-	}
486
-
487
-	/**
488
-	 * Bulk cancel actions.
489
-	 *
490
-	 * @since 3.0.0
491
-	 *
492
-	 * @param array $query_args Query parameters.
493
-	 */
494
-	protected function bulk_cancel_actions( $query_args ) {
495
-		/** @var \wpdb $wpdb */
496
-		global $wpdb;
497
-
498
-		if ( ! is_array( $query_args ) ) {
499
-			return;
500
-		}
501
-
502
-		// Don't cancel actions that are already canceled.
503
-		if ( isset( $query_args['status'] ) && $query_args['status'] == self::STATUS_CANCELED ) {
504
-			return;
505
-		}
506
-
507
-		$action_ids = true;
508
-		$query_args = wp_parse_args(
509
-			$query_args,
510
-			[
511
-				'per_page' => 1000,
512
-				'status' => self::STATUS_PENDING,
513
-			]
514
-		);
515
-
516
-		while ( $action_ids ) {
517
-			$action_ids = $this->query_actions( $query_args );
518
-			if ( empty( $action_ids ) ) {
519
-				break;
520
-			}
521
-
522
-			$format     = array_fill( 0, count( $action_ids ), '%d' );
523
-			$query_in   = '(' . implode( ',', $format ) . ')';
524
-			$parameters = $action_ids;
525
-			array_unshift( $parameters, self::STATUS_CANCELED );
526
-
527
-			$wpdb->query(
528
-				$wpdb->prepare( // wpcs: PreparedSQLPlaceholders replacement count ok.
529
-					"UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}",
530
-					$parameters
531
-				)
532
-			);
533
-
534
-			do_action( 'action_scheduler_bulk_cancel_actions', $action_ids );
535
-		}
536
-	}
537
-
538
-	/**
539
-	 * Delete an action.
540
-	 *
541
-	 * @param int $action_id Action ID.
542
-	 */
543
-	public function delete_action( $action_id ) {
544
-		/** @var \wpdb $wpdb */
545
-		global $wpdb;
546
-		$deleted = $wpdb->delete( $wpdb->actionscheduler_actions, [ 'action_id' => $action_id ], [ '%d' ] );
547
-		if ( empty( $deleted ) ) {
548
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
549
-		}
550
-		do_action( 'action_scheduler_deleted_action', $action_id );
551
-	}
552
-
553
-	/**
554
-	 * Get the schedule date for an action.
555
-	 *
556
-	 * @param string $action_id Action ID.
557
-	 *
558
-	 * @throws \InvalidArgumentException
559
-	 * @return \DateTime The local date the action is scheduled to run, or the date that it ran.
560
-	 */
561
-	public function get_date( $action_id ) {
562
-		$date = $this->get_date_gmt( $action_id );
563
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
564
-		return $date;
565
-	}
566
-
567
-	/**
568
-	 * Get the GMT schedule date for an action.
569
-	 *
570
-	 * @param int $action_id Action ID.
571
-	 *
572
-	 * @throws \InvalidArgumentException
573
-	 * @return \DateTime The GMT date the action is scheduled to run, or the date that it ran.
574
-	 */
575
-	protected function get_date_gmt( $action_id ) {
576
-		/** @var \wpdb $wpdb */
577
-		global $wpdb;
578
-		$record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) );
579
-		if ( empty( $record ) ) {
580
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
581
-		}
582
-		if ( $record->status == self::STATUS_PENDING ) {
583
-			return as_get_datetime_object( $record->scheduled_date_gmt );
584
-		} else {
585
-			return as_get_datetime_object( $record->last_attempt_gmt );
586
-		}
587
-	}
588
-
589
-	/**
590
-	 * Stake a claim on actions.
591
-	 *
592
-	 * @param int       $max_actions Maximum number of action to include in claim.
593
-	 * @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now.
594
-	 *
595
-	 * @return ActionScheduler_ActionClaim
596
-	 */
597
-	public function stake_claim( $max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
598
-		$claim_id = $this->generate_claim_id();
599
-		$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
600
-		$action_ids = $this->find_actions_by_claim_id( $claim_id );
601
-
602
-		return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
603
-	}
604
-
605
-	/**
606
-	 * Generate a new action claim.
607
-	 *
608
-	 * @return int Claim ID.
609
-	 */
610
-	protected function generate_claim_id() {
611
-		/** @var \wpdb $wpdb */
612
-		global $wpdb;
613
-		$now = as_get_datetime_object();
614
-		$wpdb->insert( $wpdb->actionscheduler_claims, [ 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ] );
615
-
616
-		return $wpdb->insert_id;
617
-	}
618
-
619
-	/**
620
-	 * Mark actions claimed.
621
-	 *
622
-	 * @param string    $claim_id Claim Id.
623
-	 * @param int       $limit Number of action to include in claim.
624
-	 * @param \DateTime $before_date Should use UTC timezone.
625
-	 *
626
-	 * @return int The number of actions that were claimed.
627
-	 * @throws \RuntimeException
628
-	 */
629
-	protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
630
-		/** @var \wpdb $wpdb */
631
-		global $wpdb;
632
-
633
-		$now  = as_get_datetime_object();
634
-		$date = is_null( $before_date ) ? $now : clone $before_date;
635
-
636
-		// can't use $wpdb->update() because of the <= condition
637
-		$update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
638
-		$params = array(
639
-			$claim_id,
640
-			$now->format( 'Y-m-d H:i:s' ),
641
-			current_time( 'mysql' ),
642
-		);
643
-
644
-		$where    = "WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s";
645
-		$params[] = $date->format( 'Y-m-d H:i:s' );
646
-		$params[] = self::STATUS_PENDING;
647
-
648
-		if ( ! empty( $hooks ) ) {
649
-			$placeholders = array_fill( 0, count( $hooks ), '%s' );
650
-			$where       .= ' AND hook IN (' . join( ', ', $placeholders ) . ')';
651
-			$params       = array_merge( $params, array_values( $hooks ) );
652
-		}
653
-
654
-		if ( ! empty( $group ) ) {
655
-
656
-			$group_id = $this->get_group_id( $group, false );
657
-
658
-			// throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour
659
-			if ( empty( $group_id ) ) {
660
-				/* translators: %s: group name */
661
-				throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
662
-			}
663
-
664
-			$where   .= ' AND group_id = %d';
665
-			$params[] = $group_id;
666
-		}
667
-
668
-		$order    = "ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC LIMIT %d";
669
-		$params[] = $limit;
670
-
671
-		$sql = $wpdb->prepare( "{$update} {$where} {$order}", $params );
672
-
673
-		$rows_affected = $wpdb->query( $sql );
674
-		if ( $rows_affected === false ) {
675
-			throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
676
-		}
677
-
678
-		return (int) $rows_affected;
679
-	}
680
-
681
-	/**
682
-	 * Get the number of active claims.
683
-	 *
684
-	 * @return int
685
-	 */
686
-	public function get_claim_count() {
687
-		global $wpdb;
688
-
689
-		$sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
690
-		$sql = $wpdb->prepare( $sql, [ self::STATUS_PENDING, self::STATUS_RUNNING ] );
691
-
692
-		return (int) $wpdb->get_var( $sql );
693
-	}
694
-
695
-	/**
696
-	 * Return an action's claim ID, as stored in the claim_id column.
697
-	 *
698
-	 * @param string $action_id Action ID.
699
-	 * @return mixed
700
-	 */
701
-	public function get_claim_id( $action_id ) {
702
-		/** @var \wpdb $wpdb */
703
-		global $wpdb;
704
-
705
-		$sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
706
-		$sql = $wpdb->prepare( $sql, $action_id );
707
-
708
-		return (int) $wpdb->get_var( $sql );
709
-	}
710
-
711
-	/**
712
-	 * Retrieve the action IDs of action in a claim.
713
-	 *
714
-	 * @param string $claim_id Claim ID.
715
-	 *
716
-	 * @return int[]
717
-	 */
718
-	public function find_actions_by_claim_id( $claim_id ) {
719
-		/** @var \wpdb $wpdb */
720
-		global $wpdb;
721
-
722
-		$sql = "SELECT action_id FROM {$wpdb->actionscheduler_actions} WHERE claim_id=%d";
723
-		$sql = $wpdb->prepare( $sql, $claim_id );
724
-
725
-		$action_ids = $wpdb->get_col( $sql );
726
-
727
-		return array_map( 'intval', $action_ids );
728
-	}
729
-
730
-	/**
731
-	 * Release actions from a claim and delete the claim.
732
-	 *
733
-	 * @param ActionScheduler_ActionClaim $claim Claim object.
734
-	 */
735
-	public function release_claim( ActionScheduler_ActionClaim $claim ) {
736
-		/** @var \wpdb $wpdb */
737
-		global $wpdb;
738
-		$wpdb->update( $wpdb->actionscheduler_actions, [ 'claim_id' => 0 ], [ 'claim_id' => $claim->get_id() ], [ '%d' ], [ '%d' ] );
739
-		$wpdb->delete( $wpdb->actionscheduler_claims, [ 'claim_id' => $claim->get_id() ], [ '%d' ] );
740
-	}
741
-
742
-	/**
743
-	 * Remove the claim from an action.
744
-	 *
745
-	 * @param int $action_id Action ID.
746
-	 *
747
-	 * @return void
748
-	 */
749
-	public function unclaim_action( $action_id ) {
750
-		/** @var \wpdb $wpdb */
751
-		global $wpdb;
752
-		$wpdb->update(
753
-			$wpdb->actionscheduler_actions,
754
-			[ 'claim_id' => 0 ],
755
-			[ 'action_id' => $action_id ],
756
-			[ '%s' ],
757
-			[ '%d' ]
758
-		);
759
-	}
760
-
761
-	/**
762
-	 * Mark an action as failed.
763
-	 *
764
-	 * @param int $action_id Action ID.
765
-	 */
766
-	public function mark_failure( $action_id ) {
767
-		/** @var \wpdb $wpdb */
768
-		global $wpdb;
769
-		$updated = $wpdb->update(
770
-			$wpdb->actionscheduler_actions,
771
-			[ 'status' => self::STATUS_FAILED ],
772
-			[ 'action_id' => $action_id ],
773
-			[ '%s' ],
774
-			[ '%d' ]
775
-		);
776
-		if ( empty( $updated ) ) {
777
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
778
-		}
779
-	}
780
-
781
-	/**
782
-	 * Add execution message to action log.
783
-	 *
784
-	 * @param int $action_id Action ID.
785
-	 *
786
-	 * @return void
787
-	 */
788
-	public function log_execution( $action_id ) {
789
-		/** @var \wpdb $wpdb */
790
-		global $wpdb;
791
-
792
-		$sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
793
-		$sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id );
794
-		$wpdb->query( $sql );
795
-	}
796
-
797
-	/**
798
-	 * Mark an action as complete.
799
-	 *
800
-	 * @param int $action_id Action ID.
801
-	 *
802
-	 * @return void
803
-	 */
804
-	public function mark_complete( $action_id ) {
805
-		/** @var \wpdb $wpdb */
806
-		global $wpdb;
807
-		$updated = $wpdb->update(
808
-			$wpdb->actionscheduler_actions,
809
-			[
810
-				'status'             => self::STATUS_COMPLETE,
811
-				'last_attempt_gmt'   => current_time( 'mysql', true ),
812
-				'last_attempt_local' => current_time( 'mysql' ),
813
-			],
814
-			[ 'action_id' => $action_id ],
815
-			[ '%s' ],
816
-			[ '%d' ]
817
-		);
818
-		if ( empty( $updated ) ) {
819
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
820
-		}
821
-	}
822
-
823
-	/**
824
-	 * Get an action's status.
825
-	 *
826
-	 * @param int $action_id Action ID.
827
-	 *
828
-	 * @return string
829
-	 */
830
-	public function get_status( $action_id ) {
831
-		/** @var \wpdb $wpdb */
832
-		global $wpdb;
833
-		$sql    = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
834
-		$sql    = $wpdb->prepare( $sql, $action_id );
835
-		$status = $wpdb->get_var( $sql );
836
-
837
-		if ( $status === null ) {
838
-			throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
839
-		} elseif ( empty( $status ) ) {
840
-			throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) );
841
-		} else {
842
-			return $status;
843
-		}
844
-	}
12
+    /** @var int */
13
+    protected static $max_args_length = 8000;
14
+
15
+    /** @var int */
16
+    protected static $max_index_length = 191;
17
+
18
+    /**
19
+     * Initialize the data store
20
+     *
21
+     * @codeCoverageIgnore
22
+     */
23
+    public function init() {
24
+        $table_maker = new ActionScheduler_StoreSchema();
25
+        $table_maker->register_tables();
26
+    }
27
+
28
+    /**
29
+     * Save an action.
30
+     *
31
+     * @param ActionScheduler_Action $action Action object.
32
+     * @param DateTime               $date Optional schedule date. Default null.
33
+     *
34
+     * @return int Action ID.
35
+     */
36
+    public function save_action( ActionScheduler_Action $action, \DateTime $date = null ) {
37
+        try {
38
+
39
+            $this->validate_action( $action );
40
+
41
+            /** @var \wpdb $wpdb */
42
+            global $wpdb;
43
+            $data = [
44
+                'hook'                 => $action->get_hook(),
45
+                'status'               => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ),
46
+                'scheduled_date_gmt'   => $this->get_scheduled_date_string( $action, $date ),
47
+                'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ),
48
+                'schedule'             => serialize( $action->get_schedule() ),
49
+                'group_id'             => $this->get_group_id( $action->get_group() ),
50
+            ];
51
+            $args = wp_json_encode( $action->get_args() );
52
+            if ( strlen( $args ) <= static::$max_index_length ) {
53
+                $data['args'] = $args;
54
+            } else {
55
+                $data['args']          = $this->hash_args( $args );
56
+                $data['extended_args'] = $args;
57
+            }
58
+
59
+            $table_name = ! empty( $wpdb->actionscheduler_actions ) ? $wpdb->actionscheduler_actions : $wpdb->prefix . 'actionscheduler_actions';
60
+            $wpdb->insert( $table_name, $data );
61
+            $action_id = $wpdb->insert_id;
62
+
63
+            if ( is_wp_error( $action_id ) ) {
64
+                throw new RuntimeException( $action_id->get_error_message() );
65
+            }
66
+            elseif ( empty( $action_id ) ) {
67
+                throw new RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
68
+            }
69
+
70
+            do_action( 'action_scheduler_stored_action', $action_id );
71
+
72
+            return $action_id;
73
+        } catch ( \Exception $e ) {
74
+            /* translators: %s: error message */
75
+            throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
76
+        }
77
+    }
78
+
79
+    /**
80
+     * Generate a hash from json_encoded $args using MD5 as this isn't for security.
81
+     *
82
+     * @param string $args JSON encoded action args.
83
+     * @return string
84
+     */
85
+    protected function hash_args( $args ) {
86
+        return md5( $args );
87
+    }
88
+
89
+    /**
90
+     * Get action args query param value from action args.
91
+     *
92
+     * @param array $args Action args.
93
+     * @return string
94
+     */
95
+    protected function get_args_for_query( $args ) {
96
+        $encoded = wp_json_encode( $args );
97
+        if ( strlen( $encoded ) <= static::$max_index_length ) {
98
+            return $encoded;
99
+        }
100
+        return $this->hash_args( $encoded );
101
+    }
102
+    /**
103
+     * Get a group's ID based on its name/slug.
104
+     *
105
+     * @param string $slug The string name of a group.
106
+     * @param bool $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group.
107
+     *
108
+     * @return int The group's ID, if it exists or is created, or 0 if it does not exist and is not created.
109
+     */
110
+    protected function get_group_id( $slug, $create_if_not_exists = true ) {
111
+        if ( empty( $slug ) ) {
112
+            return 0;
113
+        }
114
+        /** @var \wpdb $wpdb */
115
+        global $wpdb;
116
+        $group_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT group_id FROM {$wpdb->actionscheduler_groups} WHERE slug=%s", $slug ) );
117
+        if ( empty( $group_id ) && $create_if_not_exists ) {
118
+            $group_id = $this->create_group( $slug );
119
+        }
120
+
121
+        return $group_id;
122
+    }
123
+
124
+    /**
125
+     * Create an action group.
126
+     *
127
+     * @param string $slug Group slug.
128
+     *
129
+     * @return int Group ID.
130
+     */
131
+    protected function create_group( $slug ) {
132
+        /** @var \wpdb $wpdb */
133
+        global $wpdb;
134
+        $wpdb->insert( $wpdb->actionscheduler_groups, [ 'slug' => $slug ] );
135
+
136
+        return (int) $wpdb->insert_id;
137
+    }
138
+
139
+    /**
140
+     * Retrieve an action.
141
+     *
142
+     * @param int $action_id Action ID.
143
+     *
144
+     * @return ActionScheduler_Action
145
+     */
146
+    public function fetch_action( $action_id ) {
147
+        /** @var \wpdb $wpdb */
148
+        global $wpdb;
149
+        $data = $wpdb->get_row( $wpdb->prepare(
150
+            "SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d",
151
+            $action_id
152
+        ) );
153
+
154
+        if ( empty( $data ) ) {
155
+            return $this->get_null_action();
156
+        }
157
+
158
+        if ( ! empty( $data->extended_args ) ) {
159
+            $data->args = $data->extended_args;
160
+            unset( $data->extended_args );
161
+        }
162
+
163
+        try {
164
+            $action = $this->make_action_from_db_record( $data );
165
+        } catch ( ActionScheduler_InvalidActionException $exception ) {
166
+            do_action( 'action_scheduler_failed_fetch_action', $action_id, $exception );
167
+            return $this->get_null_action();
168
+        }
169
+
170
+        return $action;
171
+    }
172
+
173
+    /**
174
+     * Create a null action.
175
+     *
176
+     * @return ActionScheduler_NullAction
177
+     */
178
+    protected function get_null_action() {
179
+        return new ActionScheduler_NullAction();
180
+    }
181
+
182
+    /**
183
+     * Create an action from a database record.
184
+     *
185
+     * @param object $data Action database record.
186
+     *
187
+     * @return ActionScheduler_Action|ActionScheduler_CanceledAction|ActionScheduler_FinishedAction
188
+     */
189
+    protected function make_action_from_db_record( $data ) {
190
+
191
+        $hook     = $data->hook;
192
+        $args     = json_decode( $data->args, true );
193
+        $schedule = unserialize( $data->schedule );
194
+
195
+        $this->validate_args( $args, $data->action_id );
196
+        $this->validate_schedule( $schedule, $data->action_id );
197
+
198
+        if ( empty( $schedule ) ) {
199
+            $schedule = new ActionScheduler_NullSchedule();
200
+        }
201
+        $group = $data->group ? $data->group : '';
202
+
203
+        return ActionScheduler::factory()->get_stored_action( $data->status, $data->hook, $args, $schedule, $group );
204
+    }
205
+
206
+    /**
207
+     * Find an action.
208
+     *
209
+     * @param string $hook Action hook.
210
+     * @param array  $params Parameters of the action to find.
211
+     *
212
+     * @return string|null ID of the next action matching the criteria or NULL if not found.
213
+     */
214
+    public function find_action( $hook, $params = [] ) {
215
+        $params = wp_parse_args( $params, [
216
+            'args'   => null,
217
+            'status' => self::STATUS_PENDING,
218
+            'group'  => '',
219
+        ] );
220
+
221
+        /** @var wpdb $wpdb */
222
+        global $wpdb;
223
+        $query = "SELECT a.action_id FROM {$wpdb->actionscheduler_actions} a";
224
+        $args  = [];
225
+        if ( ! empty( $params[ 'group' ] ) ) {
226
+            $query  .= " INNER JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id AND g.slug=%s";
227
+            $args[] = $params[ 'group' ];
228
+        }
229
+        $query  .= " WHERE a.hook=%s";
230
+        $args[] = $hook;
231
+        if ( ! is_null( $params[ 'args' ] ) ) {
232
+            $query  .= " AND a.args=%s";
233
+            $args[] = $this->get_args_for_query( $params[ 'args' ] );
234
+        }
235
+
236
+        $order = 'ASC';
237
+        if ( ! empty( $params[ 'status' ] ) ) {
238
+            $query  .= " AND a.status=%s";
239
+            $args[] = $params[ 'status' ];
240
+
241
+            if ( self::STATUS_PENDING == $params[ 'status' ] ) {
242
+                $order = 'ASC'; // Find the next action that matches.
243
+            } else {
244
+                $order = 'DESC'; // Find the most recent action that matches.
245
+            }
246
+        }
247
+
248
+        $query .= " ORDER BY scheduled_date_gmt $order LIMIT 1";
249
+
250
+        $query = $wpdb->prepare( $query, $args );
251
+
252
+        $id = $wpdb->get_var( $query );
253
+
254
+        return $id;
255
+    }
256
+
257
+    /**
258
+     * Returns the SQL statement to query (or count) actions.
259
+     *
260
+     * @param array  $query Filtering options.
261
+     * @param string $select_or_count  Whether the SQL should select and return the IDs or just the row count.
262
+     *
263
+     * @return string SQL statement already properly escaped.
264
+     */
265
+    protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
266
+
267
+        if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
268
+            throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) );
269
+        }
270
+
271
+        $query = wp_parse_args( $query, [
272
+            'hook'             => '',
273
+            'args'             => null,
274
+            'date'             => null,
275
+            'date_compare'     => '<=',
276
+            'modified'         => null,
277
+            'modified_compare' => '<=',
278
+            'group'            => '',
279
+            'status'           => '',
280
+            'claimed'          => null,
281
+            'per_page'         => 5,
282
+            'offset'           => 0,
283
+            'orderby'          => 'date',
284
+            'order'            => 'ASC',
285
+        ] );
286
+
287
+        /** @var \wpdb $wpdb */
288
+        global $wpdb;
289
+        $sql  = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
290
+        $sql .= " FROM {$wpdb->actionscheduler_actions} a";
291
+        $sql_params = [];
292
+
293
+        if ( ! empty( $query[ 'group' ] ) || 'group' === $query[ 'orderby' ] ) {
294
+            $sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id";
295
+        }
296
+
297
+        $sql .= " WHERE 1=1";
298
+
299
+        if ( ! empty( $query[ 'group' ] ) ) {
300
+            $sql          .= " AND g.slug=%s";
301
+            $sql_params[] = $query[ 'group' ];
302
+        }
303
+
304
+        if ( $query[ 'hook' ] ) {
305
+            $sql          .= " AND a.hook=%s";
306
+            $sql_params[] = $query[ 'hook' ];
307
+        }
308
+        if ( ! is_null( $query[ 'args' ] ) ) {
309
+            $sql          .= " AND a.args=%s";
310
+            $sql_params[] = $this->get_args_for_query( $query[ 'args' ] );
311
+        }
312
+
313
+        if ( $query[ 'status' ] ) {
314
+            $sql          .= " AND a.status=%s";
315
+            $sql_params[] = $query[ 'status' ];
316
+        }
317
+
318
+        if ( $query[ 'date' ] instanceof \DateTime ) {
319
+            $date = clone $query[ 'date' ];
320
+            $date->setTimezone( new \DateTimeZone( 'UTC' ) );
321
+            $date_string  = $date->format( 'Y-m-d H:i:s' );
322
+            $comparator   = $this->validate_sql_comparator( $query[ 'date_compare' ] );
323
+            $sql          .= " AND a.scheduled_date_gmt $comparator %s";
324
+            $sql_params[] = $date_string;
325
+        }
326
+
327
+        if ( $query[ 'modified' ] instanceof \DateTime ) {
328
+            $modified = clone $query[ 'modified' ];
329
+            $modified->setTimezone( new \DateTimeZone( 'UTC' ) );
330
+            $date_string  = $modified->format( 'Y-m-d H:i:s' );
331
+            $comparator   = $this->validate_sql_comparator( $query[ 'modified_compare' ] );
332
+            $sql          .= " AND a.last_attempt_gmt $comparator %s";
333
+            $sql_params[] = $date_string;
334
+        }
335
+
336
+        if ( $query[ 'claimed' ] === true ) {
337
+            $sql .= " AND a.claim_id != 0";
338
+        } elseif ( $query[ 'claimed' ] === false ) {
339
+            $sql .= " AND a.claim_id = 0";
340
+        } elseif ( ! is_null( $query[ 'claimed' ] ) ) {
341
+            $sql          .= " AND a.claim_id = %d";
342
+            $sql_params[] = $query[ 'claimed' ];
343
+        }
344
+
345
+        if ( ! empty( $query['search'] ) ) {
346
+            $sql .= " AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s";
347
+            for( $i = 0; $i < 3; $i++ ) {
348
+                $sql_params[] = sprintf( '%%%s%%', $query['search'] );
349
+            }
350
+
351
+            $search_claim_id = (int) $query['search'];
352
+            if ( $search_claim_id ) {
353
+                $sql .= ' OR a.claim_id = %d';
354
+                $sql_params[] = $search_claim_id;
355
+            }
356
+
357
+            $sql .= ')';
358
+        }
359
+
360
+        if ( 'select' === $select_or_count ) {
361
+            switch ( $query['orderby'] ) {
362
+                case 'hook':
363
+                    $orderby = 'a.hook';
364
+                    break;
365
+                case 'group':
366
+                    $orderby = 'g.slug';
367
+                    break;
368
+                case 'modified':
369
+                    $orderby = 'a.last_attempt_gmt';
370
+                    break;
371
+                case 'date':
372
+                default:
373
+                    $orderby = 'a.scheduled_date_gmt';
374
+                    break;
375
+            }
376
+            if ( strtoupper( $query[ 'order' ] ) == 'ASC' ) {
377
+                $order = 'ASC';
378
+            } else {
379
+                $order = 'DESC';
380
+            }
381
+            $sql .= " ORDER BY $orderby $order";
382
+            if ( $query[ 'per_page' ] > 0 ) {
383
+                $sql          .= " LIMIT %d, %d";
384
+                $sql_params[] = $query[ 'offset' ];
385
+                $sql_params[] = $query[ 'per_page' ];
386
+            }
387
+        }
388
+
389
+        if ( ! empty( $sql_params ) ) {
390
+            $sql = $wpdb->prepare( $sql, $sql_params );
391
+        }
392
+
393
+        return $sql;
394
+    }
395
+
396
+    /**
397
+     * Query for action count of list of action IDs.
398
+     *
399
+     * @param array  $query Query parameters.
400
+     * @param string $query_type Whether to select or count the results. Default, select.
401
+     *
402
+     * @return null|string|array The IDs of actions matching the query
403
+     */
404
+    public function query_actions( $query = [], $query_type = 'select' ) {
405
+        /** @var wpdb $wpdb */
406
+        global $wpdb;
407
+
408
+        $sql = $this->get_query_actions_sql( $query, $query_type );
409
+
410
+        return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
411
+    }
412
+
413
+    /**
414
+     * Get a count of all actions in the store, grouped by status.
415
+     *
416
+     * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
417
+     */
418
+    public function action_counts() {
419
+        global $wpdb;
420
+
421
+        $sql  = "SELECT a.status, count(a.status) as 'count'";
422
+        $sql .= " FROM {$wpdb->actionscheduler_actions} a";
423
+        $sql .= " GROUP BY a.status";
424
+
425
+        $actions_count_by_status = array();
426
+        $action_stati_and_labels = $this->get_status_labels();
427
+
428
+        foreach ( $wpdb->get_results( $sql ) as $action_data ) {
429
+            // Ignore any actions with invalid status
430
+            if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) {
431
+                $actions_count_by_status[ $action_data->status ] = $action_data->count;
432
+            }
433
+        }
434
+
435
+        return $actions_count_by_status;
436
+    }
437
+
438
+    /**
439
+     * Cancel an action.
440
+     *
441
+     * @param int $action_id Action ID.
442
+     *
443
+     * @return void
444
+     */
445
+    public function cancel_action( $action_id ) {
446
+        /** @var \wpdb $wpdb */
447
+        global $wpdb;
448
+
449
+        $updated = $wpdb->update(
450
+            $wpdb->actionscheduler_actions,
451
+            [ 'status' => self::STATUS_CANCELED ],
452
+            [ 'action_id' => $action_id ],
453
+            [ '%s' ],
454
+            [ '%d' ]
455
+        );
456
+        if ( empty( $updated ) ) {
457
+            /* translators: %s: action ID */
458
+            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
459
+        }
460
+        do_action( 'action_scheduler_canceled_action', $action_id );
461
+    }
462
+
463
+    /**
464
+     * Cancel pending actions by hook.
465
+     *
466
+     * @since 3.0.0
467
+     *
468
+     * @param string $hook Hook name.
469
+     *
470
+     * @return void
471
+     */
472
+    public function cancel_actions_by_hook( $hook ) {
473
+        $this->bulk_cancel_actions( [ 'hook' => $hook ] );
474
+    }
475
+
476
+    /**
477
+     * Cancel pending actions by group.
478
+     *
479
+     * @param string $group Group slug.
480
+     *
481
+     * @return void
482
+     */
483
+    public function cancel_actions_by_group( $group ) {
484
+        $this->bulk_cancel_actions( [ 'group' => $group ] );
485
+    }
486
+
487
+    /**
488
+     * Bulk cancel actions.
489
+     *
490
+     * @since 3.0.0
491
+     *
492
+     * @param array $query_args Query parameters.
493
+     */
494
+    protected function bulk_cancel_actions( $query_args ) {
495
+        /** @var \wpdb $wpdb */
496
+        global $wpdb;
497
+
498
+        if ( ! is_array( $query_args ) ) {
499
+            return;
500
+        }
501
+
502
+        // Don't cancel actions that are already canceled.
503
+        if ( isset( $query_args['status'] ) && $query_args['status'] == self::STATUS_CANCELED ) {
504
+            return;
505
+        }
506
+
507
+        $action_ids = true;
508
+        $query_args = wp_parse_args(
509
+            $query_args,
510
+            [
511
+                'per_page' => 1000,
512
+                'status' => self::STATUS_PENDING,
513
+            ]
514
+        );
515
+
516
+        while ( $action_ids ) {
517
+            $action_ids = $this->query_actions( $query_args );
518
+            if ( empty( $action_ids ) ) {
519
+                break;
520
+            }
521
+
522
+            $format     = array_fill( 0, count( $action_ids ), '%d' );
523
+            $query_in   = '(' . implode( ',', $format ) . ')';
524
+            $parameters = $action_ids;
525
+            array_unshift( $parameters, self::STATUS_CANCELED );
526
+
527
+            $wpdb->query(
528
+                $wpdb->prepare( // wpcs: PreparedSQLPlaceholders replacement count ok.
529
+                    "UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}",
530
+                    $parameters
531
+                )
532
+            );
533
+
534
+            do_action( 'action_scheduler_bulk_cancel_actions', $action_ids );
535
+        }
536
+    }
537
+
538
+    /**
539
+     * Delete an action.
540
+     *
541
+     * @param int $action_id Action ID.
542
+     */
543
+    public function delete_action( $action_id ) {
544
+        /** @var \wpdb $wpdb */
545
+        global $wpdb;
546
+        $deleted = $wpdb->delete( $wpdb->actionscheduler_actions, [ 'action_id' => $action_id ], [ '%d' ] );
547
+        if ( empty( $deleted ) ) {
548
+            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
549
+        }
550
+        do_action( 'action_scheduler_deleted_action', $action_id );
551
+    }
552
+
553
+    /**
554
+     * Get the schedule date for an action.
555
+     *
556
+     * @param string $action_id Action ID.
557
+     *
558
+     * @throws \InvalidArgumentException
559
+     * @return \DateTime The local date the action is scheduled to run, or the date that it ran.
560
+     */
561
+    public function get_date( $action_id ) {
562
+        $date = $this->get_date_gmt( $action_id );
563
+        ActionScheduler_TimezoneHelper::set_local_timezone( $date );
564
+        return $date;
565
+    }
566
+
567
+    /**
568
+     * Get the GMT schedule date for an action.
569
+     *
570
+     * @param int $action_id Action ID.
571
+     *
572
+     * @throws \InvalidArgumentException
573
+     * @return \DateTime The GMT date the action is scheduled to run, or the date that it ran.
574
+     */
575
+    protected function get_date_gmt( $action_id ) {
576
+        /** @var \wpdb $wpdb */
577
+        global $wpdb;
578
+        $record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) );
579
+        if ( empty( $record ) ) {
580
+            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
581
+        }
582
+        if ( $record->status == self::STATUS_PENDING ) {
583
+            return as_get_datetime_object( $record->scheduled_date_gmt );
584
+        } else {
585
+            return as_get_datetime_object( $record->last_attempt_gmt );
586
+        }
587
+    }
588
+
589
+    /**
590
+     * Stake a claim on actions.
591
+     *
592
+     * @param int       $max_actions Maximum number of action to include in claim.
593
+     * @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now.
594
+     *
595
+     * @return ActionScheduler_ActionClaim
596
+     */
597
+    public function stake_claim( $max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
598
+        $claim_id = $this->generate_claim_id();
599
+        $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
600
+        $action_ids = $this->find_actions_by_claim_id( $claim_id );
601
+
602
+        return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
603
+    }
604
+
605
+    /**
606
+     * Generate a new action claim.
607
+     *
608
+     * @return int Claim ID.
609
+     */
610
+    protected function generate_claim_id() {
611
+        /** @var \wpdb $wpdb */
612
+        global $wpdb;
613
+        $now = as_get_datetime_object();
614
+        $wpdb->insert( $wpdb->actionscheduler_claims, [ 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ] );
615
+
616
+        return $wpdb->insert_id;
617
+    }
618
+
619
+    /**
620
+     * Mark actions claimed.
621
+     *
622
+     * @param string    $claim_id Claim Id.
623
+     * @param int       $limit Number of action to include in claim.
624
+     * @param \DateTime $before_date Should use UTC timezone.
625
+     *
626
+     * @return int The number of actions that were claimed.
627
+     * @throws \RuntimeException
628
+     */
629
+    protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
630
+        /** @var \wpdb $wpdb */
631
+        global $wpdb;
632
+
633
+        $now  = as_get_datetime_object();
634
+        $date = is_null( $before_date ) ? $now : clone $before_date;
635
+
636
+        // can't use $wpdb->update() because of the <= condition
637
+        $update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
638
+        $params = array(
639
+            $claim_id,
640
+            $now->format( 'Y-m-d H:i:s' ),
641
+            current_time( 'mysql' ),
642
+        );
643
+
644
+        $where    = "WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s";
645
+        $params[] = $date->format( 'Y-m-d H:i:s' );
646
+        $params[] = self::STATUS_PENDING;
647
+
648
+        if ( ! empty( $hooks ) ) {
649
+            $placeholders = array_fill( 0, count( $hooks ), '%s' );
650
+            $where       .= ' AND hook IN (' . join( ', ', $placeholders ) . ')';
651
+            $params       = array_merge( $params, array_values( $hooks ) );
652
+        }
653
+
654
+        if ( ! empty( $group ) ) {
655
+
656
+            $group_id = $this->get_group_id( $group, false );
657
+
658
+            // throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour
659
+            if ( empty( $group_id ) ) {
660
+                /* translators: %s: group name */
661
+                throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
662
+            }
663
+
664
+            $where   .= ' AND group_id = %d';
665
+            $params[] = $group_id;
666
+        }
667
+
668
+        $order    = "ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC LIMIT %d";
669
+        $params[] = $limit;
670
+
671
+        $sql = $wpdb->prepare( "{$update} {$where} {$order}", $params );
672
+
673
+        $rows_affected = $wpdb->query( $sql );
674
+        if ( $rows_affected === false ) {
675
+            throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
676
+        }
677
+
678
+        return (int) $rows_affected;
679
+    }
680
+
681
+    /**
682
+     * Get the number of active claims.
683
+     *
684
+     * @return int
685
+     */
686
+    public function get_claim_count() {
687
+        global $wpdb;
688
+
689
+        $sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
690
+        $sql = $wpdb->prepare( $sql, [ self::STATUS_PENDING, self::STATUS_RUNNING ] );
691
+
692
+        return (int) $wpdb->get_var( $sql );
693
+    }
694
+
695
+    /**
696
+     * Return an action's claim ID, as stored in the claim_id column.
697
+     *
698
+     * @param string $action_id Action ID.
699
+     * @return mixed
700
+     */
701
+    public function get_claim_id( $action_id ) {
702
+        /** @var \wpdb $wpdb */
703
+        global $wpdb;
704
+
705
+        $sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
706
+        $sql = $wpdb->prepare( $sql, $action_id );
707
+
708
+        return (int) $wpdb->get_var( $sql );
709
+    }
710
+
711
+    /**
712
+     * Retrieve the action IDs of action in a claim.
713
+     *
714
+     * @param string $claim_id Claim ID.
715
+     *
716
+     * @return int[]
717
+     */
718
+    public function find_actions_by_claim_id( $claim_id ) {
719
+        /** @var \wpdb $wpdb */
720
+        global $wpdb;
721
+
722
+        $sql = "SELECT action_id FROM {$wpdb->actionscheduler_actions} WHERE claim_id=%d";
723
+        $sql = $wpdb->prepare( $sql, $claim_id );
724
+
725
+        $action_ids = $wpdb->get_col( $sql );
726
+
727
+        return array_map( 'intval', $action_ids );
728
+    }
729
+
730
+    /**
731
+     * Release actions from a claim and delete the claim.
732
+     *
733
+     * @param ActionScheduler_ActionClaim $claim Claim object.
734
+     */
735
+    public function release_claim( ActionScheduler_ActionClaim $claim ) {
736
+        /** @var \wpdb $wpdb */
737
+        global $wpdb;
738
+        $wpdb->update( $wpdb->actionscheduler_actions, [ 'claim_id' => 0 ], [ 'claim_id' => $claim->get_id() ], [ '%d' ], [ '%d' ] );
739
+        $wpdb->delete( $wpdb->actionscheduler_claims, [ 'claim_id' => $claim->get_id() ], [ '%d' ] );
740
+    }
741
+
742
+    /**
743
+     * Remove the claim from an action.
744
+     *
745
+     * @param int $action_id Action ID.
746
+     *
747
+     * @return void
748
+     */
749
+    public function unclaim_action( $action_id ) {
750
+        /** @var \wpdb $wpdb */
751
+        global $wpdb;
752
+        $wpdb->update(
753
+            $wpdb->actionscheduler_actions,
754
+            [ 'claim_id' => 0 ],
755
+            [ 'action_id' => $action_id ],
756
+            [ '%s' ],
757
+            [ '%d' ]
758
+        );
759
+    }
760
+
761
+    /**
762
+     * Mark an action as failed.
763
+     *
764
+     * @param int $action_id Action ID.
765
+     */
766
+    public function mark_failure( $action_id ) {
767
+        /** @var \wpdb $wpdb */
768
+        global $wpdb;
769
+        $updated = $wpdb->update(
770
+            $wpdb->actionscheduler_actions,
771
+            [ 'status' => self::STATUS_FAILED ],
772
+            [ 'action_id' => $action_id ],
773
+            [ '%s' ],
774
+            [ '%d' ]
775
+        );
776
+        if ( empty( $updated ) ) {
777
+            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
778
+        }
779
+    }
780
+
781
+    /**
782
+     * Add execution message to action log.
783
+     *
784
+     * @param int $action_id Action ID.
785
+     *
786
+     * @return void
787
+     */
788
+    public function log_execution( $action_id ) {
789
+        /** @var \wpdb $wpdb */
790
+        global $wpdb;
791
+
792
+        $sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
793
+        $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id );
794
+        $wpdb->query( $sql );
795
+    }
796
+
797
+    /**
798
+     * Mark an action as complete.
799
+     *
800
+     * @param int $action_id Action ID.
801
+     *
802
+     * @return void
803
+     */
804
+    public function mark_complete( $action_id ) {
805
+        /** @var \wpdb $wpdb */
806
+        global $wpdb;
807
+        $updated = $wpdb->update(
808
+            $wpdb->actionscheduler_actions,
809
+            [
810
+                'status'             => self::STATUS_COMPLETE,
811
+                'last_attempt_gmt'   => current_time( 'mysql', true ),
812
+                'last_attempt_local' => current_time( 'mysql' ),
813
+            ],
814
+            [ 'action_id' => $action_id ],
815
+            [ '%s' ],
816
+            [ '%d' ]
817
+        );
818
+        if ( empty( $updated ) ) {
819
+            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
820
+        }
821
+    }
822
+
823
+    /**
824
+     * Get an action's status.
825
+     *
826
+     * @param int $action_id Action ID.
827
+     *
828
+     * @return string
829
+     */
830
+    public function get_status( $action_id ) {
831
+        /** @var \wpdb $wpdb */
832
+        global $wpdb;
833
+        $sql    = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
834
+        $sql    = $wpdb->prepare( $sql, $action_id );
835
+        $status = $wpdb->get_var( $sql );
836
+
837
+        if ( $status === null ) {
838
+            throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
839
+        } elseif ( empty( $status ) ) {
840
+            throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) );
841
+        } else {
842
+            return $status;
843
+        }
844
+    }
845 845
 }
Please login to merge, or discard this patch.