pdo = new PDO('sqlite:' . $dbPath); $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); } catch (PDOException $e) { error_log("Database connection failed: " . $e->getMessage()); throw $e; } } /** * Get singleton instance */ public static function getInstance() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * Get PDO connection */ public function getConnection() { return $this->pdo; } /** * Get all published theses with pagination */ public function getPublishedTheses($limit = 10, $offset = 0) { $sql = "SELECT * FROM v_theses_public ORDER BY year DESC, title ASC LIMIT :limit OFFSET :offset"; $stmt = $this->pdo->prepare($sql); $stmt->bindValue(':limit', $limit, PDO::PARAM_INT); $stmt->bindValue(':offset', $offset, PDO::PARAM_INT); $stmt->execute(); return $stmt->fetchAll(); } /** * Count all published theses */ public function countPublishedTheses() { $sql = "SELECT COUNT(*) as count FROM theses WHERE is_published = 1"; $stmt = $this->pdo->query($sql); $result = $stmt->fetch(); return $result['count']; } /** * Get thesis by ID with all related data */ public function getThesisById($id) { $sql = "SELECT * FROM v_theses_full WHERE id = :id AND is_published = 1"; $stmt = $this->pdo->prepare($sql); $stmt->bindValue(':id', $id, PDO::PARAM_INT); $stmt->execute(); $thesis = $stmt->fetch(); if (!$thesis) { return null; } // Get associated files $thesis['files'] = $this->getThesisFiles($id); return $thesis; } /** * Get files associated with a thesis */ public function getThesisFiles($thesisId) { $sql = "SELECT * FROM thesis_files WHERE thesis_id = :thesis_id ORDER BY file_type, uploaded_at"; $stmt = $this->pdo->prepare($sql); $stmt->bindValue(':thesis_id', $thesisId, PDO::PARAM_INT); $stmt->execute(); return $stmt->fetchAll(); } /** * Prevent cloning */ private function __clone() {} /** * Prevent unserialization */ public function __wakeup() { throw new Exception("Cannot unserialize singleton"); } }