Database/src/Transactions/Transaction.php

139 lines
3.1 KiB
PHP

<?php
namespace Nest\Database\Transactions;
use Nest\Database\Database;
use Nest\Database\Exceptions\NotCurrentTransactionException;
use Symfony\Component\Uid\Uuid;
/**
* Instance of a database transaction.
*/
class Transaction
{
/**
* UUID of the transaction.
* @var string
*/
private string $uuid;
/**
* Determine if the transaction is active (started and not committed nor rolled back).
* @var bool
*/
private bool $active = false;
/**
* Subtransaction of the current transaction.
* @var Transaction|null
*/
protected ?Transaction $childTransaction = null;
/**
* Create a new transaction for the given database.
* @param Database $database The database.
* @param Transaction|null $parentTransaction The parent transaction, if there is one.
*/
public function __construct(protected Database $database, protected ?Transaction $parentTransaction = null)
{
$this->uuid = Uuid::v4()->toString();
}
/**
* Get UUID of the transaction.
* @return string
*/
public function getUuid(): string
{
return $this->uuid;
}
/**
* Get the parent transaction.
* @return Transaction|null
*/
public function getParent(): ?Transaction
{
return $this->parentTransaction;
}
/**
* Set the current child transaction of this transaction.
* @param Transaction|null $transaction The child transaction. NULL if there is no child transaction.
* @return void
*/
public function setChild(?Transaction $transaction): void
{
$this->childTransaction = $transaction;
}
/**
* Start the transaction.
* @return void
* @throws NotCurrentTransactionException
*/
public function start(): void
{
// Transaction activation state changed.
$this->active = true;
$this->database->onTransactionStateChanged($this);
// Start the transaction.
$this->database->getQueriesAdapter()->newTransaction();
}
/**
* Commit the transaction.
* @return void
* @throws NotCurrentTransactionException
*/
public function commit(): void
{
if (!$this->isActive())
// Do not commit a non-active transaction.
return;
if (!empty($this->childTransaction))
// First commit the child transaction, if there is one.
$this->childTransaction->commit();
// Transaction activation state changed.
$this->active = false;
$this->database->onTransactionStateChanged($this);
// Commit the current transaction.
$this->database->getQueriesAdapter()->commitTransaction();
}
/**
* Rollback the transaction.
* @return void
* @throws NotCurrentTransactionException
*/
public function rollback(): void
{
if (!$this->isActive())
// Do not rollback a non-active transaction.
return;
if (!empty($this->childTransaction))
// First rollback the child transaction, if there is one.
$this->childTransaction->rollback();
// Transaction activation state changed.
$this->active = false;
$this->database->onTransactionStateChanged($this);
// Rollback the current transaction.
$this->database->getQueriesAdapter()->rollbackTransaction();
}
/**
* Determine if the transaction is still active (not committed nor rolled back).
* @return bool
*/
public function isActive(): bool
{
return $this->active;
}
}