]> git.leonardobizzoni.com Git - highschool-graduation-project/commitdiff
Connecting to db + migrations
authorLeonardoBizzoni <leo2002714@gmail.com>
Mon, 18 Apr 2022 08:50:23 +0000 (10:50 +0200)
committerLeonardoBizzoni <leo2002714@gmail.com>
Mon, 18 Apr 2022 08:50:23 +0000 (10:50 +0200)
12 files changed:
README.org
dockerfiles/web/Dockerfile
www/.env.example [new file with mode: 0644]
www/.gitignore
www/Migrations/m_1650263661_Initial.php [new file with mode: 0644]
www/Migrations/m_1650271236_addPasswordToUser.php [new file with mode: 0644]
www/composer.json
www/composer.lock
www/core/Application.php
www/core/Database.php [new file with mode: 0644]
www/migrationScript.php [new file with mode: 0644]
www/pub/index.php

index 778e714f92bea2e0e25f9888292519ebc3fda6cd..0517831d2d02e6f4646f62bb0cbd9685884b7cc0 100644 (file)
@@ -11,6 +11,7 @@
 - [[#realizzazione][Realizzazione]]
   - [[#entry-point---indexphp][Entry point - index.php]]
   - [[#core][Core]]
+  - [[#migrations][Migrations]]
   - [[#models][Models]]
   - [[#controllers][Controllers]]
 
@@ -208,6 +209,20 @@ if ($ruleName == self::RULE_MATCH && $value != $this->{$rule["match"]}) {
 }
 #+end_src
 
+*** Database class
+Utilizza PDO per effettuare la connessione al server mariadb in esecuzione nel docker container.
+Sia le credenziali di accesso al database che il domain service name (DSN) sono salvate nel file "www/.env" (vedi [[./www/.env.example][.env.example]]) e per leggerle si utilizza il package [[https://github.com/vlucas/phpdotenv][phpdotenv]].
+
+Installazione:
+#+begin_src bash
+cd www
+composer require vlucas/phpdotenv
+#+end_src
+
+** Migrations
+Contengono i cambiamenti efftuati in ordine sul database.
+/Formato migration: touch "m_$(date +%s)_name.php"/
+
 ** Models
 Le classi "Model" gestiscono i dati presenti nel database e controlla che i dati seguano delle determinate regole.
 Tutte le classi Model derivano dalla classe "BaseModel".
index 0e1ccc98872ea188f8e2afe46c3497fd4e367d6f..480a6ca5f7b309db07c17f600b105d37a148a6cf 100644 (file)
@@ -5,6 +5,7 @@ RUN apk update && apk add --no-cache \
     php8 \
     php8-fpm \
     php8-mysqli \
+    php8-pdo \
     nginx
 
 RUN docker-php-ext-install pdo pdo_mysql mysqli
diff --git a/www/.env.example b/www/.env.example
new file mode 100644 (file)
index 0000000..f1a3ca7
--- /dev/null
@@ -0,0 +1,3 @@
+DB_DSN = mysql:host=containerAddress;port=3306;dbname=dbName
+DB_USER = root
+DB_PASSWORD = root
index 57872d0f1e5f46731396e93c4e22b149809798f8..3d5163b66e37c0458c416d9b4f154d105c52df70 100644 (file)
@@ -1 +1,2 @@
 /vendor/
+.env
diff --git a/www/Migrations/m_1650263661_Initial.php b/www/Migrations/m_1650263661_Initial.php
new file mode 100644 (file)
index 0000000..88b7c31
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+use app\core\Application;
+
+class m_1650263661_Initial {
+    public function up() {
+        $db = Application::$app->db;
+
+        $sql = "CREATE TABLE users (
+                id INT AUTO_INCREMENT PRIMARY KEY,
+                email VARCHAR(255) NOT NULL,
+                firstname VARCHAR(255) NOT NULL,
+                lastname VARCHAR(255) NOT NULL,
+                status TINYINT NOT NULL,
+                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+              ) ENGINE=INNODB;";
+
+        $db->pdo->exec($sql);
+    }
+
+    public function down() {
+        $db = Application::$app->db;
+
+        $sql = "DROP TABLE users;";
+
+        $db->pdo->exec($sql);
+    }
+}
+?>
diff --git a/www/Migrations/m_1650271236_addPasswordToUser.php b/www/Migrations/m_1650271236_addPasswordToUser.php
new file mode 100644 (file)
index 0000000..4069115
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+
+use app\core\Application;
+
+class m_1650271236_addPasswordToUser {
+    public function up() {
+        $db = Application::$app->db;
+
+        $sql = "ALTER TABLE users ADD COLUMN password VARCHAR(512) NOT NULL;";
+
+        $db->pdo->exec($sql);
+    }
+
+    public function down() {
+        $db = Application::$app->db;
+
+        $sql = "ALTER TABLE users DROP COLUMN password;";
+
+        $db->pdo->exec($sql);
+    }
+}
+?>
index d7efd5b202f8c5be596c6640800ea4337f1d3865..c7ea11abb1e396d479a1cb15cef6f1108a3f73be 100644 (file)
@@ -11,5 +11,7 @@
             "app\\": "./"
         }
     },
-    "require": {}
+    "require": {
+        "vlucas/phpdotenv": "^5.4"
+    }
 }
index b9bf3efabb449ec78a50b09144fd8c9a1994c99c..b0e7f041603edf0f9c1fff9a2a5a7bfb151fe31e 100644 (file)
@@ -4,8 +4,470 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "9cda257e3e012f147b9543a67efa2819",
-    "packages": [],
+    "content-hash": "969f7975a8700b8eec51b07397e5007c",
+    "packages": [
+        {
+            "name": "graham-campbell/result-type",
+            "version": "v1.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/GrahamCampbell/Result-Type.git",
+                "reference": "0690bde05318336c7221785f2a932467f98b64ca"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/0690bde05318336c7221785f2a932467f98b64ca",
+                "reference": "0690bde05318336c7221785f2a932467f98b64ca",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0 || ^8.0",
+                "phpoption/phpoption": "^1.8"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "GrahamCampbell\\ResultType\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Graham Campbell",
+                    "email": "hello@gjcampbell.co.uk",
+                    "homepage": "https://github.com/GrahamCampbell"
+                }
+            ],
+            "description": "An Implementation Of The Result Type",
+            "keywords": [
+                "Graham Campbell",
+                "GrahamCampbell",
+                "Result Type",
+                "Result-Type",
+                "result"
+            ],
+            "support": {
+                "issues": "https://github.com/GrahamCampbell/Result-Type/issues",
+                "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-11-21T21:41:47+00:00"
+        },
+        {
+            "name": "phpoption/phpoption",
+            "version": "1.8.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/schmittjoh/php-option.git",
+                "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15",
+                "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.4.1",
+                "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.8-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PhpOption\\": "src/PhpOption/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Johannes M. Schmitt",
+                    "email": "schmittjoh@gmail.com",
+                    "homepage": "https://github.com/schmittjoh"
+                },
+                {
+                    "name": "Graham Campbell",
+                    "email": "hello@gjcampbell.co.uk",
+                    "homepage": "https://github.com/GrahamCampbell"
+                }
+            ],
+            "description": "Option Type for PHP",
+            "keywords": [
+                "language",
+                "option",
+                "php",
+                "type"
+            ],
+            "support": {
+                "issues": "https://github.com/schmittjoh/php-option/issues",
+                "source": "https://github.com/schmittjoh/php-option/tree/1.8.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-12-04T23:24:31+00:00"
+        },
+        {
+            "name": "symfony/polyfill-ctype",
+            "version": "v1.25.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-ctype.git",
+                "reference": "30885182c981ab175d4d034db0f6f469898070ab"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
+                "reference": "30885182c981ab175d4d034db0f6f469898070ab",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "provide": {
+                "ext-ctype": "*"
+            },
+            "suggest": {
+                "ext-ctype": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.23-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Ctype\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Gert de Pagter",
+                    "email": "BackEndTea@gmail.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for ctype functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "ctype",
+                "polyfill",
+                "portable"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-10-20T20:35:02+00:00"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.25.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825",
+                "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "provide": {
+                "ext-mbstring": "*"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.23-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-11-30T18:21:41+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php80",
+            "version": "v1.25.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php80.git",
+                "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c",
+                "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.23-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php80\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ion Bazan",
+                    "email": "ion.bazan@gmail.com"
+                },
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-03-04T08:16:47+00:00"
+        },
+        {
+            "name": "vlucas/phpdotenv",
+            "version": "v5.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/vlucas/phpdotenv.git",
+                "reference": "264dce589e7ce37a7ba99cb901eed8249fbec92f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/264dce589e7ce37a7ba99cb901eed8249fbec92f",
+                "reference": "264dce589e7ce37a7ba99cb901eed8249fbec92f",
+                "shasum": ""
+            },
+            "require": {
+                "ext-pcre": "*",
+                "graham-campbell/result-type": "^1.0.2",
+                "php": "^7.1.3 || ^8.0",
+                "phpoption/phpoption": "^1.8",
+                "symfony/polyfill-ctype": "^1.23",
+                "symfony/polyfill-mbstring": "^1.23.1",
+                "symfony/polyfill-php80": "^1.23.1"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.4.1",
+                "ext-filter": "*",
+                "phpunit/phpunit": "^7.5.20 || ^8.5.21 || ^9.5.10"
+            },
+            "suggest": {
+                "ext-filter": "Required to use the boolean validator."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Dotenv\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Graham Campbell",
+                    "email": "hello@gjcampbell.co.uk",
+                    "homepage": "https://github.com/GrahamCampbell"
+                },
+                {
+                    "name": "Vance Lucas",
+                    "email": "vance@vancelucas.com",
+                    "homepage": "https://github.com/vlucas"
+                }
+            ],
+            "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
+            "keywords": [
+                "dotenv",
+                "env",
+                "environment"
+            ],
+            "support": {
+                "issues": "https://github.com/vlucas/phpdotenv/issues",
+                "source": "https://github.com/vlucas/phpdotenv/tree/v5.4.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-12-12T23:22:04+00:00"
+        }
+    ],
     "packages-dev": [],
     "aliases": [],
     "minimum-stability": "stable",
index 9ffc41642e833d00b6f056cf8682d2e8a27d3499..a0abfe32026ac47d90734203be8d1a49e7f39ada 100644 (file)
@@ -7,17 +7,19 @@ class Application {
     public Router $router;
     public Request $req;
     public Response $res;
+    public Database $db;
 
     public static Application $app;
     public static string $ROOT_DIR;
 
-    public function __construct(string $root) {
+    public function __construct(string $root, array $config) {
         self::$ROOT_DIR = $root;
         self::$app = $this;
 
         $this->req = new Request();
         $this->res = new Response();
         $this->router = new Router($this->req, $this->res);
+        $this->db = new Database($config["db"]);
     }
 
     public function run() {
diff --git a/www/core/Database.php b/www/core/Database.php
new file mode 100644 (file)
index 0000000..8c07075
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+
+namespace app\core;
+
+use PDO;
+
+class Database
+{
+    public PDO $pdo;
+
+    public function __construct(array $config)
+    {
+        $dsn = $config["dsn"] ?? "";
+        $user = $config["user"] ?? "";
+        $password = $config["password"] ?? "";
+
+        $this->pdo = new PDO($dsn, $user, $password);
+        $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+    }
+
+    public function applyMigrations()
+    {
+        $this->createMigrationsTable();
+        $applied = $this->getAppliedMigrations();
+
+        $newMigrations = [];
+        $files = scandir(Application::$ROOT_DIR . "/Migrations");
+        $toApply = array_diff($files, $applied);
+
+        foreach ($toApply as $migration) {
+            if ($migration == "." || $migration == "..") {
+                continue;
+            }
+
+            require_once Application::$ROOT_DIR . "/Migrations/$migration";
+            $migrationClassName = pathinfo($migration, PATHINFO_FILENAME);
+
+            $this->log("Applying migration: $migration");
+            $migrationInstance = new $migrationClassName;
+            $migrationInstance->up();
+            $this->log("Applied migration: $migration");
+
+            $newMigrations[] = $migration;
+        }
+
+        if (!empty($newMigrations)) {
+            $this->saveMigration($newMigrations);
+        } else {
+            $this->log("All migrations are applied!");
+        }
+    }
+
+    public function createMigrationsTable()
+    {
+        $this->pdo->exec("
+CREATE TABLE IF NOT EXISTS migrations (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    migration VARCHAR(255),
+    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+) ENGINE=INNODB;
+");
+    }
+
+    public function getAppliedMigrations()
+    {
+        $statment = $this->pdo->prepare("SELECT migration FROM migrations");
+        $statment->execute();
+
+        return $statment->fetchAll(PDO::FETCH_COLUMN);
+    }
+
+    public function saveMigration(array $migrations)
+    {
+        $str = implode(",", array_map(fn($m) => "('$m')", $migrations));
+        $this->pdo->prepare("INSERT INTO migrations(migration) VALUES $str")->execute();
+    }
+
+    protected function log(string $message) {
+        echo "[".date("Y/m/d H:m:s")."] - $message".PHP_EOL;
+    }
+}
diff --git a/www/migrationScript.php b/www/migrationScript.php
new file mode 100644 (file)
index 0000000..c9a0432
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+use app\controllers\AuthController;
+use app\controllers\SiteController;
+use app\core\Application;
+
+require_once __DIR__."/vendor/autoload.php";
+$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
+$dotenv->load();
+
+$config = [
+    "db" => [
+        "dsn" => $_ENV["DB_DSN"],
+        "user" => $_ENV["DB_USER"],
+        "password" => $_ENV["DB_PASSWORD"]
+    ]
+];
+
+$app = new Application(__DIR__, $config);
+$app->db->applyMigrations();
+?>
index e2ef83fa3a23d2e98385d85d23176cf27c1afb25..57aa14d0687bdd64306313c2c9eb83777dbcc5d3 100644 (file)
@@ -1,11 +1,21 @@
 <?php
-require_once __DIR__."/../vendor/autoload.php";
-
 use app\controllers\AuthController;
 use app\controllers\SiteController;
 use app\core\Application;
 
-$app = new Application(dirname(__DIR__));
+require_once __DIR__."/../vendor/autoload.php";
+$dotenv = Dotenv\Dotenv::createImmutable(dirname(__DIR__));
+$dotenv->load();
+
+$config = [
+    "db" => [
+        "dsn" => $_ENV["DB_DSN"],
+        "user" => $_ENV["DB_USER"],
+        "password" => $_ENV["DB_PASSWORD"]
+    ]
+];
+
+$app = new Application(dirname(__DIR__), $config);
 
 $app->router->get("/", [SiteController::class, "home"]);