From b69be24727a314d199d9297bae396e21c20914e7 Mon Sep 17 00:00:00 2001 From: overflowerror Date: Fri, 24 Nov 2023 21:06:53 +0100 Subject: [PATCH] feat: Add basic persistence layer + migration framework --- .gitignore | 4 +- core.php | 9 ++- credentials.templ.php | 7 +++ persistence/connection.php | 7 +++ persistence/migrate.php | 107 ++++++++++++++++++++++++++++++++ persistence/migrations/.gitkeep | 0 6 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 credentials.templ.php create mode 100644 persistence/connection.php create mode 100644 persistence/migrate.php create mode 100644 persistence/migrations/.gitkeep diff --git a/.gitignore b/.gitignore index 723ef36..f14dc36 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -.idea \ No newline at end of file +.idea + +credentials.php \ No newline at end of file diff --git a/core.php b/core.php index 36140e6..490d9ad 100644 --- a/core.php +++ b/core.php @@ -7,9 +7,12 @@ define("MAINTENANCE_MODE", require(ROOT . "/maintenance.php")); if (MAINTENANCE_MODE) { require(ROOT . "/templates/maintenance.php"); } else { + $connection = require_once(ROOT . "/persistence/connection.php"); + (require(ROOT . "/persistence/migrate.php"))($connection); + $router = require(ROOT . "/router/Router.php"); - (require(ROOT . "/controllers/routes.php"))($router); - - $router->execute(); + $router->execute([ + "DB_CONNECTION" => $connection, + ]); } diff --git a/credentials.templ.php b/credentials.templ.php new file mode 100644 index 0000000..562d6e7 --- /dev/null +++ b/credentials.templ.php @@ -0,0 +1,7 @@ +query(<<rowCount() == 0 + ) { + if ($connection->exec(<<errorCode()); + } + } +} + +function getAllMigrations() { + $files = scandir(ROOT . "/persistence/migrations/"); + $files = array_values(array_filter($files, fn($f) => $f[0] != ".")); + sort($files); + + $migrations = []; + + foreach ($files as $file) { + $delimiterPos = strpos($file, "_"); + $migrations[intval(substr($file, 0, $delimiterPos))] = $file; + } + + return $migrations; +} + +function getAppliedMigrations(PDO $connection) { + $result = $connection->query(<<fetchAll() as $row) { + $migrations[$row["id"]] = $row["file"]; + } + + return $migrations; +} + +function getMigrationsToApply(PDO $connection) { + $all = getAllMigrations(); + $applied = getAppliedMigrations($connection); + + foreach ($applied as $id => $file) { + unset($all[$id]); + } + + return $all; +} + +function executeSqlScript(PDO $connection, string $sql, string $file) { + if ($connection->exec($sql) === false) { + die("failed to apply migration " . $file . ": " . $connection->errorCode()); + } +} + +function applyMigration(PDO $connection, int $id, string $file) { + $connection->beginTransaction(); + + $sql = file_get_contents(ROOT . "/persistence/migrations/" . $file); + if (!$sql) { + die("Unable to read migration file: " . $file); + } + + executeSqlScript($connection, $sql, $file); + + $statement = $connection->prepare(<<execute([$id, $file]); + + try { + $connection->commit(); + } catch (PDOException $e) { + // this might happen if the migration script contains a DDL statement + // -> ignore + } +} + +return function(PDO $connection) { + ensureDbStructureForMigrations($connection); + + $migrations = getMigrationsToApply($connection); + foreach ($migrations as $id => $file) { + applyMigration($connection, $id, $file); + } +}; diff --git a/persistence/migrations/.gitkeep b/persistence/migrations/.gitkeep new file mode 100644 index 0000000..e69de29