refactor: use encapsulated Database methods in formulaire.php and edit.php

This commit is contained in:
Pontoporeia
2026-03-28 13:47:26 +01:00
parent 71167b2cdf
commit e126e1a3b0
5 changed files with 135 additions and 90 deletions

View File

@@ -183,27 +183,13 @@ try {
$db->setThesisJury($thesisId, $juryMembers); $db->setThesisJury($thesisId, $juryMembers);
// ===== LINK LANGUAGES TO THESIS ===== // ===== LINK LANGUAGES TO THESIS =====
foreach ($languageIds as $languageId) { $db->setThesisLanguages($thesisId, $languageIds);
$stmt = $pdo->prepare("INSERT INTO thesis_languages (thesis_id, language_id) VALUES (?, ?)");
$stmt->execute([$thesisId, $languageId]);
}
// ===== LINK FORMATS TO THESIS ===== // ===== LINK FORMATS TO THESIS =====
foreach ($formatIds as $formatId) { $db->setThesisFormats($thesisId, $formatIds);
$stmt = $pdo->prepare("INSERT INTO thesis_formats (thesis_id, format_id) VALUES (?, ?)");
$stmt->execute([$thesisId, $formatId]);
}
// ===== LINK TAGS TO THESIS ===== // ===== LINK TAGS TO THESIS =====
foreach ($keywords as $keyword) { $db->setThesisTags($thesisId, $keywords);
if (!empty($keyword)) {
$tagId = $db->findOrCreateTag($keyword);
if ($tagId) {
$stmt = $pdo->prepare("INSERT OR IGNORE INTO thesis_tags (tag_id, thesis_id) VALUES (?, ?)");
$stmt->execute([$tagId, $thesisId]);
}
}
}
// ===== HANDLE FILE UPLOADS ===== // ===== HANDLE FILE UPLOADS =====
@@ -266,28 +252,7 @@ try {
} }
// Process banner image // Process banner image
if ($bannerFile && isset($bannerFile["error"]) && $bannerFile["error"] === UPLOAD_ERR_OK) { $db->handleBannerUpload($thesisId, $bannerFile ?: null);
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($bannerFile["tmp_name"]);
$fileExtension = strtolower(pathinfo($bannerFile["name"], PATHINFO_EXTENSION));
$allowedBannerMimes = ['image/jpeg', 'image/png', 'image/webp'];
$allowedBannerExts = ['jpg', 'jpeg', 'png', 'webp'];
$maxBannerSize = 5 * 1024 * 1024; // 5 MB
if (in_array($mimeType, $allowedBannerMimes) && in_array($fileExtension, $allowedBannerExts)
&& $bannerFile["size"] <= $maxBannerSize) {
$randomName = bin2hex(random_bytes(16));
$safeFileName = $randomName . "." . $fileExtension;
$targetFile = $bannerDir . $safeFileName;
if (move_uploaded_file($bannerFile["tmp_name"], $targetFile)) {
chmod($targetFile, 0644);
$db->setBannerPath($thesisId, "banners/" . $safeFileName);
error_log("Banner image uploaded: " . $safeFileName);
}
} else {
error_log("Invalid or oversized banner image: " . $bannerFile["name"]);
}
}
// Process thesis files // Process thesis files
if ($files && is_array($files["name"])) { if ($files && is_array($files["name"])) {

View File

@@ -109,71 +109,28 @@ try {
$db->setThesisJury($thesisId, $editJuryMembers); $db->setThesisJury($thesisId, $editJuryMembers);
// Update languages // Update languages
$pdo->prepare("DELETE FROM thesis_languages WHERE thesis_id = ?")->execute([$thesisId]); $db->setThesisLanguages($thesisId, isset($_POST['languages']) && is_array($_POST['languages']) ? $_POST['languages'] : []);
if (isset($_POST['languages']) && is_array($_POST['languages'])) {
foreach ($_POST['languages'] as $languageId) {
$stmt = $pdo->prepare("INSERT INTO thesis_languages (thesis_id, language_id) VALUES (?, ?)");
$stmt->execute([$thesisId, intval($languageId)]);
}
}
// Update formats // Update formats
$pdo->prepare("DELETE FROM thesis_formats WHERE thesis_id = ?")->execute([$thesisId]); $db->setThesisFormats($thesisId, isset($_POST['formats']) && is_array($_POST['formats']) ? $_POST['formats'] : []);
if (isset($_POST['formats']) && is_array($_POST['formats'])) {
foreach ($_POST['formats'] as $formatId) {
$stmt = $pdo->prepare("INSERT INTO thesis_formats (thesis_id, format_id) VALUES (?, ?)");
$stmt->execute([$thesisId, intval($formatId)]);
}
}
// Update tags // Update tags
$pdo->prepare("DELETE FROM thesis_tags WHERE thesis_id = ?")->execute([$thesisId]);
$keywordsRaw = trim($_POST['tag'] ?? ''); $keywordsRaw = trim($_POST['tag'] ?? '');
if (!empty($keywordsRaw)) { $editKeywords = !empty($keywordsRaw) ? array_map('trim', explode(',', $keywordsRaw)) : [];
$keywords = array_map('trim', explode(',', $keywordsRaw)); $db->setThesisTags($thesisId, $editKeywords);
$keywords = array_slice($keywords, 0, 10); // Max 10
foreach ($keywords as $keyword) {
if (!empty($keyword)) {
$tagId = $db->findOrCreateTag($keyword);
if ($tagId) {
$stmt = $pdo->prepare("INSERT OR IGNORE INTO thesis_tags (tag_id, thesis_id) VALUES (?, ?)");
$stmt->execute([$tagId, $thesisId]);
}
}
}
}
$db->commit(); $db->commit();
// Handle banner upload/removal (after commit, outside transaction) // Handle banner upload/removal (after commit, outside transaction)
$bannerDir = defined('STORAGE_ROOT') ? STORAGE_ROOT . "/banners/" : null;
if ($bannerDir && !file_exists($bannerDir)) {
mkdir($bannerDir, 0755, true);
}
if (isset($_POST['remove_banner'])) { if (isset($_POST['remove_banner'])) {
// Unlink existing banner file if present
$currentBannerPath = $db->getThesisBannerPath($thesisId); $currentBannerPath = $db->getThesisBannerPath($thesisId);
if ($currentBannerPath && $bannerDir) { if ($currentBannerPath && defined('STORAGE_ROOT')) {
$absPath = STORAGE_ROOT . '/' . $currentBannerPath; $absPath = STORAGE_ROOT . '/' . $currentBannerPath;
if (file_exists($absPath)) unlink($absPath); if (file_exists($absPath)) unlink($absPath);
} }
$db->setBannerPath($thesisId, null); $db->setBannerPath($thesisId, null);
} elseif (isset($_FILES['banner']) && $_FILES['banner']['error'] === UPLOAD_ERR_OK && $bannerDir) { } else {
$bannerFile = $_FILES['banner']; $db->handleBannerUpload($thesisId, $_FILES['banner'] ?? null);
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($bannerFile["tmp_name"]);
$fileExtension = strtolower(pathinfo($bannerFile["name"], PATHINFO_EXTENSION));
$allowedBannerMimes = ['image/jpeg', 'image/png', 'image/webp'];
$allowedBannerExts = ['jpg', 'jpeg', 'png', 'webp'];
if (in_array($mimeType, $allowedBannerMimes) && in_array($fileExtension, $allowedBannerExts)
&& $bannerFile["size"] <= 5 * 1024 * 1024) {
$randomName = bin2hex(random_bytes(16));
$safeFileName = $randomName . '.' . $fileExtension;
if (move_uploaded_file($bannerFile["tmp_name"], $bannerDir . $safeFileName)) {
chmod($bannerDir . $safeFileName, 0644);
$db->setBannerPath($thesisId, "banners/" . $safeFileName);
}
}
} }
$success = "TFE mis à jour avec succès!"; $success = "TFE mis à jour avec succès!";

View File

@@ -869,6 +869,71 @@ class Database {
} }
} }
// ========================================================================
// JUNCTION-TABLE HELPERS (delete-then-reinsert pattern)
// ========================================================================
/**
* Replace all language associations for a thesis.
* @param int $thesisId
* @param int[] $languageIds IDs from the languages table
*/
public function setThesisLanguages(int $thesisId, array $languageIds): void {
$this->pdo->prepare("DELETE FROM thesis_languages WHERE thesis_id = ?")->execute([$thesisId]);
$stmt = $this->pdo->prepare(
"INSERT INTO thesis_languages (thesis_id, language_id) VALUES (?, ?)"
);
foreach ($languageIds as $langId) {
$id = (int)$langId;
if ($id > 0) {
$stmt->execute([$thesisId, $id]);
}
}
}
/**
* Replace all format associations for a thesis.
* @param int $thesisId
* @param int[] $formatIds IDs from the format_types table
*/
public function setThesisFormats(int $thesisId, array $formatIds): void {
$this->pdo->prepare("DELETE FROM thesis_formats WHERE thesis_id = ?")->execute([$thesisId]);
$stmt = $this->pdo->prepare(
"INSERT INTO thesis_formats (thesis_id, format_id) VALUES (?, ?)"
);
foreach ($formatIds as $fmtId) {
$id = (int)$fmtId;
if ($id > 0) {
$stmt->execute([$thesisId, $id]);
}
}
}
/**
* Replace all tag associations for a thesis.
* Tags are identified by name (findOrCreateTag is called for each).
* Empty / whitespace-only names are silently skipped.
* Maximum 10 tags are accepted; extras are ignored.
*
* @param int $thesisId
* @param string[] $tagNames
*/
public function setThesisTags(int $thesisId, array $tagNames): void {
$this->pdo->prepare("DELETE FROM thesis_tags WHERE thesis_id = ?")->execute([$thesisId]);
$stmt = $this->pdo->prepare(
"INSERT OR IGNORE INTO thesis_tags (tag_id, thesis_id) VALUES (?, ?)"
);
$count = 0;
foreach ($tagNames as $name) {
if ($count >= 10) break;
$tagId = $this->findOrCreateTag($name); // trims, returns null for empty
if ($tagId !== null) {
$stmt->execute([$tagId, $thesisId]);
$count++;
}
}
}
// ======================================================================== // ========================================================================
// BANNER METHODS // BANNER METHODS
// ======================================================================== // ========================================================================
@@ -883,6 +948,64 @@ class Database {
$stmt->execute([$path, $thesisId]); $stmt->execute([$path, $thesisId]);
} }
/**
* Process a banner image upload for a thesis.
*
* Validates MIME type, extension, and file size, then saves the file to the
* banners/ directory under STORAGE_ROOT and calls setBannerPath().
*
* Returns the relative path (e.g. "banners/abc123.jpg") on success,
* or null if the file array is absent, has an error, fails validation,
* or cannot be moved.
*
* @param int $thesisId Target thesis ID
* @param array|null $uploadedFile Entry from $_FILES (e.g. $_FILES['banner'])
* @return string|null Relative path stored in the DB, or null
*/
public function handleBannerUpload(int $thesisId, ?array $uploadedFile): ?string {
if (!$uploadedFile || ($uploadedFile['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
return null;
}
$allowedMimes = ['image/jpeg', 'image/png', 'image/webp'];
$allowedExts = ['jpg', 'jpeg', 'png', 'webp'];
$maxBytes = 5 * 1024 * 1024; // 5 MB
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($uploadedFile['tmp_name']);
$ext = strtolower(pathinfo($uploadedFile['name'], PATHINFO_EXTENSION));
if (!in_array($mimeType, $allowedMimes, true) ||
!in_array($ext, $allowedExts, true) ||
$uploadedFile['size'] > $maxBytes) {
error_log("handleBannerUpload: rejected " . $uploadedFile['name'] . " ($mimeType, {$uploadedFile['size']} bytes)");
return null;
}
$bannerDir = defined('STORAGE_ROOT') ? STORAGE_ROOT . '/banners/' : null;
if (!$bannerDir) {
error_log("handleBannerUpload: STORAGE_ROOT not defined");
return null;
}
if (!file_exists($bannerDir)) {
mkdir($bannerDir, 0755, true);
}
$safeName = bin2hex(random_bytes(16)) . '.' . $ext;
$targetPath = $bannerDir . $safeName;
if (!move_uploaded_file($uploadedFile['tmp_name'], $targetPath)) {
error_log("handleBannerUpload: move_uploaded_file failed for " . $uploadedFile['name']);
return null;
}
chmod($targetPath, 0644);
$relativePath = 'banners/' . $safeName;
$this->setBannerPath($thesisId, $relativePath);
error_log("handleBannerUpload: saved $relativePath");
return $relativePath;
}
// ======================================================================== // ========================================================================
// ENCAPSULATED QUERY HELPERS // ENCAPSULATED QUERY HELPERS
// ======================================================================== // ========================================================================

View File

@@ -1 +1 @@
[1774701765] [1774702033]

Binary file not shown.