88use MongoDB \Client ;
99use MongoDB \Driver \Exception \RuntimeException ;
1010use MongoDB \Driver \Session ;
11+ use MongoDB \Laravel \Connection ;
1112use Throwable ;
1213
14+ use function max ;
1315use function MongoDB \with_transaction ;
16+ use function property_exists ;
1417
1518/**
1619 * @internal
@@ -55,32 +58,93 @@ private function getSessionOrThrow(): Session
5558 */
5659 public function beginTransaction (array $ options = []): void
5760 {
61+ $ this ->runCallbacksBeforeTransaction ();
62+ 5863 $ this ->getSessionOrCreate ()->startTransaction ($ options );
64+ 65+ $ this ->handleInitialTransactionState ();
66+ }
67+ 68+ private function handleInitialTransactionState (): void
69+ {
5970 $ this ->transactions = 1 ;
71+ 72+ $ this ->transactionsManager ?->begin(
73+ $ this ->getName (),
74+ $ this ->transactions ,
75+ );
76+ 77+ $ this ->fireConnectionEvent ('beganTransaction ' );
6078 }
6179
6280 /**
6381 * Commit transaction in this session.
6482 */
6583 public function commit (): void
6684 {
85+ $ this ->fireConnectionEvent ('committing ' );
6786 $ 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 ' );
69105 }
70106
71107 /**
72108 * Abort transaction in this session.
73109 */
74110 public function rollBack ($ toLevel = null ): void
75111 {
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+ {
77122 $ 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+ }
78140 }
79141
80142 /**
81143 * Static transaction function realize the with_transaction functionality provided by MongoDB.
82144 *
83- * @param int $attempts
145+ * @param int $attempts
146+ *
147+ * @throws Throwable
84148 */
85149 public function transaction (Closure $ callback , $ attempts = 1 , array $ options = []): mixed
86150 {
@@ -93,15 +157,20 @@ public function transaction(Closure $callback, $attempts = 1, array $options = [
93157
94158 if ($ attemptsLeft < 0 ) {
95159 $ session ->abortTransaction ();
160+ $ this ->handleRollbackState ();
96161
97162 return ;
98163 }
99164
165+ $ this ->runCallbacksBeforeTransaction ();
166+ $ this ->handleInitialTransactionState ();
167+ 100168 // Catch, store, and re-throw any exception thrown during execution
101169 // of the callable. The last exception is re-thrown if the transaction
102170 // was aborted because the number of callback attempts has been exceeded.
103171 try {
104172 $ callbackResult = $ callback ($ this );
173+ $ this ->fireConnectionEvent ('committing ' );
105174 } catch (Throwable $ throwable ) {
106175 throw $ throwable ;
107176 }
@@ -110,9 +179,12 @@ public function transaction(Closure $callback, $attempts = 1, array $options = [
110179 with_transaction ($ this ->getSessionOrCreate (), $ callbackFunction , $ options );
111180
112181 if ($ attemptsLeft < 0 && $ throwable ) {
182+ $ this ->handleRollbackState ();
113183 throw $ throwable ;
114184 }
115185
186+ $ this ->handleCommitState ();
187+ 116188 return $ callbackResult ;
117189 }
118190}
0 commit comments