Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
73 / 73
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
PdoRegistry
100.00% covered (success)
100.00%
73 / 73
100.00% covered (success)
100.00%
8 / 8
13
100.00% covered (success)
100.00%
1 / 1
 initializeSqlite
100.00% covered (success)
100.00%
9 / 9
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%
26 / 26
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%
26 / 26
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\Component\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
24        $schemaFile = ROOT_DIR.'/app/demo/database/schema.sqlite.sql';
25
26        if (!$schemaProduction) {
27            $schemaFile = __DIR__.'/schema.sqlite.sql';
28        }
29        $schema = file_get_contents($schemaFile);
30
31        $pdo->exec($schema);
32
33        self::$pdo = $pdo;
34
35        return $dbName;
36    }
37
38    public static function cleanupSqlite(): void
39    {
40        // Nothing to do
41    }
42
43    public static function initializeMysql(bool $schemaProduction = false): string
44    {
45        $host = 'mysql-in-memory';
46        $dbName = self::generateUniqueDbName();
47        $user = 'root';
48        $password = 'root';
49
50        $pdo = new PDO(
51            sprintf('mysql:host=%s;charset=utf8mb4', $host),
52            $user,
53            $password,
54            [
55                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
56            ]
57        );
58        $pdo->exec(sprintf('CREATE DATABASE %s', $dbName));
59        $pdo->exec(sprintf('USE %s', $dbName));
60
61        $schemaFile = ROOT_DIR.'/app/demo/database/schema.mysql.sql';
62
63        if (!$schemaProduction) {
64            $schemaFile = __DIR__.'/schema.mysql.sql';
65        }
66        $schema = file_get_contents($schemaFile);
67
68        $statements = array_filter(
69            array_map(trim(...), explode(';', $schema)),
70            fn ($stmt): bool => $stmt !== ''
71        );
72
73        foreach ($statements as $statement) {
74            $pdo->exec($statement);
75        }
76
77        self::$pdo = $pdo;
78
79        return $dbName;
80    }
81
82    public static function cleanupMysql(string $dbName): void
83    {
84        self::$pdo->exec(sprintf('DROP DATABASE IF EXISTS %s', $dbName));
85    }
86
87    public static function initializePostgresql(bool $schemaProduction = false): string
88    {
89        $host = 'postgres-in-memory';
90        $dbName = self::generateUniqueDbName();
91        $user = 'postgres';
92        $password = 'postgres';
93
94        $pdoTemp = new PDO(sprintf('pgsql:host=%s;dbname=postgres', $host), $user, $password);
95        $pdoTemp->exec(sprintf('CREATE DATABASE %s', $dbName));
96
97        $pdo = new PDO(
98            sprintf('pgsql:host=%s;dbname=%s', $host, $dbName),
99            $user,
100            $password,
101            [
102                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
103            ]
104        );
105
106        $schemaFile = ROOT_DIR.'/app/demo/database/schema.postgresql.sql';
107
108        if (!$schemaProduction) {
109            $schemaFile = __DIR__.'/schema.postgresql.sql';
110        }
111        $schema = file_get_contents($schemaFile);
112
113        $statements = array_filter(
114            array_map(trim(...), explode(';', $schema)),
115            fn ($stmt): bool => $stmt !== ''
116        );
117
118        foreach ($statements as $statement) {
119            $pdo->exec($statement);
120        }
121
122        self::$pdo = $pdo;
123
124        return $dbName;
125    }
126
127    public static function cleanupPostgresql(string $dbName): void
128    {
129        $pdoTemp = new PDO('pgsql:host=postgres-in-memory;dbname=postgres', 'postgres', 'postgres');
130        $pdoTemp->exec(sprintf(
131            "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '%s' AND pid <> pg_backend_pid()",
132            $dbName
133        ));
134        $pdoTemp->exec(sprintf('DROP DATABASE IF EXISTS %s', $dbName));
135    }
136
137    public static function getConnection(): ?PDO
138    {
139        return self::$pdo;
140    }
141
142    private static function generateUniqueDbName(): string
143    {
144        $data = random_bytes(16);
145        $hash = hash('xxh3', $data);
146
147        return sprintf('phexium_test_%s', $hash);
148    }
149}