Skip to content

Commit 356353f

Browse files
committed
[sync] Update embedded LibDB from standalone
1 parent d430f42 commit 356353f

4 files changed

Lines changed: 275 additions & 0 deletions

File tree

src/imperazim/db/DBManager.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace imperazim\db;
6+
7+
use imperazim\db\exception\DatabaseException;
8+
9+
/**
10+
* Class DBManager
11+
* @package imperazim\db
12+
*/
13+
final class DBManager {
14+
15+
/**
16+
* Connects to the specified database using the provided configuration.
17+
* @param string $type The type of database (e.g., 'mysql', 'sqlite').
18+
* @param array $config The configuration array for the database connection.
19+
* @return mixed The database instance.
20+
* @throws DatabaseException If the connection fails or the configuration is invalid.
21+
*/
22+
public static function connect(string $type, array $config): mixed {
23+
try {
24+
switch (strtolower($type)) {
25+
case 'mysql':
26+
return Mysql::connect($config['host'], $config['username'], $config['password'], $config['database']);
27+
case 'sqlite':
28+
$directory = dirname($config['database']);
29+
$fileName = pathinfo($config['database'], PATHINFO_FILENAME);
30+
return new Sqlite3($directory, $fileName);
31+
default:
32+
throw new DatabaseException("Unsupported database type: $type");
33+
}
34+
} catch (\Exception $e) {
35+
throw new DatabaseException("Failed to connect to the database: " . $e->getMessage(), 0, $e);
36+
}
37+
}
38+
}

src/imperazim/db/Mysql.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace imperazim\db;
6+
7+
use GlobalLogger;
8+
use mysqli;
9+
use mysqli_sql_exception;
10+
use imperazim\db\exception\DatabaseException;
11+
12+
/**
13+
* Class Mysql
14+
* @package imperazim\db
15+
*/
16+
final class Mysql {
17+
18+
/**
19+
* Mysql constructor.
20+
* @param mysqli $connection The mysqli connection.
21+
*/
22+
public function __construct(private mysqli $connection) {}
23+
24+
/**
25+
* Connect to a MySQL database.
26+
* @param string $host The database host.
27+
* @param string $user The database user.
28+
* @param string $password The database password.
29+
* @param string $database The database name.
30+
* @return self A new instance of Mysql.
31+
* @throws DatabaseException If the connection fails.
32+
*/
33+
public static function connect(string $host, string $user, string $password, string $database): self {
34+
try {
35+
$connection = new mysqli($host, $user, $password, $database);
36+
if ($connection->connect_error) {
37+
throw new DatabaseException("Connection failed: " . $connection->connect_error);
38+
}
39+
return new self(connection: $connection);
40+
} catch (mysqli_sql_exception $e) {
41+
throw new DatabaseException("MySQL connection error: " . $e->getMessage(), 0, $e);
42+
}
43+
}
44+
45+
/**
46+
* Execute an SQL query and return the results.
47+
* @param string $query The SQL query to execute.
48+
* @return array The results of the query.
49+
* @throws DatabaseException If the query fails.
50+
*/
51+
public function query(string $query): array {
52+
try {
53+
$result = $this->connection->query($query);
54+
if ($this->connection->error) {
55+
throw new DatabaseException("Query failed: " . $this->connection->error);
56+
}
57+
return $result->fetch_all(MYSQLI_ASSOC);
58+
} catch (mysqli_sql_exception $e) {
59+
throw new DatabaseException("MySQL query error: " . $e->getMessage(), 0, $e);
60+
}
61+
}
62+
}

src/imperazim/db/Sqlite3.php

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace imperazim\db;
6+
7+
use GlobalLogger;
8+
use PDO;
9+
use PDOException;
10+
use imperazim\db\exception\DatabaseException;
11+
12+
/**
13+
* Class Sqlite3
14+
* @package imperazim\db
15+
*/
16+
final class Sqlite3 {
17+
18+
/** @var PDO|null */
19+
private ?PDO $sqlite = null;
20+
21+
/**
22+
* Sqlite3 constructor.
23+
* @param string $directory The directory of the file.
24+
* @param string $fileName The name of the file.
25+
*/
26+
public function __construct(
27+
private ?string $directory,
28+
private ?string $fileName
29+
) {
30+
$directory = rtrim(str_replace('//', '/', $directory . '/'), '/') . '/';
31+
try {
32+
$this->sqlite = new PDO('sqlite:' . $directory . $fileName . '.db', null, null, [
33+
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
34+
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
35+
]);
36+
} catch (PDOException $e) {
37+
throw new DatabaseException("SQLite connection error: " . $e->getMessage(), 0, $e);
38+
}
39+
}
40+
41+
/**
42+
* Creates tables if they do not exist.
43+
* @param array $tables An associative array where the key is the table name and the value is the SQL query to create the table.
44+
* @return void
45+
*/
46+
public function createTableIfNotExists(array $tables): void {
47+
try {
48+
foreach ($tables as $table => $rows) {
49+
$rows = implode(", ", array_keys($rows));
50+
$this->sqlite->exec("CREATE TABLE IF NOT EXISTS $table ($rows)");
51+
}
52+
} catch (PDOException $e) {
53+
throw new DatabaseException("SQLite create table error: " . $e->getMessage(), 0, $e);
54+
}
55+
}
56+
57+
/**
58+
* Inserts data into a specified table.
59+
* @param string $table The name of the table to insert data into.
60+
* @param array $data An associative array where the key is the column name and the value is the value to insert.
61+
* @return void
62+
*/
63+
public function insert(string $table, array $data): void {
64+
try {
65+
$columns = implode(", ", array_keys($data));
66+
$placeholders = implode(", ", array_fill(0, count($data), "?"));
67+
$values = array_values($data);
68+
69+
$sql = "INSERT INTO $table ($columns) VALUES ($placeholders)";
70+
$stmt = $this->sqlite->prepare($sql);
71+
$stmt->execute($values);
72+
} catch (PDOException $e) {
73+
throw new DatabaseException("SQLite insert error: " . $e->getMessage(), 0, $e);
74+
}
75+
}
76+
77+
/**
78+
* Selects data from a specified table with optional filters.
79+
* @param string $table The name of the table to select data from.
80+
* @param string $column The column(s) to select.
81+
* @param array $filters An array of associative arrays for filtering the results.
82+
* @return array The selected data.
83+
*/
84+
public function select(string $table, string $column, array $filters = []): array {
85+
try {
86+
$sql = "SELECT $column FROM $table";
87+
$values = [];
88+
89+
if (!empty($filters)) {
90+
$sql .= " WHERE " . $this->buildWhereClause($filters, $values);
91+
}
92+
93+
$stmt = $this->sqlite->prepare($sql);
94+
$stmt->execute($values);
95+
return $stmt->fetchAll();
96+
} catch (PDOException $e) {
97+
throw new DatabaseException("SQLite select error: " . $e->getMessage(), 0, $e);
98+
}
99+
}
100+
101+
/**
102+
* Updates data in a specified table.
103+
* @param string $table The name of the table to update data in.
104+
* @param string $column The column to update.
105+
* @param mixed $value The new value to set.
106+
* @param array $filters An array of associative arrays for filtering the rows to update.
107+
* @return bool Whether any rows were updated.
108+
*/
109+
public function update(string $table, string $column, $value, array $filters = []): bool {
110+
try {
111+
$sql = "UPDATE $table SET $column = ?";
112+
$values = [$value];
113+
if (!empty($filters)) {
114+
$sql .= " WHERE " . $this->buildWhereClause($filters, $values);
115+
}
116+
$stmt = $this->sqlite->prepare($sql);
117+
$stmt->execute($values);
118+
return $stmt->rowCount() > 0;
119+
} catch (PDOException $e) {
120+
throw new DatabaseException("SQLite update error: " . $e->getMessage(), 0, $e);
121+
}
122+
}
123+
124+
/**
125+
* Checks if a record exists in a specified table.
126+
* @param string $table The name of the table to check.
127+
* @param array $conditions An array of associative arrays for the conditions to check.
128+
* @return bool Whether the record exists.
129+
*/
130+
public function exists(string $table, array $conditions): bool {
131+
try {
132+
$sql = "SELECT COUNT(*) AS count FROM $table WHERE ";
133+
$values = [];
134+
135+
$sql .= $this->buildWhereClause($conditions, $values);
136+
137+
$stmt = $this->sqlite->prepare($sql);
138+
$stmt->execute($values);
139+
$row = $stmt->fetch();
140+
return $row['count'] > 0;
141+
} catch (PDOException $e) {
142+
throw new DatabaseException("SQLite exists error: " . $e->getMessage(), 0, $e);
143+
}
144+
}
145+
146+
/**
147+
* Builds a WHERE clause from an array of conditions.
148+
* @param array $filters An array of associative arrays for filtering the results.
149+
* @param array $values Reference to the values array to be used in the prepared statement.
150+
* @return string The WHERE clause.
151+
*/
152+
private function buildWhereClause(array $filters, array &$values): string {
153+
$whereClauses = [];
154+
foreach ($filters as $filter) {
155+
$clauses = [];
156+
foreach ($filter as $key => $value) {
157+
$clauses[] = "$key = ?";
158+
$values[] = $value;
159+
}
160+
$whereClauses[] = implode(" AND ", $clauses);
161+
}
162+
return implode(" AND ", $whereClauses);
163+
}
164+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace imperazim\db\exception;
6+
7+
/**
8+
* Class DatabaseException
9+
* @package imperazim\db\exception
10+
*/
11+
class DatabaseException extends \RuntimeException {}

0 commit comments

Comments
 (0)