Skip to content

Commit 0cedf74

Browse files
committed
Add comprehensive type safety and validation to AsyncDB initialization
- Add validation error tracking to prevent repeated failed initializations - Implement strict type checking for database configuration arrays - Add PHPDoc type annotations for all public method parameters and return types - Validate database connection configuration structure and types - Add proper error handling with exception wrapping during initialization - Ensure pool size is validated as positive integer
1 parent 99b7b8b commit 0cedf74

File tree

1 file changed

+70
-25
lines changed

1 file changed

+70
-25
lines changed

src/Api/AsyncDb.php

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,71 @@
1515
class AsyncDB
1616
{
1717
private static bool $isInitialized = false;
18+
private static bool $hasValidationError = false;
1819

1920
/**
2021
* The core of the new design: A private, self-configuring initializer.
2122
* This method is called by every public method to ensure the system is ready.
23+
* Validates only once if successful, but re-validates if there were previous errors.
2224
*/
2325
private static function initializeIfNeeded(): void
2426
{
25-
if (self::$isInitialized) {
27+
if (self::$isInitialized && !self::$hasValidationError) {
2628
return;
2729
}
2830

29-
$configLoader = ConfigLoader::getInstance();
30-
31-
$dbConfigAll = $configLoader->get('database');
32-
33-
if ($dbConfigAll === null) {
34-
throw new \RuntimeException("Database configuration not found. Ensure 'config/database.php' exists in your project root.");
35-
}
36-
37-
$defaultConnection = $dbConfigAll['default'];
38-
$connectionConfig = $dbConfigAll['connections'][$defaultConnection] ?? null;
39-
$poolSize = $dbConfigAll['pool_size'] ?? 10;
40-
41-
if ($connectionConfig === null) {
42-
throw new \RuntimeException("Default database connection '{$defaultConnection}' not defined in your database config.");
31+
self::$hasValidationError = false;
32+
33+
try {
34+
$configLoader = ConfigLoader::getInstance();
35+
$dbConfigAll = $configLoader->get('database');
36+
37+
if (!is_array($dbConfigAll)) {
38+
throw new \RuntimeException("Database configuration not found. Ensure 'config/database.php' exists in your project root.");
39+
}
40+
41+
$defaultConnection = $dbConfigAll['default'] ?? null;
42+
if (!is_string($defaultConnection)) {
43+
throw new \RuntimeException("Default connection name must be a string in your database config.");
44+
}
45+
46+
$connections = $dbConfigAll['connections'] ?? null;
47+
if (!is_array($connections)) {
48+
throw new \RuntimeException("Database connections configuration must be an array.");
49+
}
50+
51+
if (!isset($connections[$defaultConnection]) || !is_array($connections[$defaultConnection])) {
52+
throw new \RuntimeException("Default database connection '{$defaultConnection}' not defined in your database config.");
53+
}
54+
55+
$connectionConfig = $connections[$defaultConnection];
56+
57+
/** @var array<string, mixed> $validatedConfig */
58+
$validatedConfig = [];
59+
foreach ($connectionConfig as $key => $value) {
60+
if (!is_string($key)) {
61+
throw new \RuntimeException("Database connection configuration must have string keys only.");
62+
}
63+
$validatedConfig[$key] = $value;
64+
}
65+
66+
$poolSize = 10;
67+
if (isset($dbConfigAll['pool_size'])) {
68+
if (!is_int($dbConfigAll['pool_size']) || $dbConfigAll['pool_size'] < 1) {
69+
throw new \RuntimeException("Database pool size must be a positive integer.");
70+
}
71+
$poolSize = $dbConfigAll['pool_size'];
72+
}
73+
74+
AsyncPDO::init($validatedConfig, $poolSize);
75+
self::$isInitialized = true;
76+
77+
} catch (\Exception $e) {
78+
self::$hasValidationError = true;
79+
self::$isInitialized = false;
80+
81+
throw $e;
4382
}
44-
45-
AsyncPDO::init($connectionConfig, $poolSize);
46-
self::$isInitialized = true;
4783
}
4884

4985
/**
@@ -54,6 +90,7 @@ public static function reset(): void
5490
AsyncPDO::reset();
5591
ConfigLoader::reset();
5692
self::$isInitialized = false;
93+
self::$hasValidationError = false;
5794
}
5895

5996
/**
@@ -62,57 +99,65 @@ public static function reset(): void
6299
public static function table(string $table): AsyncQueryBuilder
63100
{
64101
self::initializeIfNeeded();
65-
66102
return new AsyncQueryBuilder($table);
67103
}
68104

69105
/**
70106
* Execute a raw query.
107+
*
108+
* @param array<string, mixed> $bindings
109+
* @return PromiseInterface<array<int, array<string, mixed>>>
71110
*/
72111
public static function raw(string $sql, array $bindings = []): PromiseInterface
73112
{
74113
self::initializeIfNeeded();
75-
76114
return AsyncPDO::query($sql, $bindings);
77115
}
78116

79117
/**
80118
* Execute a raw query and return the first result.
119+
*
120+
* @param array<string, mixed> $bindings
121+
* @return PromiseInterface<array<string, mixed>|false>
81122
*/
82123
public static function rawFirst(string $sql, array $bindings = []): PromiseInterface
83124
{
84125
self::initializeIfNeeded();
85-
86126
return AsyncPDO::fetchOne($sql, $bindings);
87127
}
88128

89129
/**
90130
* Execute a raw query and return a single scalar value.
131+
*
132+
* @param array<string, mixed> $bindings
133+
* @return PromiseInterface<mixed>
91134
*/
92135
public static function rawValue(string $sql, array $bindings = []): PromiseInterface
93136
{
94137
self::initializeIfNeeded();
95-
96138
return AsyncPDO::fetchValue($sql, $bindings);
97139
}
98140

99141
/**
100142
* Execute a raw statement (INSERT, UPDATE, DELETE).
143+
*
144+
* @param array<string, mixed> $bindings
145+
* @return PromiseInterface<int>
101146
*/
102147
public static function rawExecute(string $sql, array $bindings = []): PromiseInterface
103148
{
104149
self::initializeIfNeeded();
105-
106150
return AsyncPDO::execute($sql, $bindings);
107151
}
108152

109153
/**
110154
* Run a database transaction.
155+
*
156+
* @return PromiseInterface<mixed>
111157
*/
112158
public static function transaction(callable $callback): PromiseInterface
113159
{
114160
self::initializeIfNeeded();
115-
116161
return AsyncPDO::transaction($callback);
117162
}
118-
}
163+
}

0 commit comments

Comments
 (0)