Вход Регистрация
Файл: vendor/laravel/framework/src/Illuminate/Database/DatabaseTransactionsManager.php
Строк: 582
<?php

namespace IlluminateDatabase;

use 
IlluminateSupportCollection;

class 
DatabaseTransactionsManager
{
    
/**
     * All of the committed transactions.
     *
     * @var IlluminateSupportCollection<int, IlluminateDatabaseDatabaseTransactionRecord>
     */
    
protected $committedTransactions;

    
/**
     * All of the pending transactions.
     *
     * @var IlluminateSupportCollection<int, IlluminateDatabaseDatabaseTransactionRecord>
     */
    
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  IlluminateDatabaseDatabaseTransactionRecord  $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 IlluminateSupportCollection<int, IlluminateDatabaseDatabaseTransactionRecord>
     */
    
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 IlluminateSupportCollection
     */
    
public function getPendingTransactions()
    {
        return 
$this->pendingTransactions;
    }

    
/**
     * Get all of the committed transactions.
     *
     * @return IlluminateSupportCollection
     */
    
public function getCommittedTransactions()
    {
        return 
$this->committedTransactions;
    }
}
Онлайн: 1
Реклама