8
8
use MongoDB \Client ;
9
9
use MongoDB \Driver \Exception \RuntimeException ;
10
10
use MongoDB \Driver \Session ;
11
+ use MongoDB \Laravel \Connection ;
11
12
use Throwable ;
12
13
14
+ use function max ;
13
15
use function MongoDB \with_transaction ;
16
+ use function property_exists ;
14
17
15
18
/**
16
19
* @internal
@@ -55,32 +58,93 @@ private function getSessionOrThrow(): Session
55
58
*/
56
59
public function beginTransaction (array $ options = []): void
57
60
{
61
+ $ this ->runCallbacksBeforeTransaction ();
62
+
58
63
$ this ->getSessionOrCreate ()->startTransaction ($ options );
64
+
65
+ $ this ->handleInitialTransactionState ();
66
+ }
67
+
68
+ private function handleInitialTransactionState (): void
69
+ {
59
70
$ this ->transactions = 1 ;
71
+
72
+ $ this ->transactionsManager ?->begin(
73
+ $ this ->getName (),
74
+ $ this ->transactions ,
75
+ );
76
+
77
+ $ this ->fireConnectionEvent ('beganTransaction ' );
60
78
}
61
79
62
80
/**
63
81
* Commit transaction in this session.
64
82
*/
65
83
public function commit (): void
66
84
{
85
+ $ this ->fireConnectionEvent ('committing ' );
67
86
$ this ->getSessionOrThrow ()->commitTransaction ();
68
- $ this ->transactions = 0 ;
87
+
88
+ $ this ->handleCommitState ();
89
+ }
90
+
91
+ private function handleCommitState (): void
92
+ {
93
+ [$ levelBeingCommitted , $ this ->transactions ] = [
94
+ $ this ->transactions ,
95
+ max (0 , $ this ->transactions - 1 ),
96
+ ];
97
+
98
+ $ this ->transactionsManager ?->commit(
99
+ $ this ->getName (),
100
+ $ levelBeingCommitted ,
101
+ $ this ->transactions ,
102
+ );
103
+
104
+ $ this ->fireConnectionEvent ('committed ' );
69
105
}
70
106
71
107
/**
72
108
* Abort transaction in this session.
73
109
*/
74
110
public function rollBack ($ toLevel = null ): void
75
111
{
76
- $ this ->getSessionOrThrow ()->abortTransaction ();
112
+ $ session = $ this ->getSessionOrThrow ();
113
+ if ($ session ->isInTransaction ()) {
114
+ $ session ->abortTransaction ();
115
+ }
116
+
117
+ $ this ->handleRollbackState ();
118
+ }
119
+
120
+ private function handleRollbackState (): void
121
+ {
77
122
$ this ->transactions = 0 ;
123
+
124
+ $ this ->transactionsManager ?->rollback(
125
+ $ this ->getName (),
126
+ $ this ->transactions ,
127
+ );
128
+
129
+ $ this ->fireConnectionEvent ('rollingBack ' );
130
+ }
131
+
132
+ private function runCallbacksBeforeTransaction (): void
133
+ {
134
+ // ToDo: remove conditional once we stop supporting Laravel 10.x
135
+ if (property_exists (Connection::class, 'beforeStartingTransaction ' )) {
136
+ foreach ($ this ->beforeStartingTransaction as $ beforeTransactionCallback ) {
137
+ $ beforeTransactionCallback ($ this );
138
+ }
139
+ }
78
140
}
79
141
80
142
/**
81
143
* Static transaction function realize the with_transaction functionality provided by MongoDB.
82
144
*
83
- * @param int $attempts
145
+ * @param int $attempts
146
+ *
147
+ * @throws Throwable
84
148
*/
85
149
public function transaction (Closure $ callback , $ attempts = 1 , array $ options = []): mixed
86
150
{
@@ -93,15 +157,20 @@ public function transaction(Closure $callback, $attempts = 1, array $options = [
93
157
94
158
if ($ attemptsLeft < 0 ) {
95
159
$ session ->abortTransaction ();
160
+ $ this ->handleRollbackState ();
96
161
97
162
return ;
98
163
}
99
164
165
+ $ this ->runCallbacksBeforeTransaction ();
166
+ $ this ->handleInitialTransactionState ();
167
+
100
168
// Catch, store, and re-throw any exception thrown during execution
101
169
// of the callable. The last exception is re-thrown if the transaction
102
170
// was aborted because the number of callback attempts has been exceeded.
103
171
try {
104
172
$ callbackResult = $ callback ($ this );
173
+ $ this ->fireConnectionEvent ('committing ' );
105
174
} catch (Throwable $ throwable ) {
106
175
throw $ throwable ;
107
176
}
@@ -110,9 +179,12 @@ public function transaction(Closure $callback, $attempts = 1, array $options = [
110
179
with_transaction ($ this ->getSessionOrCreate (), $ callbackFunction , $ options );
111
180
112
181
if ($ attemptsLeft < 0 && $ throwable ) {
182
+ $ this ->handleRollbackState ();
113
183
throw $ throwable ;
114
184
}
115
185
186
+ $ this ->handleCommitState ();
187
+
116
188
return $ callbackResult ;
117
189
}
118
190
}
0 commit comments