PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.0
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.0
2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 All 68 releases
fluent-support / vendor / wpfluent / framework / src / WPFluent / Database / DatabaseTransactionsManager.php

DatabaseTransactionsManager.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.4.0, at vendor/wpfluent/framework/src/WPFluent/Database/DatabaseTransactionsManager.php

276 lines 8.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentSupport\Framework\Database;
4
5 use FluentSupport\Framework\Support\Collection;
6
7 class DatabaseTransactionsManager
8 {
9 /**
10 * All of the committed transactions.
11 *
12 * @var \FluentSupport\Framework\Support\Collection<int, \FluentSupport\Framework\Database\DatabaseTransactionRecord>
13 */
14 protected $committedTransactions;
15
16 /**
17 * All of the pending transactions.
18 *
19 * @var \FluentSupport\Framework\Support\Collection<int, \FluentSupport\Framework\Database\DatabaseTransactionRecord>
20 */
21 protected $pendingTransactions;
22
23 /**
24 * The current transaction.
25 *
26 * @var array
27 */
28 protected $currentTransaction = [];
29
30 /**
31 * Create a new database transactions manager instance.
32 */
33 public function __construct()
34 {
35 $this->committedTransactions = new Collection;
36 $this->pendingTransactions = new Collection;
37 }
38
39 /**
40 * Start a new database transaction.
41 *
42 * @param string $connection
43 * @param int $level
44 * @return void
45 */
46 public function begin($connection, $level)
47 {
48 $this->pendingTransactions->push(
49 $newTransaction = new DatabaseTransactionRecord(
50 $connection,
51 $level,
52 $this->currentTransaction[$connection] ?? null
53 )
54 );
55
56 $this->currentTransaction[$connection] = $newTransaction;
57 }
58
59 /**
60 * Commit the root database transaction and execute callbacks.
61 *
62 * @param string $connection
63 * @param int $levelBeingCommitted
64 * @param int $newTransactionLevel
65 * @return array
66 */
67 public function commit($connection, $levelBeingCommitted, $newTransactionLevel)
68 {
69 $this->stageTransactions($connection, $levelBeingCommitted);
70
71 if (isset($this->currentTransaction[$connection])) {
72 $this->currentTransaction[$connection] = $this->currentTransaction[$connection]->parent;
73 }
74
75 if (!$this->afterCommitCallbacksShouldBeExecuted($newTransactionLevel) &&
76 $newTransactionLevel !== 0) {
77 return [];
78 }
79
80 // This method is only called when the root database transaction is
81 // committed so there shouldn't be any pending transactions, but
82 // going to clear them here anyways just in case. This method
83 // could be refactored to receive a level in the future too.
84 $this->pendingTransactions = $this->pendingTransactions->reject(
85 fn ($transaction) => $transaction->connection === $connection &&
86 $transaction->level >= $levelBeingCommitted
87 )->values();
88
89 [$forThisConnection, $forOtherConnections] = $this->committedTransactions->partition(
90 fn ($transaction) => $transaction->connection == $connection
91 );
92
93 $this->committedTransactions = $forOtherConnections->values();
94
95 $forThisConnection->map->executeCallbacks();
96
97 return $forThisConnection;
98 }
99
100 /**
101 * Move relevant pending transactions to a committed state.
102 *
103 * @param string $connection
104 * @param int $levelBeingCommitted
105 * @return void
106 */
107 public function stageTransactions($connection, $levelBeingCommitted)
108 {
109 $this->committedTransactions = $this->committedTransactions->merge(
110 $this->pendingTransactions->filter(
111 fn ($transaction) => $transaction->connection === $connection &&
112 $transaction->level >= $levelBeingCommitted
113 )
114 );
115
116 $this->pendingTransactions = $this->pendingTransactions->reject(
117 fn ($transaction) => $transaction->connection === $connection &&
118 $transaction->level >= $levelBeingCommitted
119 );
120 }
121
122 /**
123 * Rollback the active database transaction.
124 *
125 * @param string $connection
126 * @param int $newTransactionLevel
127 * @return void
128 */
129 public function rollback($connection, $newTransactionLevel)
130 {
131 if ($newTransactionLevel === 0) {
132 $this->removeAllTransactionsForConnection($connection);
133 } else {
134 $this->pendingTransactions = $this->pendingTransactions->reject(
135 fn ($transaction) => $transaction->connection == $connection &&
136 $transaction->level > $newTransactionLevel
137 )->values();
138
139 if ($this->currentTransaction) {
140 do {
141 $this->removeCommittedTransactionsThatAreChildrenOf($this->currentTransaction[$connection]);
142
143 $this->currentTransaction[$connection]->executeCallbacksForRollback();
144
145 $this->currentTransaction[$connection] = $this->currentTransaction[$connection]->parent;
146 } while (
147 isset($this->currentTransaction[$connection]) &&
148 $this->currentTransaction[$connection]->level > $newTransactionLevel
149 );
150 }
151 }
152 }
153
154 /**
155 * Remove all pending, completed, and current transactions
156 * for the given connection name.
157 *
158 * @param string $connection
159 * @return void
160 */
161 protected function removeAllTransactionsForConnection($connection)
162 {
163 if ($this->currentTransaction) {
164 for (
165 $currentTransaction = $this->currentTransaction[$connection];
166 isset($currentTransaction);
167 $currentTransaction = $currentTransaction->parent
168 ) {
169 $currentTransaction->executeCallbacksForRollback();
170 }
171 }
172
173 $this->currentTransaction[$connection] = null;
174
175 $this->pendingTransactions = $this->pendingTransactions->reject(
176 fn ($transaction) => $transaction->connection == $connection
177 )->values();
178
179 $this->committedTransactions = $this->committedTransactions->reject(
180 fn ($transaction) => $transaction->connection == $connection
181 )->values();
182 }
183
184 /**
185 * Remove all transactions that are children of the given transaction.
186 *
187 * @param \FluentSupport\Framework\Database\DatabaseTransactionRecord $transaction
188 * @return void
189 */
190 protected function removeCommittedTransactionsThatAreChildrenOf(DatabaseTransactionRecord $transaction)
191 {
192 [$removedTransactions, $this->committedTransactions] = $this->committedTransactions->partition(
193 fn ($committed) => $committed->connection == $transaction->connection &&
194 $committed->parent === $transaction
195 );
196
197 // There may be multiple deeply nested transactions that have already
198 // committed that we also need to remove. We will recurse down the
199 // children of all removed transaction instances until there are
200 // no more deeply nested child transactions for removal.
201 $removedTransactions->each(
202 fn ($transaction) => $this->removeCommittedTransactionsThatAreChildrenOf($transaction)
203 );
204 }
205
206 /**
207 * Register a transaction callback.
208 *
209 * @param callable $callback
210 * @return void
211 */
212 public function addCallback($callback)
213 {
214 if ($current = $this->callbackApplicableTransactions()->last()) {
215 return $current->addCallback($callback);
216 }
217
218 $callback();
219 }
220
221 /**
222 * Register a callback for transaction rollback.
223 *
224 * @param callable $callback
225 * @return void
226 */
227 public function addCallbackForRollback($callback)
228 {
229 if ($current = $this->callbackApplicableTransactions()->last()) {
230 return $current->addCallbackForRollback($callback);
231 }
232 }
233
234 /**
235 * Get the transactions that are applicable to callbacks.
236 *
237 * @return \FluentSupport\Framework\Support\Collection<int, \FluentSupport\Framework\Database\DatabaseTransactionRecord>
238 */
239 public function callbackApplicableTransactions()
240 {
241 return $this->pendingTransactions;
242 }
243
244 /**
245 * Determine if after commit callbacks should be executed
246 * for the given transaction level.
247 *
248 * @param int $level
249 * @return bool
250 */
251 public function afterCommitCallbacksShouldBeExecuted($level)
252 {
253 return $level === 0;
254 }
255
256 /**
257 * Get all of the pending transactions.
258 *
259 * @return \FluentSupport\Framework\Support\Collection
260 */
261 public function getPendingTransactions()
262 {
263 return $this->pendingTransactions;
264 }
265
266 /**
267 * Get all of the committed transactions.
268 *
269 * @return \FluentSupport\Framework\Support\Collection
270 */
271 public function getCommittedTransactions()
272 {
273 return $this->committedTransactions;
274 }
275 }
276