refactor: encapsulate thesis creation SQL in Database::createThesis()

Move the raw identifier-generation query and the INSERT INTO theses /
INSERT INTO thesis_authors statements out of formulaire.php into two new
Database methods:

  generateThesisIdentifier(int $year): string
    – counts existing theses for the year inside the open transaction so
      concurrent workers cannot produce duplicate YYYY-NNN identifiers.

  createThesis(array $data): int
    – generates the identifier, INSERTs the thesis row, links the author
      via thesis_authors (author_order=1), returns the new thesis ID.

  getThesisIdentifier(int $id): string
    – fetches the stored identifier for a thesis ID; used by formulaire.php
      to reconstruct the upload path (storage/theses/YYYY/YYYY-NNN/).

formulaire.php now calls $db->createThesis([…]) + $db->getThesisIdentifier()
and no longer holds any raw PDO queries for the core thesis insert.
The $pdo local variable (previously $db->getPDO()) is removed entirely.

All four test suites (Unit, RateLimit, Integration, Security) pass.
This commit is contained in:
Pontoporeia
2026-03-28 13:52:43 +01:00
parent 2ec5a7f38f
commit 61ac3c002d
5 changed files with 95 additions and 41 deletions

View File

@@ -399,7 +399,7 @@ Goal: rename the tables and column to the canonical M2M pattern (`tags`, `thesis
- [x] `edit.php` (line 155): unparameterised `"… WHERE id = $thesisId"` SQL injection → fixed; raw `SELECT banner_path``getThesisBannerPath(int $id): ?string`
- [x] `edit.php`: raw `SELECT license_id, access_type_id, context_note``getThesisRawFields(int $id): ?array`
- [x] `system.php`: raw `SELECT COUNT(*) FROM theses``getThesisCount(): int`
- [ ] `formulaire.php`: raw identifier-generation query + all junction-table INSERTs → encapsulate in `Database::createThesis(array $data): int`
- [x] `formulaire.php`: raw identifier-generation query + all junction-table INSERTs → encapsulate in `Database::createThesis(array $data): int`
- [x] **`sanitize_string()` in `formulaire.php` applies `htmlspecialchars` at write time** —
HTML-escaping belongs at render time (in the template), not at storage time. Storing