100 lines
3.3 KiB
PHP
100 lines
3.3 KiB
PHP
<?php
|
|
// db/config.php
|
|
|
|
// --- Database Credentials ---
|
|
// We are using environment variables for configuration.
|
|
$db_host = getenv('DB_HOST') ?: '127.0.0.1';
|
|
$db_port = getenv('DB_PORT') ?: '3306';
|
|
$db_name = getenv('DB_DATABASE') ?: 'app';
|
|
$db_user = getenv('DB_USERNAME') ?: 'app';
|
|
$db_pass = getenv('DB_PASSWORD') ?: 'app';
|
|
|
|
/**
|
|
* Establishes a PDO database connection.
|
|
*
|
|
* @return PDO|null A PDO connection object on success, or null on failure.
|
|
*/
|
|
function db() {
|
|
global $db_host, $db_port, $db_name, $db_user, $db_pass;
|
|
static $pdo = null;
|
|
|
|
if ($pdo !== null) {
|
|
return $pdo;
|
|
}
|
|
|
|
$dsn = "mysql:host={$db_host};port={$db_port};dbname={$db_name};charset=utf8mb4";
|
|
$options = [
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
];
|
|
|
|
try {
|
|
$pdo = new PDO($dsn, $db_user, $db_pass, $options);
|
|
return $pdo;
|
|
} catch (PDOException $e) {
|
|
// In a real application, you would log this error and show a generic error page.
|
|
// For this development environment, we'll just show the error.
|
|
error_log('Database Connection Error: ' . $e->getMessage());
|
|
// Returning null or you could throw an exception.
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Runs database migrations.
|
|
* It finds all .php files in the migrations directory and runs them in order.
|
|
* Each migration file should contain a function with the same name as the file (without .php).
|
|
*/
|
|
function run_migrations() {
|
|
$pdo = db();
|
|
if (!$pdo) {
|
|
// Cannot run migrations without a database connection.
|
|
return;
|
|
}
|
|
|
|
$migration_dir = __DIR__ . '/migrations';
|
|
if (!is_dir($migration_dir)) {
|
|
return; // No migrations directory.
|
|
}
|
|
|
|
$files = glob($migration_dir . '/*.php');
|
|
sort($files);
|
|
|
|
// Check if migrations table exists, create if not
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS migrations (migration VARCHAR(255) PRIMARY KEY)");
|
|
|
|
// Get all executed migrations
|
|
$executed_migrations = $pdo->query("SELECT migration FROM migrations")->fetchAll(PDO::FETCH_COLUMN);
|
|
|
|
foreach ($files as $file) {
|
|
$migration_name = basename($file, '.php');
|
|
|
|
if (in_array($migration_name, $executed_migrations)) {
|
|
continue; // Skip already executed migration
|
|
}
|
|
|
|
require_once $file;
|
|
// The function name inside the migration file must match the filename.
|
|
// e.g., 001_create_agenda_table.php must contain a function named 'migration_001_create_agenda_table'
|
|
$migration_function_name = 'migration_' . str_replace(['-'], '_', $migration_name);
|
|
|
|
|
|
if (function_exists($migration_function_name)) {
|
|
try {
|
|
$pdo->beginTransaction();
|
|
$migration_function_name($pdo);
|
|
// Record the migration
|
|
$stmt = $pdo->prepare("INSERT INTO migrations (migration) VALUES (?)");
|
|
$stmt->execute([$migration_name]);
|
|
$pdo->commit();
|
|
} catch (Exception $e) {
|
|
$pdo->rollBack();
|
|
error_log("Migration failed: {$migration_name}. Error: " . $e->getMessage());
|
|
// Stop on first failed migration
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|