Files
xamxam/todo/02-php-components.md
Pontoporeia 2841e05716 Extract ThesisCreateController; add Database publish methods
Consolidate action handlers into controller methods (todo/02-php-components.md).

src/ThesisCreateController.php (new, 435 lines)
  Mirrors ThesisEditController for the add-thesis flow.

  make()           — factory; instantiates Database via new Database()
  loadFormData()   — returns all lookup tables needed by admin/add.php
                     (orientations, apPrograms, finalityTypes, languages,
                      formatTypes, licenseTypes)
  submit(post, files) — full new-thesis creation pipeline:
    1. validateAndSanitise() — trims/strips HTML, validates required fields,
       year range, orientation/ap/finality IDs, language selection, max-10
       keywords, URL format; throws named Exception on failure
    2. findOrCreateAuthor() — reuses existing DB method
    3. Transaction: createThesis + setThesisJury + setThesisLanguages +
       setThesisFormats + setThesisTags; rolls back on any failure
    4. File uploads outside transaction: cover image (JPG/PNG only, stored in
       storage/covers/), banner via handleBannerUpload(), thesis files
       (PDF/JPG/PNG/MP4/ZIP/VTT, stored in storage/theses/YEAR/IDENT/,
       file_type auto-detected: caption/annex/main/other)
  autofocusFieldForError() — static; maps exception messages to field names
    for WCAG 3.3.1 autofocus on re-render (same contract as
    ThesisEditController::autofocusFieldForError)

admin/actions/formulaire.php  346 → 45 lines
  Now: bootstrap + CSRF guard + ThesisCreateController::make()->submit() +
  flash/redirect on error. All validation, DB logic, and file handling removed.

admin/add.php
  Lookup-table block (new Database() + 6 individual DB calls) replaced with
  ThesisCreateController::make()->loadFormData() + extract().

src/Database.php — two new methods added
  setPublished(int , bool ): void
    UPDATE theses SET is_published = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?
  bulkSetPublished(int[] , bool ): void
    Same but with an IN (...) clause for multiple IDs

admin/actions/publish.php  100 → 65 lines
  Raw SQL (->prepare('UPDATE theses SET is_published = ?...')) replaced
  with ->setPublished() / ->bulkSetPublished(). No raw PDO calls remain
  in any action handler file.
2026-04-06 15:33:08 +02:00

5.6 KiB

PHP Components (Reusable Partials)

Form field partials — templates/partials/form/

  • text-field.php — already implemented; used across add.php and edit.php for all single-line fields
  • select-field.php — already implemented; used for orientation, ap, finality, license, access type, etc.
  • checkbox-list.php — already implemented with <fieldset>/<legend class="sr-only">/<ul> structure for WCAG 1.3.1
  • file-field.php — already implemented; used for cover image, banner, and TFE files
  • jury-fieldset.php — already implemented; single partial shared by add.php and edit.php; includes all WCAG aria-labels and JS for dynamic rows

Shared UI partials — templates/partials/

  • pagination.php — partial created and used in both search.php and (now) admin/index.php; admin/index.php also gained proper server-side pagination (25/page) with filter-aware $baseParams
  • status-badge.php — partial fully implemented (templates/partials/status-badge.php) with $badgeType/$badgeValue API; CSS rules in admin.css; used in admin/index.php for publish + access badges
  • admin-alert.php — already done; flash-messages.php calls App::consumeFlash() which handles all legacy key variants (_flash_error, error, admin_error, edit_error, form_error, success, admin_success, edit_success) and clears them all

Controller Extraction (In Progress)

  • Extract SearchControllersrc/SearchController.php; rate-limiting, param sanitisation, DB queries, OG meta, and author-map construction moved out of public/search.php; entry point is now a 6-line dispatcher (create() + handle() + extract()); view template unchanged
  • Extract SystemControllersrc/SystemController.php (452 lines); all status checks, disk/PHP info, log reading, nginx config reading, and line classifiers centralised; system.php reduced 582→282 lines; system-fragment.php reduced 213→137 lines with all duplicated frag_* helpers eliminated
  • Extract ThesisEditControllersrc/ThesisEditController.php (285 lines); load() fetches thesis row, current language/format/jury selections and all lookup tables for the view; save() validates and persists metadata, authors, jury, languages, formats, tags, banner in a transaction; static autofocusFieldForError() centralises WCAG 3.3.1 field-name mapping; admin/edit.php reduced 191→162 lines; actions/edit.php reduced 153→53 lines
  • Extract TfeControllersrc/TfeController.php; ID validation, thesis load (404→redirect), access-type check, meta-description assembly, OG/Twitter tag construction (banner→image→empty resolution), WebVTT caption-file collection, and all page-meta variables moved out of public/tfe.php; entry point is now a 9-line dispatcher (create() + handle() + extract()); tfe.php reduced 271→206 lines; $db reference removed from view layer entirely
  • Extract HomeControllersrc/HomeController.php; page/year param parsing, display-mode detection (default-random / year-filtered / paginated-all), DB queries (getLatestPublishedYear, getLatestYearTheses, searchTheses, countSearchResults, getPublishedTheses, countPublishedTheses, getCoverPathsForTheses, getAvailableYears), cover-image batch loading, OG/meta tag assembly, and $baseParams construction moved out of public/index.php; entry point is now a 6-line dispatcher (create() + handle() + extract()); index.php reduced from 100 → 71 lines; all data-fetching and error-handling logic removed from view layer
  • Consolidate action handlers into controller methods — ThesisCreateController (src/ThesisCreateController.php, 435 lines) extracted from actions/formulaire.php: make() factory, loadFormData() for add-form lookup tables, submit() for full new-thesis creation (validation, transaction, cover/banner/file uploads), autofocusFieldForError() for WCAG 3.3.1; actions/formulaire.php reduced 346→45 lines; admin/add.php DB block replaced with ThesisCreateController::make()->loadFormData(); Database::setPublished() and Database::bulkSetPublished() added, eliminating the raw SQL in actions/publish.php (100→65 lines); no raw PDO calls remain in any action file
  • Unify flash message keys project-wide to _flash_error / _flash_success — all callers already use App::flash(); removed dead legacy-key fallback chains (error, admin_error, edit_error, form_error, success, admin_success, edit_success) from consumeFlash()
  • Move OG tag construction into controller logic — all three public controllers (SearchController, TfeController, and the new home-page controller once extracted) build $ogTags internally and return it as a plain array key; no OG tag assembly remains in entry-point scripts
  • Extract inline CSS/JS from system.php into separate assets — JS moved to public/assets/js/system.js (loaded via $extraJs); 4 inline style= attributes replaced with CSS classes; only dynamic CSS custom properties (--disk-pct, --disk-color) remain as inline styles because they carry PHP runtime values

Backend Maintenance

  • RateLimit cache dir — already in storage/cache/rate_limit; justfile deploy excludes storage/cache/* from rsync. APCu/SQLite migration deferred (not blocking).
  • apropos.php contacts and credits — moved to config/apropos.php config array (contacts[], credits[], erg_url); apropos.php loops over the config with htmlspecialchars; update names/emails by editing only the config file