mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
refactor: extract edit.php POST handler to actions/edit.php
edit.php was a 530-line file mixing form display, POST handling, file
uploads, and reference-data loading. This refactor splits it along the
same action-file pattern already used by formulaire.php, tag.php, and
page.php.
Changes:
- public/admin/actions/edit.php (new): standalone POST handler; auth
guard, CSRF check, transaction, redirect with session flash messages
- public/admin/edit.php: display-only; reads edit_success/edit_error
flash keys from session; form action points to actions/edit.php via
a hidden thesis_id field instead of a query-string self-post
- src/Database.php: four new methods to remove all raw PDO from both
files:
- updateThesis(int, array): void — UPDATE theses core fields
- setThesisAuthors(int, array): void — delete-then-reinsert authors
- getThesisLanguageIds(int): array — SELECT language_id for form
- getThesisFormatIds(int): array — SELECT format_id for form
This commit is contained in:
9
TODO.md
9
TODO.md
@@ -423,10 +423,11 @@ Goal: rename the tables and column to the canonical M2M pattern (`tags`, `thesis
|
|||||||
|
|
||||||
### C — Code organisation / maintainability
|
### C — Code organisation / maintainability
|
||||||
|
|
||||||
- [ ] **`edit.php` does too much** — 530 lines combining form display, POST handling, file upload,
|
- [x] **`edit.php` does too much** — POST handler extracted to `public/admin/actions/edit.php`;
|
||||||
and all reference-data loading in one file. Extract the POST handler to
|
`edit.php` is now display-only (loads data, renders form, reads flash messages from session).
|
||||||
`public/admin/actions/edit.php` (matching the pattern already used by `formulaire.php`,
|
Added `Database::updateThesis()`, `Database::setThesisAuthors()`,
|
||||||
`tag.php`, `page.php`, etc.).
|
`Database::getThesisLanguageIds()`, `Database::getThesisFormatIds()` to remove all raw PDO
|
||||||
|
from both files. Matches the pattern of `formulaire.php`, `tag.php`, `page.php`.
|
||||||
|
|
||||||
- [x] **`formulaire.php` duplicates banner-upload logic verbatim from `edit.php`** — extracted to
|
- [x] **`formulaire.php` duplicates banner-upload logic verbatim from `edit.php`** — extracted to
|
||||||
`Database::handleBannerUpload(int $thesisId, ?array $uploadedFile): ?string`; both action
|
`Database::handleBannerUpload(int $thesisId, ?array $uploadedFile): ?string`; both action
|
||||||
|
|||||||
141
public/admin/actions/edit.php
Normal file
141
public/admin/actions/edit.php
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
// Bootstrap application
|
||||||
|
require_once __DIR__ . "/../../../config/bootstrap.php";
|
||||||
|
require_once __DIR__ . '/../../../src/AdminAuth.php';
|
||||||
|
|
||||||
|
// PHP-level auth guard (defence-in-depth behind nginx Basic Auth)
|
||||||
|
AdminAuth::requireLogin();
|
||||||
|
|
||||||
|
// Only handle POST requests
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
header('Location: ../index.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify CSRF token
|
||||||
|
if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) ||
|
||||||
|
!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
|
||||||
|
error_log("CSRF token validation failed in edit action");
|
||||||
|
die("Erreur de sécurité : token invalide. Veuillez recharger le formulaire.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$thesisId = isset($_POST['thesis_id']) ? intval($_POST['thesis_id']) : 0;
|
||||||
|
if ($thesisId <= 0) {
|
||||||
|
die("ID de TFE invalide.");
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../../src/Database.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = new Database();
|
||||||
|
|
||||||
|
$db->beginTransaction();
|
||||||
|
|
||||||
|
// Thesis metadata
|
||||||
|
$db->updateThesis($thesisId, [
|
||||||
|
'title' => trim($_POST['titre']),
|
||||||
|
'subtitle' => trim($_POST['subtitle'] ?? ''),
|
||||||
|
'year' => intval($_POST['année']),
|
||||||
|
'orientation_id' => intval($_POST['orientation']),
|
||||||
|
'ap_program_id' => intval($_POST['ap']),
|
||||||
|
'finality_id' => intval($_POST['finality']),
|
||||||
|
'synopsis' => trim($_POST['synopsis']),
|
||||||
|
'context_note' => trim($_POST['context_note'] ?? ''),
|
||||||
|
'file_size_info' => trim($_POST['duration_info'] ?? ''),
|
||||||
|
'baiu_link' => trim($_POST['lien'] ?? ''),
|
||||||
|
'license_id' => filter_var($_POST['license_id'] ?? '', FILTER_VALIDATE_INT) ?: null,
|
||||||
|
'access_type_id' => filter_var($_POST['access_type_id'] ?? '', FILTER_VALIDATE_INT) ?: null,
|
||||||
|
'is_published' => isset($_POST['is_published']),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Authors
|
||||||
|
$authorsRaw = trim($_POST['auteurice'] ?? '');
|
||||||
|
$authorEntries = [];
|
||||||
|
if (!empty($authorsRaw)) {
|
||||||
|
$names = array_map('trim', explode(',', $authorsRaw));
|
||||||
|
foreach ($names as $index => $name) {
|
||||||
|
if ($name !== '') {
|
||||||
|
$authorEntries[] = [
|
||||||
|
'name' => $name,
|
||||||
|
'email' => $index === 0 ? ($_POST['mail'] ?? null) : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$db->setThesisAuthors($thesisId, $authorEntries);
|
||||||
|
|
||||||
|
// Jury
|
||||||
|
$juryMembers = [];
|
||||||
|
if (!empty(trim($_POST['jury_president'] ?? ''))) {
|
||||||
|
$juryMembers[] = ['name' => trim($_POST['jury_president']), 'role' => 'president', 'is_external' => 0];
|
||||||
|
}
|
||||||
|
if (!empty(trim($_POST['jury_promoteur'] ?? ''))) {
|
||||||
|
$juryMembers[] = [
|
||||||
|
'name' => trim($_POST['jury_promoteur']),
|
||||||
|
'role' => 'promoteur',
|
||||||
|
'is_external' => isset($_POST['jury_promoteur_ext']) ? 1 : 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
foreach ($_POST['jury_lecteurs'] ?? [] as $i => $name) {
|
||||||
|
$name = trim($name);
|
||||||
|
if ($name !== '') {
|
||||||
|
$juryMembers[] = [
|
||||||
|
'name' => $name,
|
||||||
|
'role' => 'lecteur',
|
||||||
|
'is_external' => isset($_POST['jury_lecteurs_ext'][$i]) ? 1 : 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$db->setThesisJury($thesisId, $juryMembers);
|
||||||
|
|
||||||
|
// Languages
|
||||||
|
$db->setThesisLanguages(
|
||||||
|
$thesisId,
|
||||||
|
isset($_POST['languages']) && is_array($_POST['languages']) ? $_POST['languages'] : []
|
||||||
|
);
|
||||||
|
|
||||||
|
// Formats
|
||||||
|
$db->setThesisFormats(
|
||||||
|
$thesisId,
|
||||||
|
isset($_POST['formats']) && is_array($_POST['formats']) ? $_POST['formats'] : []
|
||||||
|
);
|
||||||
|
|
||||||
|
// Tags
|
||||||
|
$keywordsRaw = trim($_POST['tag'] ?? '');
|
||||||
|
$editKeywords = !empty($keywordsRaw) ? array_map('trim', explode(',', $keywordsRaw)) : [];
|
||||||
|
$db->setThesisTags($thesisId, $editKeywords);
|
||||||
|
|
||||||
|
$db->commit();
|
||||||
|
|
||||||
|
// Banner upload/removal (after commit, outside transaction)
|
||||||
|
if (isset($_POST['remove_banner'])) {
|
||||||
|
$currentBannerPath = $db->getThesisBannerPath($thesisId);
|
||||||
|
if ($currentBannerPath && defined('STORAGE_ROOT')) {
|
||||||
|
$absPath = STORAGE_ROOT . '/' . $currentBannerPath;
|
||||||
|
if (file_exists($absPath)) {
|
||||||
|
unlink($absPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$db->setBannerPath($thesisId, null);
|
||||||
|
} else {
|
||||||
|
$db->handleBannerUpload($thesisId, $_FILES['banner'] ?? null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regenerate CSRF token
|
||||||
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||||
|
|
||||||
|
// Flash success and redirect back to edit form
|
||||||
|
$_SESSION['edit_success'] = "TFE mis à jour avec succès!";
|
||||||
|
header('Location: ../edit.php?id=' . $thesisId);
|
||||||
|
exit();
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if (isset($db)) {
|
||||||
|
$db->rollback();
|
||||||
|
}
|
||||||
|
error_log("Edit action error: " . $e->getMessage());
|
||||||
|
|
||||||
|
$_SESSION['edit_error'] = $e->getMessage();
|
||||||
|
header('Location: ../edit.php?id=' . $thesisId);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
@@ -14,167 +14,41 @@ if (empty($_SESSION['csrf_token'])) {
|
|||||||
require_once __DIR__ . '/../../src/Database.php';
|
require_once __DIR__ . '/../../src/Database.php';
|
||||||
|
|
||||||
$thesisId = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
$thesisId = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||||
$error = null;
|
|
||||||
$success = null;
|
|
||||||
|
|
||||||
if ($thesisId <= 0) {
|
if ($thesisId <= 0) {
|
||||||
die("ID invalide");
|
die("ID invalide");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Consume flash messages from the edit action
|
||||||
|
$error = $_SESSION['edit_error'] ?? null;
|
||||||
|
$success = $_SESSION['edit_success'] ?? null;
|
||||||
|
unset($_SESSION['edit_error'], $_SESSION['edit_success']);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$db = new Database();
|
$db = new Database();
|
||||||
$pdo = $db->getPDO();
|
|
||||||
|
|
||||||
// Handle form submission
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['csrf_token'])) {
|
|
||||||
// Verify CSRF token
|
|
||||||
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
|
|
||||||
throw new Exception("Erreur de sécurité : token invalide.");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$db->beginTransaction();
|
|
||||||
|
|
||||||
// Update thesis basic info
|
|
||||||
$editLicenseId = filter_var($_POST['license_id'] ?? '', FILTER_VALIDATE_INT) ?: null;
|
|
||||||
$editAccessTypeId = filter_var($_POST['access_type_id'] ?? '', FILTER_VALIDATE_INT) ?: null;
|
|
||||||
$editContextNote = trim($_POST['context_note'] ?? '');
|
|
||||||
|
|
||||||
$stmt = $pdo->prepare("
|
|
||||||
UPDATE theses SET
|
|
||||||
title = ?,
|
|
||||||
subtitle = ?,
|
|
||||||
year = ?,
|
|
||||||
orientation_id = ?,
|
|
||||||
ap_program_id = ?,
|
|
||||||
finality_id = ?,
|
|
||||||
synopsis = ?,
|
|
||||||
context_note = ?,
|
|
||||||
file_size_info = ?,
|
|
||||||
baiu_link = ?,
|
|
||||||
license_id = ?,
|
|
||||||
access_type_id = ?,
|
|
||||||
is_published = ?,
|
|
||||||
updated_at = CURRENT_TIMESTAMP
|
|
||||||
WHERE id = ?
|
|
||||||
");
|
|
||||||
|
|
||||||
$stmt->execute([
|
|
||||||
trim($_POST['titre']),
|
|
||||||
!empty($_POST['subtitle']) ? trim($_POST['subtitle']) : null,
|
|
||||||
intval($_POST['année']),
|
|
||||||
intval($_POST['orientation']),
|
|
||||||
intval($_POST['ap']),
|
|
||||||
intval($_POST['finality']),
|
|
||||||
trim($_POST['synopsis']),
|
|
||||||
!empty($editContextNote) ? $editContextNote : null,
|
|
||||||
!empty($_POST['duration_info']) ? trim($_POST['duration_info']) : null,
|
|
||||||
!empty($_POST['lien']) ? trim($_POST['lien']) : null,
|
|
||||||
$editLicenseId,
|
|
||||||
$editAccessTypeId,
|
|
||||||
isset($_POST['is_published']) ? 1 : 0,
|
|
||||||
$thesisId
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Update authors
|
|
||||||
$pdo->prepare("DELETE FROM thesis_authors WHERE thesis_id = ?")->execute([$thesisId]);
|
|
||||||
$authorsRaw = trim($_POST['auteurice'] ?? '');
|
|
||||||
if (!empty($authorsRaw)) {
|
|
||||||
$authors = array_map('trim', explode(',', $authorsRaw));
|
|
||||||
foreach ($authors as $index => $authorName) {
|
|
||||||
if (!empty($authorName)) {
|
|
||||||
$authorId = $db->findOrCreateAuthor($authorName, $index === 0 ? ($_POST['mail'] ?? null) : null);
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO thesis_authors (thesis_id, author_id, author_order) VALUES (?, ?, ?)");
|
|
||||||
$stmt->execute([$thesisId, $authorId, $index + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update jury
|
|
||||||
$editJuryMembers = [];
|
|
||||||
if (!empty(trim($_POST['jury_president'] ?? ''))) {
|
|
||||||
$editJuryMembers[] = ['name' => trim($_POST['jury_president']), 'role' => 'president', 'is_external' => 0];
|
|
||||||
}
|
|
||||||
if (!empty(trim($_POST['jury_promoteur'] ?? ''))) {
|
|
||||||
$editJuryMembers[] = ['name' => trim($_POST['jury_promoteur']), 'role' => 'promoteur',
|
|
||||||
'is_external' => isset($_POST['jury_promoteur_ext']) ? 1 : 0];
|
|
||||||
}
|
|
||||||
foreach ($_POST['jury_lecteurs'] ?? [] as $i => $name) {
|
|
||||||
$name = trim($name);
|
|
||||||
if ($name !== '') {
|
|
||||||
$editJuryMembers[] = ['name' => $name, 'role' => 'lecteur',
|
|
||||||
'is_external' => isset($_POST['jury_lecteurs_ext'][$i]) ? 1 : 0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$db->setThesisJury($thesisId, $editJuryMembers);
|
|
||||||
|
|
||||||
// Update languages
|
|
||||||
$db->setThesisLanguages($thesisId, isset($_POST['languages']) && is_array($_POST['languages']) ? $_POST['languages'] : []);
|
|
||||||
|
|
||||||
// Update formats
|
|
||||||
$db->setThesisFormats($thesisId, isset($_POST['formats']) && is_array($_POST['formats']) ? $_POST['formats'] : []);
|
|
||||||
|
|
||||||
// Update tags
|
|
||||||
$keywordsRaw = trim($_POST['tag'] ?? '');
|
|
||||||
$editKeywords = !empty($keywordsRaw) ? array_map('trim', explode(',', $keywordsRaw)) : [];
|
|
||||||
$db->setThesisTags($thesisId, $editKeywords);
|
|
||||||
|
|
||||||
$db->commit();
|
|
||||||
|
|
||||||
// Handle banner upload/removal (after commit, outside transaction)
|
|
||||||
if (isset($_POST['remove_banner'])) {
|
|
||||||
$currentBannerPath = $db->getThesisBannerPath($thesisId);
|
|
||||||
if ($currentBannerPath && defined('STORAGE_ROOT')) {
|
|
||||||
$absPath = STORAGE_ROOT . '/' . $currentBannerPath;
|
|
||||||
if (file_exists($absPath)) unlink($absPath);
|
|
||||||
}
|
|
||||||
$db->setBannerPath($thesisId, null);
|
|
||||||
} else {
|
|
||||||
$db->handleBannerUpload($thesisId, $_FILES['banner'] ?? null);
|
|
||||||
}
|
|
||||||
|
|
||||||
$success = "TFE mis à jour avec succès!";
|
|
||||||
|
|
||||||
// Regenerate CSRF token
|
|
||||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$db->rollback();
|
|
||||||
$error = $e->getMessage();
|
|
||||||
error_log("Edit error: " . $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load thesis data
|
// Load thesis data
|
||||||
$thesis = $db->getThesis($thesisId);
|
$thesis = $db->getThesis($thesisId);
|
||||||
|
|
||||||
if (!$thesis) {
|
if (!$thesis) {
|
||||||
die("TFE non trouvé");
|
die("TFE non trouvé");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load current relationships
|
// Load current relationships via dedicated DB methods (no raw PDO)
|
||||||
$stmt = $pdo->prepare("SELECT language_id FROM thesis_languages WHERE thesis_id = ?");
|
$currentLanguages = $db->getThesisLanguageIds($thesisId);
|
||||||
$stmt->execute([$thesisId]);
|
$currentFormats = $db->getThesisFormatIds($thesisId);
|
||||||
$currentLanguages = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
$jury = $db->getThesisJury($thesisId);
|
||||||
|
|
||||||
$stmt = $pdo->prepare("SELECT format_id FROM thesis_formats WHERE thesis_id = ?");
|
// Reference / lookup data
|
||||||
$stmt->execute([$thesisId]);
|
$orientations = $db->getAllOrientations();
|
||||||
$currentFormats = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
$apPrograms = $db->getAllAPPrograms();
|
||||||
|
|
||||||
// Load jury
|
|
||||||
$jury = $db->getThesisJury($thesisId);
|
|
||||||
|
|
||||||
// Load reference data
|
|
||||||
$orientations = $db->getAllOrientations();
|
|
||||||
$apPrograms = $db->getAllAPPrograms();
|
|
||||||
$finalityTypes = $db->getAllFinalityTypes();
|
$finalityTypes = $db->getAllFinalityTypes();
|
||||||
$languages = $db->getAllLanguages();
|
$languages = $db->getAllLanguages();
|
||||||
$formatTypes = $db->getAllFormatTypes();
|
$formatTypes = $db->getAllFormatTypes();
|
||||||
$licenseTypes = $db->getAllLicenseTypes();
|
$licenseTypes = $db->getAllLicenseTypes();
|
||||||
$accessTypes = $db->getAccessTypes();
|
$accessTypes = $db->getAccessTypes();
|
||||||
|
|
||||||
// Fetch raw FK IDs (view only exposes name strings)
|
// Fetch raw FK IDs (view only exposes name strings)
|
||||||
$rawRow = $db->getThesisRawFields($thesisId);
|
$rawRow = $db->getThesisRawFields($thesisId);
|
||||||
$currentLicenseId = $rawRow['license_id'] ?? null;
|
$currentLicenseId = $rawRow['license_id'] ?? null;
|
||||||
$currentAccessTypeId = $rawRow['access_type_id'] ?? null;
|
$currentAccessTypeId = $rawRow['access_type_id'] ?? null;
|
||||||
$currentContextNote = $rawRow['context_note'] ?? '';
|
$currentContextNote = $rawRow['context_note'] ?? '';
|
||||||
@@ -199,8 +73,9 @@ try {
|
|||||||
<div class="admin-alert admin-alert--success">✓ <?= htmlspecialchars($success) ?></div>
|
<div class="admin-alert admin-alert--success">✓ <?= htmlspecialchars($success) ?></div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<form method="post" action="edit.php?id=<?= $thesisId ?>" class="admin-form" enctype="multipart/form-data">
|
<form method="post" action="/admin/actions/edit.php" class="admin-form" enctype="multipart/form-data">
|
||||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
||||||
|
<input type="hidden" name="thesis_id" value="<?= $thesisId ?>">
|
||||||
|
|
||||||
<div class="admin-form-row">
|
<div class="admin-form-row">
|
||||||
<label class="admin-label" for="auteurice">Auteur·ice(s) :</label>
|
<label class="admin-label" for="auteurice">Auteur·ice(s) :</label>
|
||||||
@@ -257,11 +132,10 @@ try {
|
|||||||
|
|
||||||
<!-- Composition du jury -->
|
<!-- Composition du jury -->
|
||||||
<?php
|
<?php
|
||||||
// Pre-split jury by role for easy pre-population
|
$juryPresident = null;
|
||||||
$juryPresident = null;
|
$juryPromoteur = null;
|
||||||
$juryPromoteur = null;
|
|
||||||
$juryPromoteurExt = 0;
|
$juryPromoteurExt = 0;
|
||||||
$juryLecteurs = [];
|
$juryLecteurs = [];
|
||||||
foreach ($jury as $jm) {
|
foreach ($jury as $jm) {
|
||||||
if ($jm['role'] === 'president') {
|
if ($jm['role'] === 'president') {
|
||||||
$juryPresident = $jm['name'];
|
$juryPresident = $jm['name'];
|
||||||
|
|||||||
@@ -909,6 +909,30 @@ class Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of language IDs currently linked to a thesis.
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
public function getThesisLanguageIds(int $thesisId): array {
|
||||||
|
$stmt = $this->pdo->prepare(
|
||||||
|
"SELECT language_id FROM thesis_languages WHERE thesis_id = ?"
|
||||||
|
);
|
||||||
|
$stmt->execute([$thesisId]);
|
||||||
|
return $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of format IDs currently linked to a thesis.
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
public function getThesisFormatIds(int $thesisId): array {
|
||||||
|
$stmt = $this->pdo->prepare(
|
||||||
|
"SELECT format_id FROM thesis_formats WHERE thesis_id = ?"
|
||||||
|
);
|
||||||
|
$stmt->execute([$thesisId]);
|
||||||
|
return $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace all tag associations for a thesis.
|
* Replace all tag associations for a thesis.
|
||||||
* Tags are identified by name (findOrCreateTag is called for each).
|
* Tags are identified by name (findOrCreateTag is called for each).
|
||||||
@@ -1128,6 +1152,65 @@ class Database {
|
|||||||
*
|
*
|
||||||
* @return int The new thesis ID.
|
* @return int The new thesis ID.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Update core thesis fields.
|
||||||
|
* All columns except identifier, submitted_at, and file-related fields.
|
||||||
|
*/
|
||||||
|
public function updateThesis(int $thesisId, array $data): void {
|
||||||
|
$stmt = $this->pdo->prepare("
|
||||||
|
UPDATE theses SET
|
||||||
|
title = ?,
|
||||||
|
subtitle = ?,
|
||||||
|
year = ?,
|
||||||
|
orientation_id = ?,
|
||||||
|
ap_program_id = ?,
|
||||||
|
finality_id = ?,
|
||||||
|
synopsis = ?,
|
||||||
|
context_note = ?,
|
||||||
|
file_size_info = ?,
|
||||||
|
baiu_link = ?,
|
||||||
|
license_id = ?,
|
||||||
|
access_type_id = ?,
|
||||||
|
is_published = ?,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
|
WHERE id = ?
|
||||||
|
");
|
||||||
|
$stmt->execute([
|
||||||
|
$data['title'],
|
||||||
|
!empty($data['subtitle']) ? $data['subtitle'] : null,
|
||||||
|
(int)$data['year'],
|
||||||
|
(int)$data['orientation_id'],
|
||||||
|
(int)$data['ap_program_id'],
|
||||||
|
(int)$data['finality_id'],
|
||||||
|
$data['synopsis'],
|
||||||
|
!empty($data['context_note']) ? $data['context_note'] : null,
|
||||||
|
!empty($data['file_size_info']) ? $data['file_size_info'] : null,
|
||||||
|
!empty($data['baiu_link']) ? $data['baiu_link'] : null,
|
||||||
|
isset($data['license_id']) ? $data['license_id'] : null,
|
||||||
|
isset($data['access_type_id']) ? $data['access_type_id'] : null,
|
||||||
|
$data['is_published'] ? 1 : 0,
|
||||||
|
$thesisId,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace all author associations for a thesis (delete-then-reinsert).
|
||||||
|
* $authors is an array of ['name' => string, 'email' => string|null].
|
||||||
|
* The first entry is considered the primary author (author_order = 1).
|
||||||
|
*/
|
||||||
|
public function setThesisAuthors(int $thesisId, array $authors): void {
|
||||||
|
$this->pdo->prepare("DELETE FROM thesis_authors WHERE thesis_id = ?")->execute([$thesisId]);
|
||||||
|
$stmt = $this->pdo->prepare(
|
||||||
|
"INSERT INTO thesis_authors (thesis_id, author_id, author_order) VALUES (?, ?, ?)"
|
||||||
|
);
|
||||||
|
foreach ($authors as $index => $author) {
|
||||||
|
$name = trim($author['name'] ?? '');
|
||||||
|
if ($name === '') continue;
|
||||||
|
$authorId = $this->findOrCreateAuthor($name, $author['email'] ?? null);
|
||||||
|
$stmt->execute([$thesisId, $authorId, $index + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function createThesis(array $data): int {
|
public function createThesis(array $data): int {
|
||||||
$identifier = $this->generateThesisIdentifier((int)$data['year']);
|
$identifier = $this->generateThesisIdentifier((int)$data['year']);
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[1774712930]
|
[1774717688]
|
||||||
BIN
storage/test.db
BIN
storage/test.db
Binary file not shown.
Reference in New Issue
Block a user