Viewing file: DatabaseTransactionsManager.php (7.75 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
namespace Illuminate\Database;
use Illuminate\Support\Collection;
class DatabaseTransactionsManager { /** * All of the committed transactions. * * @var \Illuminate\Support\Collection<int, \Illuminate\Database\DatabaseTransactionRecord> */ protected $committedTransactions;
/** * All of the pending transactions. * * @var \Illuminate\Support\Collection<int, \Illuminate\Database\DatabaseTransactionRecord> */ protected $pendingTransactions;
/** * The current transaction. * * @var array */ protected $currentTransaction = [];
/** * Create a new database transactions manager instance. * * @return void */ public function __construct() { $this->committedTransactions = new Collection; $this->pendingTransactions = new Collection; }
/** * Start a new database transaction. * * @param string $connection * @param int $level * @return void */ public function begin($connection, $level) { $this->pendingTransactions->push( $newTransaction = new DatabaseTransactionRecord( $connection, $level, $this->currentTransaction[$connection] ?? null ) );
$this->currentTransaction[$connection] = $newTransaction; }
/** * Commit the root database transaction and execute callbacks. * * @param string $connection * @param int $levelBeingCommitted * @param int $newTransactionLevel * @return array */ public function commit($connection, $levelBeingCommitted, $newTransactionLevel) { $this->stageTransactions($connection, $levelBeingCommitted);
if (isset($this->currentTransaction[$connection])) { $this->currentTransaction[$connection] = $this->currentTransaction[$connection]->parent; }
if (! $this->afterCommitCallbacksShouldBeExecuted($newTransactionLevel) && $newTransactionLevel !== 0) { return []; }
// This method is only called when the root database transaction is committed so there // shouldn't be any pending transactions, but going to clear them here anyways just // in case. This method could be refactored to receive a level in the future too. $this->pendingTransactions = $this->pendingTransactions->reject( fn ($transaction) => $transaction->connection === $connection && $transaction->level >= $levelBeingCommitted )->values();
[$forThisConnection, $forOtherConnections] = $this->committedTransactions->partition( fn ($transaction) => $transaction->connection == $connection );
$this->committedTransactions = $forOtherConnections->values();
$forThisConnection->map->executeCallbacks();
return $forThisConnection; }
/** * Move relevant pending transactions to a committed state. * * @param string $connection * @param int $levelBeingCommitted * @return void */ public function stageTransactions($connection, $levelBeingCommitted) { $this->committedTransactions = $this->committedTransactions->merge( $this->pendingTransactions->filter( fn ($transaction) => $transaction->connection === $connection && $transaction->level >= $levelBeingCommitted ) );
$this->pendingTransactions = $this->pendingTransactions->reject( fn ($transaction) => $transaction->connection === $connection && $transaction->level >= $levelBeingCommitted ); }
/** * Rollback the active database transaction. * * @param string $connection * @param int $newTransactionLevel * @return void */ public function rollback($connection, $newTransactionLevel) { if ($newTransactionLevel === 0) { $this->removeAllTransactionsForConnection($connection); } else { $this->pendingTransactions = $this->pendingTransactions->reject( fn ($transaction) => $transaction->connection == $connection && $transaction->level > $newTransactionLevel )->values();
if ($this->currentTransaction) { do { $this->removeCommittedTransactionsThatAreChildrenOf($this->currentTransaction[$connection]);
$this->currentTransaction[$connection] = $this->currentTransaction[$connection]->parent; } while ( isset($this->currentTransaction[$connection]) && $this->currentTransaction[$connection]->level > $newTransactionLevel ); } } }
/** * Remove all pending, completed, and current transactions for the given connection name. * * @param string $connection * @return void */ protected function removeAllTransactionsForConnection($connection) { $this->currentTransaction[$connection] = null;
$this->pendingTransactions = $this->pendingTransactions->reject( fn ($transaction) => $transaction->connection == $connection )->values();
$this->committedTransactions = $this->committedTransactions->reject( fn ($transaction) => $transaction->connection == $connection )->values(); }
/** * Remove all transactions that are children of the given transaction. * * @param \Illuminate\Database\DatabaseTransactionRecord $transaction * @return void */ protected function removeCommittedTransactionsThatAreChildrenOf(DatabaseTransactionRecord $transaction) { [$removedTransactions, $this->committedTransactions] = $this->committedTransactions->partition( fn ($committed) => $committed->connection == $transaction->connection && $committed->parent === $transaction );
// There may be multiple deeply nested transactions that have already committed that we // also need to remove. We will recurse down the children of all removed transaction // instances until there are no more deeply nested child transactions for removal. $removedTransactions->each( fn ($transaction) => $this->removeCommittedTransactionsThatAreChildrenOf($transaction) ); }
/** * Register a transaction callback. * * @param callable $callback * @return void */ public function addCallback($callback) { if ($current = $this->callbackApplicableTransactions()->last()) { return $current->addCallback($callback); }
$callback(); }
/** * Get the transactions that are applicable to callbacks. * * @return \Illuminate\Support\Collection<int, \Illuminate\Database\DatabaseTransactionRecord> */ public function callbackApplicableTransactions() { return $this->pendingTransactions; }
/** * Determine if after commit callbacks should be executed for the given transaction level. * * @param int $level * @return bool */ public function afterCommitCallbacksShouldBeExecuted($level) { return $level === 0; }
/** * Get all of the pending transactions. * * @return \Illuminate\Support\Collection */ public function getPendingTransactions() { return $this->pendingTransactions; }
/** * Get all of the committed transactions. * * @return \Illuminate\Support\Collection */ public function getCommittedTransactions() { return $this->committedTransactions; } }
|