PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 1.9.1
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v1.9.1
2.3.0 2.2.0 2.1.1 2.1.0 2.0.0 1.10.0 1.9.1 1.9.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 All 59 releases
storeengine / includes / sql-transaction.php

sql-transaction.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 1.9.1, at includes/sql-transaction.php

154 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * A SQL Transaction Handler to assist with starting, commiting and rolling back transactions.
4 * This class also closes off an active transaction before shutdown to allow for shutdown processes to write to the database.
5 */
6
7 namespace StoreEngine;
8
9 use StoreEngine\Classes\Exceptions\StoreEngineInvalidArgumentException;
10 use StoreEngine\Utils\Constants;
11 use StoreEngine\Utils\Helper;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 class SqlTransaction {
18
19 /**
20 * The query to run when a fatal shutdown occurs.
21 *
22 * @var string
23 */
24 public string $on_fatal = '';
25
26 /**
27 * The query to run if the PHP request ends without error.
28 *
29 * @var string
30 */
31 public string $on_shutdown = '';
32
33 /**
34 * Whether there's an active MYSQL transaction.
35 *
36 * @var bool
37 */
38 public bool $active_transaction = false;
39
40 /**
41 * Constructor.
42 *
43 * @param string<"commit"|"rollback"> $on_fatal Optional. The type of query to run on fatal shutdown if this transaction is still active. Can be 'rollback' or 'commit'. Default is 'rollback'.
44 * @param string<"commit"|"rollback"> $on_shutdown Optional. The type of query to run if a non-error shutdown occurs but there's still an active transaction. Can be 'rollback' or 'commit'. Default is 'commit'.
45 */
46 public function __construct( string $on_fatal = 'rollback', string $on_shutdown = 'commit' ) {
47
48 // Validate the $on_fatal and $on_shutdown parameters.
49 if ( 'commit' !== $on_fatal && 'rollback' !== $on_fatal ) {
50 _doing_it_wrong( __METHOD__, esc_html__( 'This method was called with an invalid parameter. The first argument ($on_fatal) should be "rollback" or "commit"', 'storeengine' ), '1.0.0' );
51 }
52
53 if ( 'commit' !== $on_shutdown && 'rollback' !== $on_shutdown ) {
54 _doing_it_wrong( __METHOD__, esc_html__( 'This method was called with an invalid parameter. The second argument ($on_shutdown) should be "rollback" or "commit"', 'storeengine' ), '1.0.0' );
55 }
56
57 $this->on_fatal = $on_fatal;
58 $this->on_shutdown = $on_shutdown;
59
60 // Ensure we close off this transaction on shutdown to allow other shutdown processes to save changes to the DB.
61 add_action( 'shutdown', [ $this, 'handle_shutdown' ], - 100 );
62 }
63
64 /**
65 * Starts a MYSQL Transaction.
66 */
67 public function start() {
68 self::transaction_query( 'start' );
69 $this->active_transaction = true;
70 }
71
72 /**
73 * Commits the MYSQL Transaction.
74 */
75 public function commit() {
76 self::transaction_query( 'commit' );
77 $this->active_transaction = false;
78 }
79
80 /**
81 * Rolls back any changes made during the MYSQL Transaction.
82 */
83 public function rollback() {
84 self::transaction_query( 'rollback' );
85 $this->active_transaction = false;
86 }
87
88 /**
89 * Closes out an active transaction depending on the type of shutdown.
90 *
91 * Shutdowns caused by a fatal will be rolledback or commited @see $this->on_fatal.
92 * Shutdowns caused by a natural PHP termination (no error) will be rolledback or commited. @see $this->on_shutdown.
93 */
94 public function handle_shutdown() {
95 if ( ! $this->active_transaction ) {
96 return;
97 }
98
99 $error = error_get_last();
100 $types = [
101 E_ERROR,
102 E_PARSE,
103 E_COMPILE_ERROR,
104 E_USER_ERROR,
105 E_RECOVERABLE_ERROR,
106 ];
107
108 if ( $error && in_array( $error['type'], $types, true ) ) {
109 $this->{$this->on_fatal}();
110 } else {
111 $this->{$this->on_shutdown}();
112 }
113 }
114
115 /**
116 * Run a MySQL transaction query, if supported.
117 *
118 * @param string<"start"|"commit"|"rollback"> $type Types: start (default), commit, rollback.
119 * @param bool $force use of transactions.
120 *
121 * @throws StoreEngineInvalidArgumentException
122 */
123 public static function transaction_query( string $type = 'start', bool $force = false ) {
124 global $wpdb;
125
126 $allowed = [ 'start', 'commit', 'rollback' ];
127
128 if ( ! in_array( $type, $allowed, true ) ) {
129 throw StoreEngineInvalidArgumentException::create( 1, 'type', $allowed, $type ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
130 }
131
132 $wpdb->hide_errors();
133
134 Helper::maybe_define_constant( 'STOREENGINE_USE_TRANSACTIONS', true );
135
136 if ( Constants::is_true( 'STOREENGINE_USE_TRANSACTIONS' ) || $force ) {
137 // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
138 switch ( $type ) {
139 case 'commit':
140 $wpdb->query( 'COMMIT' );
141 break;
142 case 'rollback':
143 $wpdb->query( 'ROLLBACK' );
144 break;
145 case 'start':
146 default:
147 $wpdb->query( 'START TRANSACTION' );
148 break;
149 }
150 // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
151 }
152 }
153 }
154