File "ActionScheduler_DBStore.php"
Full path: /home/kosmetik/public_html/wp-content/plugins/woocommerce/packages/action-scheduler/classes/data-stores/ActionScheduler_DBStore.php
File
size: 18.96 B
MIME-type: text/x-php
Charset: utf-8
Download Open Edit Advanced Editor Back
<?php
class ActionScheduler_DBStore extends ActionScheduler_Store
{
private $claim_before_date = null;
protected static $max_args_length = 8000;
protected static $max_index_length = 191;
public function init()
{
$table_maker = new ActionScheduler_StoreSchema();
$table_maker->init();
$table_maker->register_tables();
}
public function save_action(ActionScheduler_Action $action, \DateTime $date = null)
{
try {
$this->validate_action($action);
global $wpdb;
$data = ['hook' => $action->get_hook(), 'status' => $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING, 'scheduled_date_gmt' => $this->get_scheduled_date_string($action, $date), 'scheduled_date_local' => $this->get_scheduled_date_string_local($action, $date), 'schedule' => serialize($action->get_schedule()), 'group_id' => $this->get_group_id($action->get_group())];
$args = wp_json_encode($action->get_args());
if (strlen($args) <= static::$max_index_length) {
$data['args'] = $args;
} else {
$data['args'] = $this->hash_args($args);
$data['extended_args'] = $args;
}
$table_name = !empty($wpdb->actionscheduler_actions) ? $wpdb->actionscheduler_actions : $wpdb->prefix . 'actionscheduler_actions';
$wpdb->insert($table_name, $data);
$action_id = $wpdb->insert_id;
if (is_wp_error($action_id)) {
throw new RuntimeException($action_id->get_error_message());
} elseif (empty($action_id)) {
throw new RuntimeException($wpdb->last_error ? $wpdb->last_error : __('Database error.', 'woocommerce'));
}
do_action('action_scheduler_stored_action', $action_id);
return $action_id;
} catch (\Exception $e) {
throw new \RuntimeException(sprintf(__('Error saving action: %s', 'woocommerce'), $e->getMessage()), 0);
}
}
protected function hash_args($args)
{
return md5($args);
}
protected function get_args_for_query($args)
{
$encoded = wp_json_encode($args);
if (strlen($encoded) <= static::$max_index_length) {
return $encoded;
}
return $this->hash_args($encoded);
}
protected function get_group_id($slug, $create_if_not_exists = true)
{
if (empty($slug)) {
return 0;
}
global $wpdb;
$group_id = (int) $wpdb->get_var($wpdb->prepare("SELECT group_id FROM {$wpdb->actionscheduler_groups} WHERE slug=%s", $slug));
if (empty($group_id) && $create_if_not_exists) {
$group_id = $this->create_group($slug);
}
return $group_id;
}
protected function create_group($slug)
{
global $wpdb;
$wpdb->insert($wpdb->actionscheduler_groups, ['slug' => $slug]);
return (int) $wpdb->insert_id;
}
public function fetch_action($action_id)
{
global $wpdb;
$data = $wpdb->get_row($wpdb->prepare("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", $action_id));
if (empty($data)) {
return $this->get_null_action();
}
if (!empty($data->extended_args)) {
$data->args = $data->extended_args;
unset($data->extended_args);
}
$date_fields = ['scheduled_date_gmt', 'scheduled_date_local', 'last_attempt_gmt', 'last_attempt_gmt'];
foreach ($date_fields as $date_field) {
if (is_null($data->{$date_field})) {
$data->{$date_field} = ActionScheduler_StoreSchema::DEFAULT_DATE;
}
}
try {
$action = $this->make_action_from_db_record($data);
} catch (ActionScheduler_InvalidActionException $exception) {
do_action('action_scheduler_failed_fetch_action', $action_id, $exception);
return $this->get_null_action();
}
return $action;
}
protected function get_null_action()
{
return new ActionScheduler_NullAction();
}
protected function make_action_from_db_record($data)
{
$hook = $data->hook;
$args = json_decode($data->args, true);
$schedule = unserialize($data->schedule);
$this->validate_args($args, $data->action_id);
$this->validate_schedule($schedule, $data->action_id);
if (empty($schedule)) {
$schedule = new ActionScheduler_NullSchedule();
}
$group = $data->group ? $data->group : '';
return ActionScheduler::factory()->get_stored_action($data->status, $data->hook, $args, $schedule, $group);
}
protected function get_query_actions_sql(array $query, $select_or_count = 'select')
{
if (!in_array($select_or_count, array('select', 'count'))) {
throw new InvalidArgumentException(__('Invalid value for select or count parameter. Cannot query actions.', 'woocommerce'));
}
$query = wp_parse_args($query, ['hook' => '', 'args' => null, 'date' => null, 'date_compare' => '<=', 'modified' => null, 'modified_compare' => '<=', 'group' => '', 'status' => '', 'claimed' => null, 'per_page' => 5, 'offset' => 0, 'orderby' => 'date', 'order' => 'ASC']);
global $wpdb;
$sql = 'count' === $select_or_count ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
$sql .= " FROM {$wpdb->actionscheduler_actions} a";
$sql_params = [];
if (!empty($query['group']) || 'group' === $query['orderby']) {
$sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id";
}
$sql .= " WHERE 1=1";
if (!empty($query['group'])) {
$sql .= " AND g.slug=%s";
$sql_params[] = $query['group'];
}
if ($query['hook']) {
$sql .= " AND a.hook=%s";
$sql_params[] = $query['hook'];
}
if (!is_null($query['args'])) {
$sql .= " AND a.args=%s";
$sql_params[] = $this->get_args_for_query($query['args']);
}
if ($query['status']) {
$statuses = (array) $query['status'];
$placeholders = array_fill(0, count($statuses), '%s');
$sql .= ' AND a.status IN (' . join(', ', $placeholders) . ')';
$sql_params = array_merge($sql_params, array_values($statuses));
}
if ($query['date'] instanceof \DateTime) {
$date = clone $query['date'];
$date->setTimezone(new \DateTimeZone('UTC'));
$date_string = $date->format('Y-m-d H:i:s');
$comparator = $this->validate_sql_comparator($query['date_compare']);
$sql .= " AND a.scheduled_date_gmt {$comparator} %s";
$sql_params[] = $date_string;
}
if ($query['modified'] instanceof \DateTime) {
$modified = clone $query['modified'];
$modified->setTimezone(new \DateTimeZone('UTC'));
$date_string = $modified->format('Y-m-d H:i:s');
$comparator = $this->validate_sql_comparator($query['modified_compare']);
$sql .= " AND a.last_attempt_gmt {$comparator} %s";
$sql_params[] = $date_string;
}
if ($query['claimed'] === true) {
$sql .= " AND a.claim_id != 0";
} elseif ($query['claimed'] === false) {
$sql .= " AND a.claim_id = 0";
} elseif (!is_null($query['claimed'])) {
$sql .= " AND a.claim_id = %d";
$sql_params[] = $query['claimed'];
}
if (!empty($query['search'])) {
$sql .= " AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s";
for ($i = 0; $i < 3; $i++) {
$sql_params[] = sprintf('%%%s%%', $query['search']);
}
$search_claim_id = (int) $query['search'];
if ($search_claim_id) {
$sql .= ' OR a.claim_id = %d';
$sql_params[] = $search_claim_id;
}
$sql .= ')';
}
if ('select' === $select_or_count) {
if ('ASC' === strtoupper($query['order'])) {
$order = 'ASC';
} else {
$order = 'DESC';
}
switch ($query['orderby']) {
case 'hook':
$sql .= " ORDER BY a.hook {$order}";
break;
case 'group':
$sql .= " ORDER BY g.slug {$order}";
break;
case 'modified':
$sql .= " ORDER BY a.last_attempt_gmt {$order}";
break;
case 'none':
break;
case 'action_id':
$sql .= " ORDER BY a.action_id {$order}";
break;
case 'date':
default:
$sql .= " ORDER BY a.scheduled_date_gmt {$order}";
break;
}
if ($query['per_page'] > 0) {
$sql .= " LIMIT %d, %d";
$sql_params[] = $query['offset'];
$sql_params[] = $query['per_page'];
}
}
if (!empty($sql_params)) {
$sql = $wpdb->prepare($sql, $sql_params);
}
return $sql;
}
public function query_actions($query = array(), $query_type = 'select')
{
global $wpdb;
$sql = $this->get_query_actions_sql($query, $query_type);
return 'count' === $query_type ? $wpdb->get_var($sql) : $wpdb->get_col($sql);
}
public function action_counts()
{
global $wpdb;
$sql = "SELECT a.status, count(a.status) as 'count'";
$sql .= " FROM {$wpdb->actionscheduler_actions} a";
$sql .= " GROUP BY a.status";
$actions_count_by_status = array();
$action_stati_and_labels = $this->get_status_labels();
foreach ($wpdb->get_results($sql) as $action_data) {
if (array_key_exists($action_data->status, $action_stati_and_labels)) {
$actions_count_by_status[$action_data->status] = $action_data->count;
}
}
return $actions_count_by_status;
}
public function cancel_action($action_id)
{
global $wpdb;
$updated = $wpdb->update($wpdb->actionscheduler_actions, ['status' => self::STATUS_CANCELED], ['action_id' => $action_id], ['%s'], ['%d']);
if (empty($updated)) {
throw new \InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
do_action('action_scheduler_canceled_action', $action_id);
}
public function cancel_actions_by_hook($hook)
{
$this->bulk_cancel_actions(['hook' => $hook]);
}
public function cancel_actions_by_group($group)
{
$this->bulk_cancel_actions(['group' => $group]);
}
protected function bulk_cancel_actions($query_args)
{
global $wpdb;
if (!is_array($query_args)) {
return;
}
if (isset($query_args['status']) && $query_args['status'] == self::STATUS_CANCELED) {
return;
}
$action_ids = true;
$query_args = wp_parse_args($query_args, ['per_page' => 1000, 'status' => self::STATUS_PENDING, 'orderby' => 'action_id']);
while ($action_ids) {
$action_ids = $this->query_actions($query_args);
if (empty($action_ids)) {
break;
}
$format = array_fill(0, count($action_ids), '%d');
$query_in = '(' . implode(',', $format) . ')';
$parameters = $action_ids;
array_unshift($parameters, self::STATUS_CANCELED);
$wpdb->query($wpdb->prepare("UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}", $parameters));
do_action('action_scheduler_bulk_cancel_actions', $action_ids);
}
}
public function delete_action($action_id)
{
global $wpdb;
$deleted = $wpdb->delete($wpdb->actionscheduler_actions, ['action_id' => $action_id], ['%d']);
if (empty($deleted)) {
throw new \InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
do_action('action_scheduler_deleted_action', $action_id);
}
public function get_date($action_id)
{
$date = $this->get_date_gmt($action_id);
ActionScheduler_TimezoneHelper::set_local_timezone($date);
return $date;
}
protected function get_date_gmt($action_id)
{
global $wpdb;
$record = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id));
if (empty($record)) {
throw new \InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
if ($record->status == self::STATUS_PENDING) {
return as_get_datetime_object($record->scheduled_date_gmt);
} else {
return as_get_datetime_object($record->last_attempt_gmt);
}
}
public function stake_claim($max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '')
{
$claim_id = $this->generate_claim_id();
$this->claim_before_date = $before_date;
$this->claim_actions($claim_id, $max_actions, $before_date, $hooks, $group);
$action_ids = $this->find_actions_by_claim_id($claim_id);
$this->claim_before_date = null;
return new ActionScheduler_ActionClaim($claim_id, $action_ids);
}
protected function generate_claim_id()
{
global $wpdb;
$now = as_get_datetime_object();
$wpdb->insert($wpdb->actionscheduler_claims, ['date_created_gmt' => $now->format('Y-m-d H:i:s')]);
return $wpdb->insert_id;
}
protected function claim_actions($claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '')
{
global $wpdb;
$now = as_get_datetime_object();
$date = is_null($before_date) ? $now : clone $before_date;
$update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
$params = array($claim_id, $now->format('Y-m-d H:i:s'), current_time('mysql'));
$where = "WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s";
$params[] = $date->format('Y-m-d H:i:s');
$params[] = self::STATUS_PENDING;
if (!empty($hooks)) {
$placeholders = array_fill(0, count($hooks), '%s');
$where .= ' AND hook IN (' . join(', ', $placeholders) . ')';
$params = array_merge($params, array_values($hooks));
}
if (!empty($group)) {
$group_id = $this->get_group_id($group, false);
if (empty($group_id)) {
throw new InvalidArgumentException(sprintf(__('The group "%s" does not exist.', 'woocommerce'), $group));
}
$where .= ' AND group_id = %d';
$params[] = $group_id;
}
$order = "ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC LIMIT %d";
$params[] = $limit;
$sql = $wpdb->prepare("{$update} {$where} {$order}", $params);
$rows_affected = $wpdb->query($sql);
if ($rows_affected === false) {
throw new \RuntimeException(__('Unable to claim actions. Database error.', 'woocommerce'));
}
return (int) $rows_affected;
}
public function get_claim_count()
{
global $wpdb;
$sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
$sql = $wpdb->prepare($sql, [self::STATUS_PENDING, self::STATUS_RUNNING]);
return (int) $wpdb->get_var($sql);
}
public function get_claim_id($action_id)
{
global $wpdb;
$sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
$sql = $wpdb->prepare($sql, $action_id);
return (int) $wpdb->get_var($sql);
}
public function find_actions_by_claim_id($claim_id)
{
global $wpdb;
$action_ids = array();
$before_date = isset($this->claim_before_date) ? $this->claim_before_date : as_get_datetime_object();
$cut_off = $before_date->format('Y-m-d H:i:s');
$sql = $wpdb->prepare("SELECT action_id, scheduled_date_gmt FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d", $claim_id);
foreach ($wpdb->get_results($sql) as $claimed_action) {
if ($claimed_action->scheduled_date_gmt <= $cut_off) {
$action_ids[] = absint($claimed_action->action_id);
}
}
return $action_ids;
}
public function release_claim(ActionScheduler_ActionClaim $claim)
{
global $wpdb;
$wpdb->update($wpdb->actionscheduler_actions, ['claim_id' => 0], ['claim_id' => $claim->get_id()], ['%d'], ['%d']);
$wpdb->delete($wpdb->actionscheduler_claims, ['claim_id' => $claim->get_id()], ['%d']);
}
public function unclaim_action($action_id)
{
global $wpdb;
$wpdb->update($wpdb->actionscheduler_actions, ['claim_id' => 0], ['action_id' => $action_id], ['%s'], ['%d']);
}
public function mark_failure($action_id)
{
global $wpdb;
$updated = $wpdb->update($wpdb->actionscheduler_actions, ['status' => self::STATUS_FAILED], ['action_id' => $action_id], ['%s'], ['%d']);
if (empty($updated)) {
throw new \InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
}
public function log_execution($action_id)
{
global $wpdb;
$sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
$sql = $wpdb->prepare($sql, self::STATUS_RUNNING, current_time('mysql', true), current_time('mysql'), $action_id);
$wpdb->query($sql);
}
public function mark_complete($action_id)
{
global $wpdb;
$updated = $wpdb->update($wpdb->actionscheduler_actions, ['status' => self::STATUS_COMPLETE, 'last_attempt_gmt' => current_time('mysql', true), 'last_attempt_local' => current_time('mysql')], ['action_id' => $action_id], ['%s'], ['%d']);
if (empty($updated)) {
throw new \InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
}
public function get_status($action_id)
{
global $wpdb;
$sql = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
$sql = $wpdb->prepare($sql, $action_id);
$status = $wpdb->get_var($sql);
if ($status === null) {
throw new \InvalidArgumentException(__('Invalid action ID. No status found.', 'woocommerce'));
} elseif (empty($status)) {
throw new \RuntimeException(__('Unknown status found for action.', 'woocommerce'));
} else {
return $status;
}
}
}