Files
xamxam/src/HomeController.php
Pontoporeia b1e70a2bf1 Extract HomeController from public/index.php
Move all data-fetching and view-variable assembly out of public/index.php
into a new src/HomeController.php, following the same pattern as
SearchController, TfeController, SystemController, and ThesisEditController.

HomeController::create() builds the Database singleton dependency.
HomeController::handle() encapsulates:
- GET param parsing (page, year) with safe type coercion
- Display-mode detection: default random-latest view / year-filtered /
  paginated-all theses
- All DB calls: getLatestPublishedYear, getLatestYearTheses, searchTheses,
  countSearchResults, getPublishedTheses, countPublishedTheses,
  getCoverPathsForTheses, getAvailableYears
- Batch cover-image loading for theses without a banner_path
- baseParams assembly for the pagination partial
- OG / meta tag array construction
- Graceful error handling (logs exception, returns safe empty state)
- Returns a flat array of view variables

public/index.php is now a 6-line dispatcher (require + create + handle +
extract) followed by a pure view template. Reduced from 100 to 71 lines.
All error-handling and data logic removed from the view layer entirely.
2026-04-06 15:33:08 +02:00

141 lines
5.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* HomeController
*
* Handles all data-fetching and view-variable assembly for the public home page
* (public/index.php).
*
* Responsibilities:
* - Parse and validate GET parameters (`page`, `year`)
* - Determine the display mode (default random-latest / year-filtered / paginated all)
* - Run the appropriate Database queries
* - Batch-load cover images for theses without a banner_path
* - Assemble OG / meta tag array
* - Return a flat array of view variables ready for template extraction
*
* The class has NO output side-effects; all template rendering stays in
* public/index.php so the view layer remains easy to inspect and modify.
*/
class HomeController
{
private const ITEMS_PER_PAGE = 24;
private Database $db;
public function __construct(Database $db)
{
$this->db = $db;
}
// ── Factory ───────────────────────────────────────────────────────────────
/**
* Convenience factory: loads the Database singleton and returns a ready
* controller instance.
*/
public static function create(): self
{
require_once APP_ROOT . '/src/Database.php';
return new self(Database::getInstance());
}
// ── Main entry point ─────────────────────────────────────────────────────
/**
* Process the current request and return all variables needed by the view.
*
* @return array<string, mixed>
*/
public function handle(): array
{
$page = isset($_GET['page']) ? max(1, (int) $_GET['page']) : 1;
$year = isset($_GET['year']) ? (int) $_GET['year'] : null;
// Normalise zero (e.g. ?year=0) to null so it is treated as "no filter"
if ($year === 0) {
$year = null;
}
// Default home view: random theses from latest year (no year filter, no explicit page)
$isDefaultView = ($year === null && $page === 1);
$itemsToLoad = [];
$totalItems = 0;
$availableYears = [];
$latestYear = null;
$coverMap = [];
try {
$offset = ($page - 1) * self::ITEMS_PER_PAGE;
$availableYears = $this->db->getAvailableYears();
if ($year !== null) {
$itemsToLoad = $this->db->searchTheses(['year' => $year], self::ITEMS_PER_PAGE, $offset);
$totalItems = $this->db->countSearchResults(['year' => $year]);
} elseif ($isDefaultView) {
$latestYear = $this->db->getLatestPublishedYear();
$itemsToLoad = $this->db->getLatestYearTheses(self::ITEMS_PER_PAGE);
$totalItems = count($itemsToLoad); // no multi-page on default view
} else {
$itemsToLoad = $this->db->getPublishedTheses(self::ITEMS_PER_PAGE, $offset);
$totalItems = $this->db->countPublishedTheses();
}
// Batch-load cover images for theses that have no banner_path
if (!empty($itemsToLoad)) {
$needCover = array_column(
array_filter($itemsToLoad, static fn($t) => empty($t['banner_path'])),
'id'
);
if (!empty($needCover)) {
$coverMap = $this->db->getCoverPathsForTheses($needCover);
}
}
} catch (Exception $e) {
error_log('HomeController: ' . $e->getMessage());
// Return safe empty state; view will show "Aucun mémoire trouvé"
$isDefaultView = false;
}
$totalPages = $isDefaultView ? 1 : (int) ceil($totalItems / self::ITEMS_PER_PAGE);
// Avoid division by zero on empty DB
if ($totalPages < 1) {
$totalPages = 0;
}
$baseParams = array_filter(['year' => $year]);
return [
// Pagination / filter state
'page' => $page,
'year' => $year,
'isDefaultView' => $isDefaultView,
'totalItems' => $totalItems,
'totalPages' => $totalPages,
'baseParams' => $baseParams,
// Thesis data
'itemsToLoad' => $itemsToLoad,
'latestYear' => $latestYear,
'availableYears' => $availableYears,
'coverMap' => $coverMap,
// Page meta
'pageTitle' => 'Posterg Mémoires de l\'ERG',
'metaDescription' => 'Posterg répertorie et valorise les mémoires de fin d\'études (TFE) de l\'erg École de Recherches Graphiques de Bruxelles.',
'ogTags' => [
'type' => 'website',
'title' => 'Posterg Mémoires de l\'ERG',
'description' => 'Posterg répertorie et valorise les mémoires de fin d\'études (TFE) de l\'erg École de Recherches Graphiques de Bruxelles.',
'url' => 'https://posterg.erg.be/',
'site_name' => 'Posterg ERG',
],
// Layout
'currentNav' => '',
'extraCss' => ['/assets/css/main.css'],
'bodyClass' => 'home-body',
];
}
}