Passed
Branch main (d8f02c)
by Sílvio
02:57
created

MigrationManager::mysqlSchema()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 7
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 15
rs 10
1
<?php
2
3
namespace Silviooosilva\CacheerPhp\Core;
4
5
use PDO;
6
use PDOException;
7
use Silviooosilva\CacheerPhp\Enums\DatabaseDriver;
8
9
/**
10
 * Class MigrationManager
11
 * @author Sílvio Silva <https://github.com/silviooosilva>
12
 * @package Silviooosilva\CacheerPhp
13
 */
14
class MigrationManager
15
{
16
    /**
17
     * Executes the migration process for the database.
18
     * 
19
     * @param PDO $connection
20
     * @return void
21
     */
22
    public static function migrate(PDO $connection, ?string $tableName = null): void
23
    {
24
        try {
25
            self::prepareDatabase($connection);
26
            $queries = self::getMigrationQueries($connection, $tableName);
27
            foreach ($queries as $query) {
28
                if (trim($query)) {
29
                    $connection->exec($query);
30
                }
31
            }
32
        } catch (PDOException $exception) {
33
            throw new PDOException($exception->getMessage(), $exception->getCode());
34
        }
35
    }
36
37
    /**
38
     * Prepares the database connection for migration.
39
     * 
40
     * @param PDO $connection
41
     * @return void
42
     */
43
    private static function prepareDatabase(PDO $connection): void
44
    {
45
        $driver = DatabaseDriver::tryFrom($connection->getAttribute(PDO::ATTR_DRIVER_NAME));
46
        if ($driver !== DatabaseDriver::SQLITE) {
47
            $dbname = CACHEER_DATABASE_CONFIG[Connect::getConnection()->value]['dbname'];
48
            $connection->exec("USE $dbname");
49
        }
50
    }
51
52
    /**
53
     * Generates the SQL queries needed for the migration based on the database driver.
54
     * 
55
     * @param PDO $connection
56
     * @param string|null $tableName
57
     * @return array
58
     */
59
    private static function getMigrationQueries(PDO $connection, ?string $tableName = null): array
60
    {
61
        $driver = self::resolveDriver($connection);
62
        $createdAtDefault = self::createdAtDefault($driver);
63
        $table = self::resolveTableName($tableName);
64
65
        $query = self::buildSchemaQuery($driver, $table, $createdAtDefault);
66
        return self::splitQueries($query);
67
    }
68
69
    /**
70
     * @param PDO $connection
71
     * @return DatabaseDriver|null
72
     */
73
    private static function resolveDriver(PDO $connection): ?DatabaseDriver
74
    {
75
        return DatabaseDriver::tryFrom($connection->getAttribute(PDO::ATTR_DRIVER_NAME));
76
    }
77
78
    /**
79
     * @param string|null $tableName
80
     * @return string
81
     */
82
    private static function resolveTableName(?string $tableName): string
83
    {
84
        if ($tableName) {
85
            return $tableName;
86
        }
87
        if (defined('CACHEER_TABLE')) {
88
            return CACHEER_TABLE;
89
        }
90
        return 'cacheer_table';
91
    }
92
93
    /**
94
     * @param DatabaseDriver|null $driver
95
     * @return string
96
     */
97
    private static function createdAtDefault(?DatabaseDriver $driver): string
98
    {
99
        return ($driver === DatabaseDriver::PGSQL) ? 'DEFAULT NOW()' : 'DEFAULT CURRENT_TIMESTAMP';
100
    }
101
102
    /**
103
     * @param DatabaseDriver|null $driver
104
     * @param string $table
105
     * @param string $createdAtDefault
106
     * @return string
107
     */
108
    private static function buildSchemaQuery(?DatabaseDriver $driver, string $table, string $createdAtDefault): string
109
    {
110
        if ($driver === DatabaseDriver::SQLITE) {
111
            return self::sqliteSchema($table, $createdAtDefault);
112
        }
113
        if ($driver === DatabaseDriver::PGSQL) {
114
            return self::pgsqlSchema($table, $createdAtDefault);
115
        }
116
        return self::mysqlSchema($table, $createdAtDefault);
117
    }
118
119
    /**
120
     * @param string $table
121
     * @param string $createdAtDefault
122
     * @return string
123
     */
124
    private static function sqliteSchema(string $table, string $createdAtDefault): string
125
    {
126
        return "
127
                CREATE TABLE IF NOT EXISTS {$table} (
128
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
129
                    cacheKey VARCHAR(255) NOT NULL,
130
                    cacheData TEXT NOT NULL,
131
                    cacheNamespace VARCHAR(255),
132
                    expirationTime DATETIME NOT NULL,
133
                    created_at DATETIME $createdAtDefault,
134
                    UNIQUE(cacheKey, cacheNamespace)
135
                );
136
                CREATE INDEX IF NOT EXISTS idx_{$table}_cacheKey ON {$table} (cacheKey);
137
                CREATE INDEX IF NOT EXISTS idx_{$table}_cacheNamespace ON {$table} (cacheNamespace);
138
                CREATE INDEX IF NOT EXISTS idx_{$table}_expirationTime ON {$table} (expirationTime);
139
                CREATE INDEX IF NOT EXISTS idx_{$table}_key_namespace ON {$table} (cacheKey, cacheNamespace);
140
            ";
141
    }
142
143
    /**
144
     * @param string $table
145
     * @param string $createdAtDefault
146
     * @return string
147
     */
148
    private static function pgsqlSchema(string $table, string $createdAtDefault): string
149
    {
150
        return "
151
                CREATE TABLE IF NOT EXISTS {$table} (
152
                    id SERIAL PRIMARY KEY,
153
                    cacheKey VARCHAR(255) NOT NULL,
154
                    cacheData TEXT NOT NULL,
155
                    cacheNamespace VARCHAR(255),
156
                    expirationTime TIMESTAMP NOT NULL,
157
                    created_at TIMESTAMP $createdAtDefault,
158
                    UNIQUE(cacheKey, cacheNamespace)
159
                );
160
                CREATE INDEX IF NOT EXISTS idx_{$table}_cacheKey ON {$table} (cacheKey);
161
                CREATE INDEX IF NOT EXISTS idx_{$table}_cacheNamespace ON {$table} (cacheNamespace);
162
                CREATE INDEX IF NOT EXISTS idx_{$table}_expirationTime ON {$table} (expirationTime);
163
                CREATE INDEX IF NOT EXISTS idx_{$table}_key_namespace ON {$table} (cacheKey, cacheNamespace);
164
            ";
165
    }
166
167
    /**
168
     * @param string $table
169
     * @param string $createdAtDefault
170
     * @return string
171
     */
172
    private static function mysqlSchema(string $table, string $createdAtDefault): string
173
    {
174
        return "
175
                CREATE TABLE IF NOT EXISTS {$table} (
176
                    id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
177
                    cacheKey VARCHAR(255) NOT NULL,
178
                    cacheData LONGTEXT NOT NULL,
179
                    cacheNamespace VARCHAR(255) NULL,
180
                    expirationTime DATETIME NOT NULL,
181
                    created_at TIMESTAMP $createdAtDefault,
182
                    UNIQUE KEY unique_cache_key_namespace (cacheKey, cacheNamespace),
183
                    KEY idx_{$table}_cacheKey (cacheKey),
184
                    KEY idx_{$table}_cacheNamespace (cacheNamespace),
185
                    KEY idx_{$table}_expirationTime (expirationTime),
186
                    KEY idx_{$table}_key_namespace (cacheKey, cacheNamespace)
187
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
188
            ";
189
    }
190
191
    /**
192
     * @param string $query
193
     * @return array
194
     */
195
    private static function splitQueries(string $query): array
196
    {
197
        return array_filter(array_map('trim', explode(';', $query)));
198
    }
199
}
200