Skip to content

Commit 76a158e

Browse files
authored
[9.x] Fix afterCommit and RefreshDatabase (#41782)
* fix afterCommit and refreshDatabase * additional work * method extraction
1 parent 6ed23a5 commit 76a158e

File tree

3 files changed

+61
-3
lines changed

3 files changed

+61
-3
lines changed

src/Illuminate/Database/Concerns/ManagesTransactions.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public function transaction(Closure $callback, $attempts = 1)
4747

4848
$this->transactions = max(0, $this->transactions - 1);
4949

50-
if ($this->transactions == 0) {
50+
if ($this->afterCommitCallbacksShouldBeExecuted()) {
5151
$this->transactionsManager?->commit($this->getName());
5252
}
5353
} catch (Throwable $e) {
@@ -193,13 +193,25 @@ public function commit()
193193

194194
$this->transactions = max(0, $this->transactions - 1);
195195

196-
if ($this->transactions == 0) {
196+
if ($this->afterCommitCallbacksShouldBeExecuted()) {
197197
$this->transactionsManager?->commit($this->getName());
198198
}
199199

200200
$this->fireConnectionEvent('committed');
201201
}
202202

203+
/**
204+
* Determine if after commit callbacks should be executed.
205+
*
206+
* @return bool
207+
*/
208+
protected function afterCommitCallbacksShouldBeExecuted()
209+
{
210+
return $this->transactions == 0 ||
211+
($this->transactionsManager &&
212+
$this->transactionsManager->callbackApplicableTransactions()->count() === 1);
213+
}
214+
203215
/**
204216
* Handle an exception encountered when committing a transaction.
205217
*

src/Illuminate/Database/DatabaseTransactionsManager.php

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ class DatabaseTransactionsManager
1111
*/
1212
protected $transactions;
1313

14+
/**
15+
* The database transaction that should be ignored by callbacks.
16+
*
17+
* @var \Illuminate\Database\DatabaseTransactionRecord
18+
*/
19+
protected $callbacksShouldIgnore;
20+
1421
/**
1522
* Create a new database transactions manager instance.
1623
*
@@ -47,6 +54,10 @@ public function rollback($connection, $level)
4754
$this->transactions = $this->transactions->reject(
4855
fn ($transaction) => $transaction->connection == $connection && $transaction->level > $level
4956
)->values();
57+
58+
if ($this->transactions->isEmpty()) {
59+
$this->callbacksShouldIgnore = null;
60+
}
5061
}
5162

5263
/**
@@ -64,6 +75,10 @@ public function commit($connection)
6475
$this->transactions = $forOtherConnections->values();
6576

6677
$forThisConnection->map->executeCallbacks();
78+
79+
if ($this->transactions->isEmpty()) {
80+
$this->callbacksShouldIgnore = null;
81+
}
6782
}
6883

6984
/**
@@ -74,13 +89,38 @@ public function commit($connection)
7489
*/
7590
public function addCallback($callback)
7691
{
77-
if ($current = $this->transactions->last()) {
92+
if ($current = $this->callbackApplicableTransactions()->last()) {
7893
return $current->addCallback($callback);
7994
}
8095

8196
$callback();
8297
}
8398

99+
/**
100+
* Specify that callbacks should ignore the given transaction when determining if they should be executed.
101+
*
102+
* @param \Illuminate\Database\DatabaseTransactionRecord $transaction
103+
* @return $this
104+
*/
105+
public function callbacksShouldIgnore(DatabaseTransactionRecord $transaction)
106+
{
107+
$this->callbacksShouldIgnore = $transaction;
108+
109+
return $this;
110+
}
111+
112+
/**
113+
* Get the transactions that are applicable to callbacks.
114+
*
115+
* @return \Illuminate\Support\Collection
116+
*/
117+
public function callbackApplicableTransactions()
118+
{
119+
return $this->transactions->reject(function ($transaction) {
120+
return $transaction === $this->callbacksShouldIgnore;
121+
})->values();
122+
}
123+
84124
/**
85125
* Get all the transactions.
86126
*

src/Illuminate/Foundation/Testing/RefreshDatabase.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ public function beginDatabaseTransaction()
9393
$connection->unsetEventDispatcher();
9494
$connection->beginTransaction();
9595
$connection->setEventDispatcher($dispatcher);
96+
97+
if ($this->app->resolved('db.transactions')) {
98+
$this->app->make('db.transactions')->callbacksShouldIgnore(
99+
$this->app->make('db.transactions')->getTransactions()->first()
100+
);
101+
}
96102
}
97103

98104
$this->beforeApplicationDestroyed(function () use ($database) {

0 commit comments

Comments
 (0)