| 1 |
<?php |
| 2 |
/** |
| 3 |
* Schema of the follow-up table. |
| 4 |
* |
| 5 |
* @package Forge12\DoubleOptIn\Repository |
| 6 |
* @since 5.6.0 |
| 7 |
*/ |
| 8 |
|
| 9 |
declare( strict_types=1 ); |
| 10 |
|
| 11 |
namespace Forge12\DoubleOptIn\Repository; |
| 12 |
|
| 13 |
if ( ! defined( 'ABSPATH' ) ) { |
| 14 |
exit; |
| 15 |
} |
| 16 |
|
| 17 |
/** |
| 18 |
* Creates / updates `{prefix}f12_cf7_doubleoptin_followup`. |
| 19 |
* |
| 20 |
* Called from the activation hook, the `OnUpdate` ladder and its |
| 21 |
* "table missing" safety net — the same three places as the other core |
| 22 |
* tables, so a restored backup or a manual file upload heals itself. |
| 23 |
* |
| 24 |
* No form data is stored here. The row references the opt-in by id; |
| 25 |
* the payload stays in the opt-in row where retention and deletion |
| 26 |
* already apply to it. |
| 27 |
*/ |
| 28 |
final class FollowUpSchema { |
| 29 |
|
| 30 |
public const TABLE_NAME = 'f12_cf7_doubleoptin_followup'; |
| 31 |
|
| 32 |
/** |
| 33 |
* Run dbDelta for the current blog. |
| 34 |
*/ |
| 35 |
public static function install(): void { |
| 36 |
global $wpdb; |
| 37 |
|
| 38 |
if ( ! function_exists( 'dbDelta' ) ) { |
| 39 |
require_once ABSPATH . 'wp-admin/includes/upgrade.php'; |
| 40 |
} |
| 41 |
|
| 42 |
$table = $wpdb->prefix . self::TABLE_NAME; |
| 43 |
$charset = $wpdb->get_charset_collate(); |
| 44 |
|
| 45 |
// dbDelta formatting rules: two spaces after PRIMARY KEY, one |
| 46 |
// column per line, KEY instead of INDEX. |
| 47 |
$sql = "CREATE TABLE {$table} ( |
| 48 |
id bigint(20) unsigned NOT NULL auto_increment, |
| 49 |
optin_id bigint(20) unsigned NOT NULL, |
| 50 |
integration varchar(50) NOT NULL DEFAULT '', |
| 51 |
action_id varchar(100) NOT NULL, |
| 52 |
action_kind varchar(20) NOT NULL DEFAULT '', |
| 53 |
action_label varchar(190) NOT NULL DEFAULT '', |
| 54 |
config_fingerprint char(64) NOT NULL DEFAULT '', |
| 55 |
status varchar(24) NOT NULL DEFAULT 'pending', |
| 56 |
attempts int(11) unsigned NOT NULL DEFAULT 0, |
| 57 |
budget_attempts int(11) unsigned NOT NULL DEFAULT 0, |
| 58 |
attempt_id varchar(64) NOT NULL DEFAULT '', |
| 59 |
attempt_trigger varchar(20) NOT NULL DEFAULT '', |
| 60 |
started_at datetime DEFAULT NULL, |
| 61 |
finished_at datetime DEFAULT NULL, |
| 62 |
next_attempt_at datetime DEFAULT NULL, |
| 63 |
lease_until datetime DEFAULT NULL, |
| 64 |
error_code varchar(64) NOT NULL DEFAULT '', |
| 65 |
retryable tinyint(1) NOT NULL DEFAULT 0, |
| 66 |
http_status smallint(5) unsigned NOT NULL DEFAULT 0, |
| 67 |
response_kind varchar(24) NOT NULL DEFAULT '', |
| 68 |
entry_ref varchar(100) NOT NULL DEFAULT '', |
| 69 |
evidence varchar(64) NOT NULL DEFAULT '', |
| 70 |
ticket_hash char(64) DEFAULT NULL, |
| 71 |
ticket_expires datetime DEFAULT NULL, |
| 72 |
created_at datetime NOT NULL, |
| 73 |
updated_at datetime NOT NULL, |
| 74 |
PRIMARY KEY (id), |
| 75 |
UNIQUE KEY optin_action (optin_id,action_id), |
| 76 |
KEY status_next (status,next_attempt_at), |
| 77 |
KEY status_lease (status,lease_until) |
| 78 |
) {$charset};"; |
| 79 |
|
| 80 |
dbDelta( $sql ); |
| 81 |
} |
| 82 |
|
| 83 |
/** |
| 84 |
* Whether the table exists and has the newest column. Cheap enough |
| 85 |
* for the OnUpdate safety net, which runs on every load: one |
| 86 |
* SHOW COLUMNS … LIKE against a small table. |
| 87 |
*/ |
| 88 |
public static function isCurrent(): bool { |
| 89 |
global $wpdb; |
| 90 |
if ( ! self::exists() ) { |
| 91 |
return false; |
| 92 |
} |
| 93 |
$table = $wpdb->prefix . self::TABLE_NAME; |
| 94 |
return (bool) $wpdb->get_var( $wpdb->prepare( "SHOW COLUMNS FROM {$table} LIKE %s", 'budget_attempts' ) ); |
| 95 |
} |
| 96 |
|
| 97 |
/** |
| 98 |
* Whether the table exists on the current blog. |
| 99 |
*/ |
| 100 |
public static function exists(): bool { |
| 101 |
global $wpdb; |
| 102 |
$table = $wpdb->prefix . self::TABLE_NAME; |
| 103 |
return $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table; |
| 104 |
} |
| 105 |
} |
| 106 |
|