PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4" ]; try { $this->pdo = new PDO($dsn, DB_USER, DB_PASS, $options); } catch (PDOException $e) { die(json_encode(['error' => 'Database connection failed: ' . $e->getMessage()])); } } public static function getInstance(): Database { if (self::$instance === null) { self::$instance = new Database(); } return self::$instance; } public function getConnection(): PDO { return $this->pdo; } // Shorthand query public function query(string $sql, array $params = []): PDOStatement { $stmt = $this->pdo->prepare($sql); $stmt->execute($params); return $stmt; } public function fetchAll(string $sql, array $params = []): array { return $this->query($sql, $params)->fetchAll(); } public function fetchOne(string $sql, array $params = []): ?array { $row = $this->query($sql, $params)->fetch(); return $row ?: null; } public function insert(string $table, array $data): int { $cols = implode(', ', array_keys($data)); $placeholders = implode(', ', array_fill(0, count($data), '?')); $sql = "INSERT INTO `$table` ($cols) VALUES ($placeholders)"; $this->query($sql, array_values($data)); return (int)$this->pdo->lastInsertId(); } public function update(string $table, array $data, string $where, array $whereParams = []): int { $sets = implode(', ', array_map(fn($k) => "`$k` = ?", array_keys($data))); $sql = "UPDATE `$table` SET $sets WHERE $where"; $stmt = $this->query($sql, array_merge(array_values($data), $whereParams)); return $stmt->rowCount(); } public function delete(string $table, string $where, array $params = []): int { $stmt = $this->query("DELETE FROM `$table` WHERE $where", $params); return $stmt->rowCount(); } public function lastInsertId(): string { return $this->pdo->lastInsertId(); } // Prevent cloning private function __clone() {} }