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  $ optionsvoid 
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 ($ toLevelnull ): void 
75111    {
76-         $ this getSessionOrThrow ()->abortTransaction ();
112+         $ session$ this getSessionOrThrow ();
113+         if  ($ sessionisInTransaction ()) {
114+             $ sessionabortTransaction ();
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$ attempts1 , array  $ optionsmixed 
86150    {
@@ -93,15 +157,20 @@ public function transaction(Closure $callback, $attempts = 1, array $options = [
93157
94158            if  ($ attemptsLeft0 ) {
95159                $ sessionabortTransaction ();
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  ($ attemptsLeft0  && $ throwable
182+             $ this handleRollbackState ();
113183            throw  $ throwable
114184        }
115185
186+         $ this handleCommitState ();
187+ 
116188        return  $ callbackResult
117189    }
118190}
0 commit comments