Skip to content

Commit d75d54c

Browse files
authored
feat(database): add pdo options to database configs (#1840)
1 parent 1af376a commit d75d54c

File tree

6 files changed

+191
-0
lines changed

6 files changed

+191
-0
lines changed

packages/database/src/Config/DatabaseConfig.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,52 @@
99

1010
interface DatabaseConfig extends HasTag
1111
{
12+
/**
13+
* PDO data source name connection string.
14+
*/
1215
public string $dsn {
1316
get;
1417
}
1518

19+
/**
20+
* The naming strategy for database tables and columns.
21+
*/
1622
public NamingStrategy $namingStrategy {
1723
get;
1824
}
1925

26+
/**
27+
* The database dialect (MySQL, PostgreSQL, SQLite).
28+
*/
2029
public DatabaseDialect $dialect {
2130
get;
2231
}
2332

33+
/**
34+
* The database username for authentication.
35+
*/
2436
public ?string $username {
2537
get;
2638
}
2739

40+
/**
41+
* The database password for authentication.
42+
*/
2843
public ?string $password {
2944
get;
3045
}
46+
47+
/**
48+
* Whether to use persistent database connections.
49+
*/
50+
public bool $usePersistentConnection {
51+
get;
52+
}
53+
54+
/**
55+
* PDO connection options built from configuration properties.
56+
*/
57+
public array $options {
58+
get;
59+
}
3160
}

packages/database/src/Config/MysqlConfig.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Tempest\Database\Config;
66

7+
use PDO;
8+
use Pdo\Mysql;
79
use SensitiveParameter;
810
use Tempest\Database\Tables\NamingStrategy;
911
use Tempest\Database\Tables\PluralizedSnakeCaseStrategy;
@@ -24,6 +26,52 @@ final class MysqlConfig implements DatabaseConfig
2426
get => DatabaseDialect::MYSQL;
2527
}
2628

29+
public bool $usePersistentConnection {
30+
get => $this->persistent;
31+
}
32+
33+
public array $options {
34+
get {
35+
$options = [];
36+
37+
if ($this->persistent) {
38+
$options[PDO::ATTR_PERSISTENT] = true;
39+
}
40+
41+
if ($this->certificateAuthority !== null) {
42+
$options[Mysql::ATTR_SSL_CA] = $this->certificateAuthority;
43+
}
44+
45+
if ($this->verifyServerCertificate !== null) {
46+
$options[Mysql::ATTR_SSL_VERIFY_SERVER_CERT] = $this->verifyServerCertificate;
47+
}
48+
49+
if ($this->clientCertificate !== null) {
50+
$options[Mysql::ATTR_SSL_CERT] = $this->clientCertificate;
51+
}
52+
53+
if ($this->clientKey !== null) {
54+
$options[Mysql::ATTR_SSL_KEY] = $this->clientKey;
55+
}
56+
57+
return $options;
58+
}
59+
}
60+
61+
/**
62+
* @param string $host The MySQL server hostname or IP address.
63+
* @param string $port The MySQL server port number.
64+
* @param string $username The MySQL username for authentication.
65+
* @param string $password The MySQL password for authentication.
66+
* @param string $database The database name to connect to.
67+
* @param bool $persistent Whether to use persistent connections. Persistent connections are not closed at the end of the script and are cached for reuse when another script requests a connection using the same credentials.
68+
* @param bool|null $verifyServerCertificate Whether to verify the server's SSL certificate. Set to false for self-signed certificates (not recommended for production).
69+
* @param string|null $certificateAuthority Path to the SSL Certificate Authority (CA) file. Required for SSL/TLS connections to verify the server's certificate.
70+
* @param string|null $clientCertificate Path to the client's SSL certificate file. Used for mutual TLS authentication.
71+
* @param string|null $clientKey Path to the client's SSL private key file. Used for mutual TLS authentication.
72+
* @param NamingStrategy $namingStrategy The naming strategy for database tables and columns.
73+
* @param string|UnitEnum|null $tag An optional tag to identify this database configuration.
74+
*/
2775
public function __construct(
2876
#[SensitiveParameter]
2977
public string $host = 'localhost',
@@ -35,6 +83,11 @@ public function __construct(
3583
public string $password = '',
3684
#[SensitiveParameter]
3785
public string $database = 'app',
86+
public bool $persistent = false,
87+
public ?bool $verifyServerCertificate = null,
88+
public ?string $certificateAuthority = null,
89+
public ?string $clientCertificate = null,
90+
public ?string $clientKey = null,
3891
public NamingStrategy $namingStrategy = new PluralizedSnakeCaseStrategy(),
3992
public null|string|UnitEnum $tag = null,
4093
) {}

packages/database/src/Config/PostgresConfig.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Tempest\Database\Config;
66

7+
use PDO;
78
use SensitiveParameter;
89
use Tempest\Database\Tables\NamingStrategy;
910
use Tempest\Database\Tables\PluralizedSnakeCaseStrategy;
@@ -26,6 +27,32 @@ final class PostgresConfig implements DatabaseConfig
2627
get => DatabaseDialect::POSTGRESQL;
2728
}
2829

30+
public bool $usePersistentConnection {
31+
get => $this->persistent;
32+
}
33+
34+
public array $options {
35+
get {
36+
$options = [];
37+
38+
if ($this->persistent) {
39+
$options[PDO::ATTR_PERSISTENT] = true;
40+
}
41+
42+
return $options;
43+
}
44+
}
45+
46+
/**
47+
* @param string $host The PostgreSQL server hostname or IP address.
48+
* @param string $port The PostgreSQL server port number.
49+
* @param string $username The PostgreSQL username for authentication.
50+
* @param string $password The PostgreSQL password for authentication.
51+
* @param string $database The database name to connect to.
52+
* @param bool $persistent Whether to use persistent connections. Persistent connections are not closed at the end of the script and are cached for reuse when another script requests a connection using the same credentials.
53+
* @param NamingStrategy $namingStrategy The naming strategy for database tables and columns.
54+
* @param string|UnitEnum|null $tag An optional tag to identify this database configuration.
55+
*/
2956
public function __construct(
3057
#[SensitiveParameter]
3158
public string $host = '127.0.0.1',
@@ -37,6 +64,7 @@ public function __construct(
3764
public string $password = '',
3865
#[SensitiveParameter]
3966
public string $database = 'app',
67+
public bool $persistent = false,
4068
public NamingStrategy $namingStrategy = new PluralizedSnakeCaseStrategy(),
4169
public null|string|UnitEnum $tag = null,
4270
) {}

packages/database/src/Config/SQLiteConfig.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Tempest\Database\Config;
66

7+
use PDO;
78
use SensitiveParameter;
89
use Tempest\Database\Tables\NamingStrategy;
910
use Tempest\Database\Tables\PluralizedSnakeCaseStrategy;
@@ -30,9 +31,32 @@ final class SQLiteConfig implements DatabaseConfig
3031
get => DatabaseDialect::SQLITE;
3132
}
3233

34+
public bool $usePersistentConnection {
35+
get => $this->persistent;
36+
}
37+
38+
public array $options {
39+
get {
40+
$options = [];
41+
42+
if ($this->persistent) {
43+
$options[PDO::ATTR_PERSISTENT] = true;
44+
}
45+
46+
return $options;
47+
}
48+
}
49+
50+
/**
51+
* @param string $path Path to the SQLite database file. Use ':memory:' for an in-memory database.
52+
* @param bool $persistent Whether to use persistent connections. Persistent connections are not closed at the end of the script and are cached for reuse when another script requests a connection using the same credentials.
53+
* @param NamingStrategy $namingStrategy The naming strategy for database tables and columns.
54+
* @param string|UnitEnum|null $tag An optional tag to identify this database configuration.
55+
*/
3356
public function __construct(
3457
#[SensitiveParameter]
3558
public string $path = 'localhost',
59+
public bool $persistent = false,
3660
public NamingStrategy $namingStrategy = new PluralizedSnakeCaseStrategy(),
3761
public null|string|UnitEnum $tag = null,
3862
) {}

packages/database/src/Connection/PDOConnection.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ public function connect(): void
102102
dsn: $this->config->dsn,
103103
username: $this->config->username,
104104
password: $this->config->password,
105+
options: $this->config->options,
105106
);
106107
}
107108
}

packages/database/tests/Config/DatabaseConfigTest.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace Tempest\Database\Tests\Config;
66

77
use Generator;
8+
use PDO;
9+
use Pdo\Mysql;
810
use PHPUnit\Framework\Attributes\DataProvider;
911
use PHPUnit\Framework\Attributes\Test;
1012
use PHPUnit\Framework\TestCase;
@@ -62,4 +64,58 @@ public static function provide_database_drivers(): Generator
6264
'secret',
6365
];
6466
}
67+
68+
#[DataProvider('provide_database_drivers_with_options')]
69+
#[Test]
70+
public function driver_supports_pdo_options(DatabaseConfig $driver, array $expectedOptions): void
71+
{
72+
$this->assertSame($expectedOptions, $driver->options);
73+
}
74+
75+
public static function provide_database_drivers_with_options(): Generator
76+
{
77+
yield 'mysql with SSL' => [
78+
new MysqlConfig(
79+
certificateAuthority: '/etc/ssl/certs/ca-certificates.crt',
80+
persistent: true,
81+
),
82+
[
83+
PDO::ATTR_PERSISTENT => true,
84+
Mysql::ATTR_SSL_CA => '/etc/ssl/certs/ca-certificates.crt',
85+
],
86+
];
87+
88+
yield 'mysql with all SSL options' => [
89+
new MysqlConfig(
90+
certificateAuthority: '/etc/ssl/certs/ca-certificates.crt',
91+
verifyServerCertificate: false,
92+
clientCertificate: '/path/to/cert.pem',
93+
clientKey: '/path/to/key.pem',
94+
),
95+
[
96+
Mysql::ATTR_SSL_CA => '/etc/ssl/certs/ca-certificates.crt',
97+
Mysql::ATTR_SSL_VERIFY_SERVER_CERT => false,
98+
Mysql::ATTR_SSL_CERT => '/path/to/cert.pem',
99+
Mysql::ATTR_SSL_KEY => '/path/to/key.pem',
100+
],
101+
];
102+
103+
yield 'postgresql with persistent' => [
104+
new PostgresConfig(
105+
persistent: true,
106+
),
107+
[
108+
PDO::ATTR_PERSISTENT => true,
109+
],
110+
];
111+
112+
yield 'sqlite with persistent' => [
113+
new SQLiteConfig(
114+
persistent: true,
115+
),
116+
[
117+
PDO::ATTR_PERSISTENT => true,
118+
],
119+
];
120+
}
65121
}

0 commit comments

Comments
 (0)