Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(database): add closable connection wrapper for PDO connection #875

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/Tempest/Database/src/CachedConnectionInitializer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Tempest\Database;

use Tempest\Container\Container;
use Tempest\Container\Initializer;
use Tempest\Container\Singleton;

/**
* Reuses the same connection instance based on a static variable instead of the container.
*
* Used in testing where each test can have its own container instance.
*/
final class CachedConnectionInitializer implements Initializer
{
private static Connection|null $instance = null;

public function __construct(private readonly ConnectionInitializer $initializer)
{
}

#[Singleton]
public function initialize(Container $container): Connection
{
if (self::$instance !== null) {
return self::$instance;
}

self::$instance = $this->initializer->initialize($container);

return self::$instance;
}
}
24 changes: 24 additions & 0 deletions src/Tempest/Database/src/Connection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Tempest\Database;

use PDOStatement;

interface Connection
brendt marked this conversation as resolved.
Show resolved Hide resolved
{
public function beginTransaction(): bool;

public function commit(): bool;

public function rollback(): bool;

public function lastInsertId(): false|string;

public function prepare(string $sql): false|PDOStatement;

public function close(): void;

public function connect(): void;
}
23 changes: 23 additions & 0 deletions src/Tempest/Database/src/ConnectionInitializer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Tempest\Database;

use Tempest\Container\Container;
use Tempest\Container\Initializer;
use Tempest\Container\Singleton;

final class ConnectionInitializer implements Initializer
{
#[Singleton]
public function initialize(Container $container): Connection
{
$databaseConfig = $container->get(DatabaseConfig::class);

$connection = new PDOConnection($databaseConfig->connection());
$connection->connect();

return $connection;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

declare(strict_types=1);

namespace Tempest\Database;
namespace Tempest\Database\Connections;

use Tempest\Database\DatabaseDialect;
use Tempest\Database\Tables\NamingStrategy;

interface DatabaseConnection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

declare(strict_types=1);

namespace Tempest\Database;
namespace Tempest\Database\Connections;

use Tempest\Container\Container;
use Tempest\Container\Initializer;
use Tempest\Container\Singleton;
use Tempest\Database\DatabaseConfig;

final class DatabaseConnectionInitializer implements Initializer
{
Expand Down
1 change: 0 additions & 1 deletion src/Tempest/Database/src/Connections/MySqlConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Tempest\Database\Connections;

use SensitiveParameter;
use Tempest\Database\DatabaseConnection;
use Tempest\Database\DatabaseDialect;
use Tempest\Database\Tables\NamingStrategy;
use Tempest\Database\Tables\PluralizedSnakeCaseStrategy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Tempest\Database\Connections;

use SensitiveParameter;
use Tempest\Database\DatabaseConnection;
use Tempest\Database\DatabaseDialect;
use Tempest\Database\Tables\NamingStrategy;
use Tempest\Database\Tables\PluralizedSnakeCaseStrategy;
Expand Down
1 change: 0 additions & 1 deletion src/Tempest/Database/src/Connections/SQLiteConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Tempest\Database\Connections;

use SensitiveParameter;
use Tempest\Database\DatabaseConnection;
use Tempest\Database\DatabaseDialect;
use Tempest\Database\Tables\NamingStrategy;
use Tempest\Database\Tables\PluralizedSnakeCaseStrategy;
Expand Down
2 changes: 2 additions & 0 deletions src/Tempest/Database/src/DatabaseConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace Tempest\Database;

use Tempest\Database\Connections\DatabaseConnection;

final class DatabaseConfig
{
private array $migrations = [];
Expand Down
1 change: 1 addition & 0 deletions src/Tempest/Database/src/DatabaseDialectInitializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Tempest\Container\Container;
use Tempest\Container\Initializer;
use Tempest\Database\Connections\DatabaseConnection;

final readonly class DatabaseDialectInitializer implements Initializer
{
Expand Down
3 changes: 1 addition & 2 deletions src/Tempest/Database/src/DatabaseInitializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Tempest\Database;

use PDO;
use Tempest\Container\Container;
use Tempest\Container\Initializer;
use Tempest\Container\Singleton;
Expand All @@ -16,7 +15,7 @@
public function initialize(Container $container): Database
{
return new GenericDatabase(
$container->get(PDO::class),
$container->get(Connection::class),
$container->get(TransactionManager::class),
);
}
Expand Down
13 changes: 13 additions & 0 deletions src/Tempest/Database/src/Exceptions/ConnectionClosed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Tempest\Database\Exceptions;

final class ConnectionClosed extends DatabaseException
{
public function __construct()
{
parent::__construct('Connection is closed');
}
}
12 changes: 6 additions & 6 deletions src/Tempest/Database/src/GenericDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
use Tempest\Database\Transactions\TransactionManager;
use Throwable;

final class GenericDatabase implements Database
final readonly class GenericDatabase implements Database
{
public function __construct(
private PDO $pdo,
private readonly TransactionManager $transactionManager,
private Connection $connection,
private TransactionManager $transactionManager,
) {
}

Expand All @@ -25,7 +25,7 @@ public function execute(Query $query): void
$bindings = $this->resolveBindings($query);

try {
$this->pdo
$this->connection
->prepare($query->getSql())
->execute($bindings);
} catch (PDOException $pdoException) {
Expand All @@ -35,12 +35,12 @@ public function execute(Query $query): void

public function getLastInsertId(): Id
{
return new Id($this->pdo->lastInsertId());
return new Id($this->connection->lastInsertId());
}

public function fetch(Query $query): array
{
$pdoQuery = $this->pdo->prepare($query->getSql());
$pdoQuery = $this->connection->prepare($query->getSql());

$pdoQuery->execute($this->resolveBindings($query));

Expand Down
82 changes: 82 additions & 0 deletions src/Tempest/Database/src/PDOConnection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);

namespace Tempest\Database;

use PDO;
use PDOStatement;
use Tempest\Database\Connections\DatabaseConnection;
use Tempest\Database\Exceptions\ConnectionClosed;

final class PDOConnection implements Connection
{
private PDO|null $pdo = null;

public function __construct(private readonly DatabaseConnection $connection)
{
}

public function beginTransaction(): bool
{
if ($this->pdo === null) {
throw new ConnectionClosed();
}

return $this->pdo->beginTransaction();
}

public function commit(): bool
{
if ($this->pdo === null) {
throw new ConnectionClosed();
}

return $this->pdo->commit();
}

public function rollback(): bool
{
if ($this->pdo === null) {
throw new ConnectionClosed();
}

return $this->pdo->rollBack();
}

public function lastInsertId(): false|string
{
if ($this->pdo === null) {
throw new ConnectionClosed();
}

return $this->pdo->lastInsertId();
}

public function prepare(string $sql): false|PDOStatement
{
if ($this->pdo === null) {
throw new ConnectionClosed();
}

return $this->pdo->prepare($sql);
}

public function close(): void
{
$this->pdo = null;
}

public function connect(): void
{
if ($this->pdo !== null) {
return;
}

$this->pdo = new PDO(
$this->connection->getDsn(),
$this->connection->getUsername(),
$this->connection->getPassword(),
);
}
}
35 changes: 0 additions & 35 deletions src/Tempest/Database/src/PDOInitializer.php

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@

namespace Tempest\Database\Transactions;

use PDO;
use Tempest\Database\Connection;
use Tempest\Database\Exceptions\CouldNotBeginTransaction;
use Tempest\Database\Exceptions\CouldNotCommitTransaction;
use Tempest\Database\Exceptions\CouldNotRollbackTransaction;

final class GenericTransactionManager implements TransactionManager
{
public function __construct(private PDO $pdo)
public function __construct(private Connection $connection)
{
}

public function begin(): void
{
$transactionBegun = $this->pdo->beginTransaction();
$transactionBegun = $this->connection->beginTransaction();

if (! $transactionBegun) {
throw new CouldNotBeginTransaction();
Expand All @@ -26,7 +26,7 @@ public function begin(): void

public function commit(): void
{
$transactionCommitted = $this->pdo->commit();
$transactionCommitted = $this->connection->commit();

if (! $transactionCommitted) {
throw new CouldNotCommitTransaction();
Expand All @@ -35,7 +35,7 @@ public function commit(): void

public function rollback(): void
{
$transactionRolledBack = $this->pdo->rollBack();
$transactionRolledBack = $this->connection->rollBack();

if (! $transactionRolledBack) {
throw new CouldNotRollbackTransaction();
Expand Down
Loading
Loading