Skip to content

Commit

Permalink
Fix nested transaction callbacks handling
Browse files Browse the repository at this point in the history
  • Loading branch information
mpyw committed Sep 20, 2023
1 parent 1157523 commit cf8af67
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 21 deletions.
21 changes: 3 additions & 18 deletions src/Illuminate/Database/Concerns/ManagesTransactions.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ public function transaction(Closure $callback, $attempts = 1)
}

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

if ($this->afterCommitCallbacksShouldBeExecuted()) {
$this->transactionsManager?->commit($this->getName());
}
$this->transactionsManager?->commit($this->getName());
} catch (Throwable $e) {
$this->handleCommitTransactionException(
$e, $currentAttempt, $attempts
Expand Down Expand Up @@ -203,18 +200,6 @@ public function commit()
$this->fireConnectionEvent('committed');
}

/**
* Determine if after commit callbacks should be executed.
*
* @return bool
*/
protected function afterCommitCallbacksShouldBeExecuted()
{
return $this->transactions == 0 ||
($this->transactionsManager &&
$this->transactionsManager->callbackApplicableTransactions()->count() === 1);
}

/**
* Handle an exception encountered when committing a transaction.
*
Expand Down Expand Up @@ -254,8 +239,8 @@ public function rollBack($toLevel = null)
// that this given transaction level is valid before attempting to rollback to
// that level. If it's not we will just return out and not attempt anything.
$toLevel = is_null($toLevel)
? $this->transactions - 1
: $toLevel;
? $this->transactions - 1
: $toLevel;

if ($toLevel < 0 || $toLevel >= $this->transactions) {
return;
Expand Down
39 changes: 36 additions & 3 deletions src/Illuminate/Database/DatabaseTransactionsManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,52 @@ public function rollback($connection, $level)
*/
public function commit($connection)
{
[$forThisConnection, $forOtherConnections] = $this->transactions->partition(
if ($this->afterCommitCallbacksShouldBeExecuted()) {
[$forThisConnection, $forOtherConnections] = $this->transactions->partition(
fn ($transaction) => $transaction->connection == $connection
);

$this->transactions = $forOtherConnections->values();

$forThisConnection->map->executeCallbacks();

if ($this->transactions->isEmpty()) {
$this->callbacksShouldIgnore = null;
}

return;
}

$last = $this->transactions->last(
fn ($transaction) => $transaction->connection == $connection
);
$parent = $this->transactions->last(
fn ($transaction) => $transaction->connection == $connection && $last !== $transaction,
);

$this->transactions = $forOtherConnections->values();
$this->transactions = $this->transactions->reject(
fn ($transaction) => $transaction === $last,
);

$forThisConnection->map->executeCallbacks();
foreach ($last?->getCallbacks() ?? [] as $callback) {
$parent?->addCallback($callback);
}

if ($this->transactions->isEmpty()) {
$this->callbacksShouldIgnore = null;
}
}

/**
* Determine if after commit callbacks should be executed.
*
* @return bool
*/
protected function afterCommitCallbacksShouldBeExecuted()
{
return $this->callbackApplicableTransactions()->count() === 1;
}

/**
* Register a transaction callback.
*
Expand Down

0 comments on commit cf8af67

Please sign in to comment.