Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
76 / 76
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
PdoRegistry
100.00% covered (success)
100.00%
76 / 76
100.00% covered (success)
100.00%
8 / 8
13
100.00% covered (success)
100.00%
1 / 1
 initializeSqlite
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 cleanupSqlite
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 initializeMysql
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
3
 cleanupMysql
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 initializePostgresql
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
3
 cleanupPostgresql
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getConnection
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 generateUniqueDbName
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3// ╔════════════════════════════════════════════════════════════╗
4// ║ MIT Licence (#Expat) - https://opensource.org/licenses/MIT ║
5// ║ Copyright 2026 Frederic Poeydomenge <dyno@phexium.com>     ║
6// ╚════════════════════════════════════════════════════════════╝
7
8declare(strict_types=1);
9
10namespace Tests\Phexium\Integration\Support;
11
12use PDO;
13
14final class PdoRegistry
15{
16    private static ?PDO $pdo = null;
17
18    public static function initializeSqlite(bool $schemaProduction = false): string
19    {
20        $dbName = 'sqlite::memory:';
21
22        $pdo = new PDO($dbName);
23        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
24
25        $schemaFile = ROOT_DIR.'/database/schema.sqlite.sql';
26
27        if (!$schemaProduction) {
28            $schemaFile = __DIR__.'/schema.sqlite.sql';
29        }
30        $schema = file_get_contents($schemaFile);
31
32        $pdo->exec($schema);
33
34        self::$pdo = $pdo;
35
36        return $dbName;
37    }
38
39    public static function cleanupSqlite(): void
40    {
41        // Nothing to do
42    }
43
44    public static function initializeMysql(bool $schemaProduction = false): string
45    {
46        $host = 'mariadb-in-memory';
47        $dbName = self::generateUniqueDbName();
48        $user = 'root';
49        $password = 'root';
50
51        $pdo = new PDO(
52            sprintf('mysql:host=%s;charset=utf8mb4', $host),
53            $user,
54            $password,
55            [
56                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
57                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
58            ]
59        );
60        $pdo->exec(sprintf('CREATE DATABASE %s', $dbName));
61        $pdo->exec(sprintf('USE %s', $dbName));
62
63        $schemaFile = ROOT_DIR.'/database/schema.mysql.sql';
64
65        if (!$schemaProduction) {
66            $schemaFile = __DIR__.'/schema.mysql.sql';
67        }
68        $schema = file_get_contents($schemaFile);
69
70        $statements = array_filter(
71            array_map(trim(...), explode(';', $schema)),
72            fn ($stmt): bool => $stmt !== ''
73        );
74
75        foreach ($statements as $statement) {
76            $pdo->exec($statement);
77        }
78
79        self::$pdo = $pdo;
80
81        return $dbName;
82    }
83
84    public static function cleanupMysql(string $dbName): void
85    {
86        self::$pdo->exec(sprintf('DROP DATABASE IF EXISTS %s', $dbName));
87    }
88
89    public static function initializePostgresql(bool $schemaProduction = false): string
90    {
91        $host = 'postgres-in-memory';
92        $dbName = self::generateUniqueDbName();
93        $user = 'postgres';
94        $password = 'postgres';
95
96        $pdoTemp = new PDO(sprintf('pgsql:host=%s;dbname=postgres', $host), $user, $password);
97        $pdoTemp->exec(sprintf('CREATE DATABASE %s', $dbName));
98
99        $pdo = new PDO(
100            sprintf('pgsql:host=%s;dbname=%s', $host, $dbName),
101            $user,
102            $password,
103            [
104                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
105                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
106            ]
107        );
108
109        $schemaFile = ROOT_DIR.'/database/schema.postgresql.sql';
110
111        if (!$schemaProduction) {
112            $schemaFile = __DIR__.'/schema.postgresql.sql';
113        }
114        $schema = file_get_contents($schemaFile);
115
116        $statements = array_filter(
117            array_map(trim(...), explode(';', $schema)),
118            fn ($stmt): bool => $stmt !== ''
119        );
120
121        foreach ($statements as $statement) {
122            $pdo->exec($statement);
123        }
124
125        self::$pdo = $pdo;
126
127        return $dbName;
128    }
129
130    public static function cleanupPostgresql(string $dbName): void
131    {
132        $pdoTemp = new PDO('pgsql:host=postgres-in-memory;dbname=postgres', 'postgres', 'postgres');
133        $pdoTemp->exec(sprintf(
134            "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '%s' AND pid <> pg_backend_pid()",
135            $dbName
136        ));
137        $pdoTemp->exec(sprintf('DROP DATABASE IF EXISTS %s', $dbName));
138    }
139
140    public static function getConnection(): ?PDO
141    {
142        return self::$pdo;
143    }
144
145    private static function generateUniqueDbName(): string
146    {
147        $data = random_bytes(16);
148        $hash = hash('xxh3', $data);
149
150        return sprintf('phexium_test_%s', $hash);
151    }
152}