mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 11:09:18 +02:00
This commit introduces a complete thesis management interface and migrates the system from YAML-based storage to SQLite: Core Changes: - Add Database.php helper class with PDO connection and entity management - Add list.php for viewing all theses with filtering and sorting - Add edit.php for modifying existing thesis records - Add import.php for migrating legacy YAML data to SQLite - Add justfile with development tasks (serve, init-test-db, etc.) Documentation: - Add MIGRATION.md with complete migration guide and architecture docs - Update README.md with database setup and Just recipe instructions - Update .gitignore to exclude test databases and error logs Modified Forms: - Enhanced formulaire.php with transaction-based SQLite processing - Updated index.php with database-driven form options - Improved thanks.php to read from database views The new architecture provides: - Normalized database schema (19 tables, 2 views) - Transaction safety and referential integrity - CRUD operations for thesis management - Filtering by year, orientation, AP program, publication status - Secure file handling with metadata tracking 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
112 lines
3.0 KiB
PHP
112 lines
3.0 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Database connection class for SQLite
|
|
*/
|
|
class Database {
|
|
private static $instance = null;
|
|
private $pdo;
|
|
|
|
/**
|
|
* Private constructor to prevent multiple instances
|
|
*/
|
|
private function __construct() {
|
|
$dbPath = __DIR__ . '/../formulaire/test.db';
|
|
|
|
if (!file_exists($dbPath)) {
|
|
throw new Exception("Database file not found: " . $dbPath);
|
|
}
|
|
|
|
try {
|
|
$this->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");
|
|
}
|
|
}
|