chore: complete update
This commit is contained in:
136
src/Framework/Database/ReadWriteConnection.php
Normal file
136
src/Framework/Database/ReadWriteConnection.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Database;
|
||||
|
||||
use App\Framework\Database\Exception\DatabaseException;
|
||||
|
||||
/**
|
||||
* Class ReadWriteConnection provides a mechanism to handle separate writing and reading database connections.
|
||||
* It ensures that write-heavy operations are directed to a designated write connection,
|
||||
* while read operations are distributed among a pool of read connections.
|
||||
*/
|
||||
final class ReadWriteConnection implements ConnectionInterface
|
||||
{
|
||||
private ConnectionInterface $writeConnection;
|
||||
private array $readConnections;
|
||||
private int $currentReadIndex = 0;
|
||||
private bool $forceWrite = false;
|
||||
|
||||
public function __construct(ConnectionInterface $writeConnection, array $readConnections)
|
||||
{
|
||||
$this->writeConnection = $writeConnection;
|
||||
$this->readConnections = $readConnections;
|
||||
|
||||
if (empty($this->readConnections)) {
|
||||
throw new DatabaseException('At least one read connection is required');
|
||||
}
|
||||
}
|
||||
|
||||
public function execute(string $sql, array $parameters = []): int
|
||||
{
|
||||
$this->forceWrite = true;
|
||||
return $this->writeConnection->execute($sql, $parameters);
|
||||
}
|
||||
|
||||
public function query(string $sql, array $parameters = []): ResultInterface
|
||||
{
|
||||
if ($this->shouldUseWriteConnection($sql)) {
|
||||
return $this->writeConnection->query($sql, $parameters);
|
||||
}
|
||||
|
||||
return $this->getReadConnection()->query($sql, $parameters);
|
||||
}
|
||||
|
||||
public function queryOne(string $sql, array $parameters = []): ?array
|
||||
{
|
||||
if ($this->shouldUseWriteConnection($sql)) {
|
||||
return $this->writeConnection->queryOne($sql, $parameters);
|
||||
}
|
||||
|
||||
return $this->getReadConnection()->queryOne($sql, $parameters);
|
||||
}
|
||||
|
||||
public function queryColumn(string $sql, array $parameters = []): array
|
||||
{
|
||||
if ($this->shouldUseWriteConnection($sql)) {
|
||||
return $this->writeConnection->queryColumn($sql, $parameters);
|
||||
}
|
||||
|
||||
return $this->getReadConnection()->queryColumn($sql, $parameters);
|
||||
}
|
||||
|
||||
public function queryScalar(string $sql, array $parameters = []): mixed
|
||||
{
|
||||
if ($this->shouldUseWriteConnection($sql)) {
|
||||
return $this->writeConnection->queryScalar($sql, $parameters);
|
||||
}
|
||||
|
||||
return $this->getReadConnection()->queryScalar($sql, $parameters);
|
||||
}
|
||||
|
||||
public function beginTransaction(): void
|
||||
{
|
||||
$this->forceWrite = true;
|
||||
$this->writeConnection->beginTransaction();
|
||||
}
|
||||
|
||||
public function commit(): void
|
||||
{
|
||||
$this->writeConnection->commit();
|
||||
$this->forceWrite = false;
|
||||
}
|
||||
|
||||
public function rollback(): void
|
||||
{
|
||||
$this->writeConnection->rollback();
|
||||
$this->forceWrite = false;
|
||||
}
|
||||
|
||||
public function inTransaction(): bool
|
||||
{
|
||||
return $this->writeConnection->inTransaction();
|
||||
}
|
||||
|
||||
public function lastInsertId(): string
|
||||
{
|
||||
return $this->writeConnection->lastInsertId();
|
||||
}
|
||||
|
||||
public function getPdo(): \PDO
|
||||
{
|
||||
return $this->writeConnection->getPdo();
|
||||
}
|
||||
|
||||
public function forceWriteConnection(): void
|
||||
{
|
||||
$this->forceWrite = true;
|
||||
}
|
||||
|
||||
public function resetConnectionMode(): void
|
||||
{
|
||||
$this->forceWrite = false;
|
||||
}
|
||||
|
||||
private function shouldUseWriteConnection(string $sql): bool
|
||||
{
|
||||
if ($this->forceWrite || $this->inTransaction()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$sql = trim(strtoupper($sql));
|
||||
$writeOperations = ['INSERT', 'UPDATE', 'DELETE', 'CREATE', 'ALTER', 'DROP', 'TRUNCATE'];
|
||||
|
||||
return array_any($writeOperations, fn($operation) => str_starts_with($sql, $operation));
|
||||
|
||||
}
|
||||
|
||||
private function getReadConnection(): ConnectionInterface
|
||||
{
|
||||
$connection = $this->readConnections[$this->currentReadIndex];
|
||||
$this->currentReadIndex = ($this->currentReadIndex + 1) % count($this->readConnections);
|
||||
|
||||
return $connection;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user