Skip to content

Commit

Permalink
[9.x] Fix afterCommit and RefreshDatabase (#41782)
Browse files Browse the repository at this point in the history
* fix afterCommit and refreshDatabase

* additional work

* method extraction
  • Loading branch information
taylorotwell committed Apr 6, 2022
1 parent 6ed23a5 commit 76a158e
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 3 deletions.
16 changes: 14 additions & 2 deletions src/Illuminate/Database/Concerns/ManagesTransactions.php
Expand Up @@ -47,7 +47,7 @@ public function transaction(Closure $callback, $attempts = 1)

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

if ($this->transactions == 0) {
if ($this->afterCommitCallbacksShouldBeExecuted()) {
$this->transactionsManager?->commit($this->getName());
}
} catch (Throwable $e) {
Expand Down Expand Up @@ -193,13 +193,25 @@ public function commit()

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

if ($this->transactions == 0) {
if ($this->afterCommitCallbacksShouldBeExecuted()) {
$this->transactionsManager?->commit($this->getName());
}

$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
42 changes: 41 additions & 1 deletion src/Illuminate/Database/DatabaseTransactionsManager.php
Expand Up @@ -11,6 +11,13 @@ class DatabaseTransactionsManager
*/
protected $transactions;

/**
* The database transaction that should be ignored by callbacks.
*
* @var \Illuminate\Database\DatabaseTransactionRecord
*/
protected $callbacksShouldIgnore;

/**
* Create a new database transactions manager instance.
*
Expand Down Expand Up @@ -47,6 +54,10 @@ public function rollback($connection, $level)
$this->transactions = $this->transactions->reject(
fn ($transaction) => $transaction->connection == $connection && $transaction->level > $level
)->values();

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

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

$forThisConnection->map->executeCallbacks();

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

/**
Expand All @@ -74,13 +89,38 @@ public function commit($connection)
*/
public function addCallback($callback)
{
if ($current = $this->transactions->last()) {
if ($current = $this->callbackApplicableTransactions()->last()) {
return $current->addCallback($callback);
}

$callback();
}

/**
* Specify that callbacks should ignore the given transaction when determining if they should be executed.
*
* @param \Illuminate\Database\DatabaseTransactionRecord $transaction
* @return $this
*/
public function callbacksShouldIgnore(DatabaseTransactionRecord $transaction)
{
$this->callbacksShouldIgnore = $transaction;

return $this;
}

/**
* Get the transactions that are applicable to callbacks.
*
* @return \Illuminate\Support\Collection
*/
public function callbackApplicableTransactions()
{
return $this->transactions->reject(function ($transaction) {
return $transaction === $this->callbacksShouldIgnore;
})->values();
}

/**
* Get all the transactions.
*
Expand Down
6 changes: 6 additions & 0 deletions src/Illuminate/Foundation/Testing/RefreshDatabase.php
Expand Up @@ -93,6 +93,12 @@ public function beginDatabaseTransaction()
$connection->unsetEventDispatcher();
$connection->beginTransaction();
$connection->setEventDispatcher($dispatcher);

if ($this->app->resolved('db.transactions')) {
$this->app->make('db.transactions')->callbacksShouldIgnore(
$this->app->make('db.transactions')->getTransactions()->first()
);
}
}

$this->beforeApplicationDestroyed(function () use ($database) {
Expand Down

0 comments on commit 76a158e

Please sign in to comment.