144 lines
4.1 KiB
PHP
144 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace Nest\Database;
|
|
|
|
use Nest\Database\Query\QueryBuilder;
|
|
use Nest\Database\Transactions\Transaction;
|
|
use Nest\Exceptions\Database\NotCurrentTransactionException;
|
|
use Throwable;
|
|
|
|
/**
|
|
* Class of a database.
|
|
*/
|
|
abstract class Database
|
|
{
|
|
/**
|
|
* The current transaction, in one is started.
|
|
* @var Transaction|null
|
|
*/
|
|
private ?Transaction $transaction = null;
|
|
|
|
/**
|
|
* Connect to the database.
|
|
* @return void
|
|
*/
|
|
public abstract function connect(): void;
|
|
|
|
/**
|
|
* Execute a query.
|
|
* @param string $statement The query statement.
|
|
* @param array $bindings The query bindings.
|
|
* @return object[] Query result as an array of objects.
|
|
*/
|
|
public abstract function execute(string $statement, array $bindings = []): array;
|
|
|
|
/**
|
|
* Get a queries adapter for the current database.
|
|
* @return DatabaseAdapter A database queries adapter.
|
|
*/
|
|
public abstract function getQueriesAdapter(): DatabaseAdapter;
|
|
|
|
/**
|
|
* Create a new query on the database.
|
|
* @param ?string $table The table on which to build the new query.
|
|
* @return QueryBuilder A query builder.
|
|
*/
|
|
public function query(?string $table = null): QueryBuilder
|
|
{
|
|
return new QueryBuilder($this, $table);
|
|
}
|
|
|
|
/**
|
|
* Create a new query on the given table of the database.
|
|
* @param string $table The table on which to build the new query.
|
|
* @return QueryBuilder A query builder.
|
|
*/
|
|
public function table(string $table): QueryBuilder
|
|
{
|
|
return $this->query($table);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the current transaction, if there is one.
|
|
* @return Transaction|null
|
|
*/
|
|
public function getCurrentTransaction(): ?Transaction
|
|
{
|
|
return $this->transaction;
|
|
}
|
|
|
|
/**
|
|
* Called when the state of a transaction changed (inactive -> active or active -> inactive).
|
|
* @param Transaction $transaction
|
|
* @return void
|
|
* @throws NotCurrentTransactionException
|
|
*/
|
|
public function onTransactionStateChanged(Transaction $transaction): void
|
|
{
|
|
if ($transaction->isActive())
|
|
{ // Set the newly active transaction as the current one.
|
|
|
|
// Its parent should be the current transaction, if it exists.
|
|
if (!empty($transaction->getParent()) && $transaction->getParent()->getUuid() != $this->transaction->getUuid())
|
|
throw new NotCurrentTransactionException($this->transaction, $transaction->getParent());
|
|
|
|
$this->transaction = $transaction;
|
|
}
|
|
else
|
|
{ // The transaction has been terminated, it should be the current one.
|
|
if (!empty($this->transaction) && $this->transaction->getUuid() != $transaction->getUuid())
|
|
throw new NotCurrentTransactionException($this->transaction, $transaction);
|
|
|
|
$this->transaction = $transaction->getParent();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start a new transaction (in the current one, if there is one).
|
|
* @return Transaction The new transaction.
|
|
* @throws NotCurrentTransactionException
|
|
*/
|
|
public function startTransaction(): Transaction
|
|
{
|
|
// Create the transaction as a child of the existing one, if there is one.
|
|
$newTransaction = new Transaction($this, $this->transaction);
|
|
if (!empty($this->transaction))
|
|
// Set the new transaction as child of the current one.
|
|
$this->transaction->setChild($newTransaction);
|
|
|
|
$newTransaction->start(); // Start the new transaction.
|
|
|
|
return $newTransaction; // Return the new transaction.
|
|
}
|
|
|
|
/**
|
|
* Start a new transaction and execute the function in parameter.
|
|
* The transaction will be committed / rolled back automatically at the end of the function.
|
|
* A rollback happen if any exception is thrown in the function.
|
|
* @param callable(Transaction): mixed $function The function to execute in a transaction.
|
|
* @return mixed Function result.
|
|
* @throws Throwable
|
|
*/
|
|
public function transaction(callable $function): mixed
|
|
{
|
|
// Start a new transaction.
|
|
$transaction = $this->startTransaction();
|
|
|
|
try
|
|
{ // Trying to run the function in the started transaction.
|
|
$result = $function($transaction);
|
|
|
|
// The function finished successfully, commit the transaction.
|
|
$transaction->commit();
|
|
|
|
// Return result of the function.
|
|
return $result;
|
|
}
|
|
catch (Throwable $throwable)
|
|
{ // An exception has been thrown, rolling back the transaction and throw it again.
|
|
$transaction->rollback();
|
|
throw $throwable;
|
|
}
|
|
}
|
|
}
|