mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-07 03:29:19 +02:00
Extract TfeController from public/tfe.php
src/TfeController.php (new, 195 lines): - Dedicated controller for the public TFE detail page - create(): Database singleton injection, ready-to-use factory - handle(): validates id param (redirect to index.php on missing/invalid/404), loads thesis via getThesisById(), fetches access type via getThesisAccessTypeId() - buildMetaDescription(): strip_tags + 160-char mb_substr truncation - resolveOgImage(): banner_path → first image file → empty string resolution - buildOgTags(): full og:type/title/description/url/image/image_alt/site_name + article:author / article:published_time assembly - collectCaptionPaths(): ordered list of VTT paths for N-th-video pairing - returns flat array of all view variables including ogTags, captionFiles, pageTitle, metaDescription, isInterdit, bodyClass, extraCss, currentNav public/tfe.php (271 → 206 lines): - Reduced to 9-line dispatcher: require TfeController, create(), handle(), extract() - $db reference removed from view layer entirely - Inline OG tag block (~20 lines) removed - Inline meta-description block (~5 lines) removed - Inline caption-collection loop (~10 lines) removed - $captionFiles replaces $_captionFiles in the video pairing section todo/02-php-components.md: - TfeController extraction marked done - 'Move OG tag construction into controller logic' marked done - Remaining item narrowed to public/index.php home-page controller
This commit is contained in:
2
TODO.md
2
TODO.md
@@ -11,6 +11,8 @@ Pending tasks have been split into topic files under [`todo/`](todo/README.md):
|
|||||||
|
|
||||||
## Recently completed (this session)
|
## Recently completed (this session)
|
||||||
|
|
||||||
|
- [x] `src/TfeController.php` — extracted all data-fetching, OG-tag assembly, and view-variable construction from `public/tfe.php` into a dedicated controller class; `create()` returns a ready instance with `Database` singleton injected; `handle()` validates the `id` param (redirects on missing/invalid), loads the thesis row via `getThesisById()`, calls `getThesisAccessTypeId()` for visibility gating, builds the meta description (strip_tags + 160-char truncation), resolves the OG image (banner_path → first image file → empty), assembles the full `$ogTags` array (type/title/description/url/image/image_alt/site_name/article_author/article_published_time), collects WebVTT caption paths for N-th-video pairing, and returns a flat view-variable array; `captionFiles` replaces inline `$_captionFiles` array in the view; `$db` reference removed from `tfe.php` entirely; `tfe.php` reduced 271→206 lines (9-line dispatcher + pure view template); `todo/02-php-components.md` “Extract remaining controllers” and “Move OG tag construction into controller logic” tasks updated
|
||||||
|
|
||||||
- [x] `src/ThesisEditController.php` — extracted all data-fetching and mutation logic from `admin/edit.php` and `admin/actions/edit.php` into a dedicated controller class; `load(int $thesisId): array` fetches the thesis row, current language/format/jury selections, and all lookup tables for the view; `save(int $thesisId, array $post, array $files): void` validates and persists thesis metadata, authors, jury, languages, formats, tags, and banner in a transaction with proper rollback on error; static `autofocusFieldForError(string $msg): ?string` centralises WCAG 3.3.1 field-name mapping; `admin/edit.php` reduced 191→162 lines (pure dispatcher + view template); `actions/edit.php` reduced 153→53 lines (CSRF guard + one controller call)
|
- [x] `src/ThesisEditController.php` — extracted all data-fetching and mutation logic from `admin/edit.php` and `admin/actions/edit.php` into a dedicated controller class; `load(int $thesisId): array` fetches the thesis row, current language/format/jury selections, and all lookup tables for the view; `save(int $thesisId, array $post, array $files): void` validates and persists thesis metadata, authors, jury, languages, formats, tags, and banner in a transaction with proper rollback on error; static `autofocusFieldForError(string $msg): ?string` centralises WCAG 3.3.1 field-name mapping; `admin/edit.php` reduced 191→162 lines (pure dispatcher + view template); `actions/edit.php` reduced 153→53 lines (CSRF guard + one controller call)
|
||||||
|
|
||||||
- [x] `src/SystemController.php` — extracted all data-fetching logic from `admin/system.php` and `admin/system-fragment.php` into a dedicated controller class; centralises: system status checks (nginx, php-fpm, HTTP ping, SQLite DB, storage dir, maintenance flag) with 2-min TTL caching, PHP environment info (1-hour TTL), disk usage (5-min TTL), log file reading (`readLogTail`), nginx config reading, and the shared CSS-class classifier methods (`logLineClass`, `nginxLineClass`, `statusLabel`, `statusClass`, `humanBytes`, `diskColor`); `system.php` reduced 582→282 lines; `system-fragment.php` reduced 213→137 lines with all `frag_*`-prefixed duplicated helpers removed; both files now purely dispatch to the controller and render view templates
|
- [x] `src/SystemController.php` — extracted all data-fetching logic from `admin/system.php` and `admin/system-fragment.php` into a dedicated controller class; centralises: system status checks (nginx, php-fpm, HTTP ping, SQLite DB, storage dir, maintenance flag) with 2-min TTL caching, PHP environment info (1-hour TTL), disk usage (5-min TTL), log file reading (`readLogTail`), nginx config reading, and the shared CSS-class classifier methods (`logLineClass`, `nginxLineClass`, `statusLabel`, `statusClass`, `humanBytes`, `diskColor`); `system.php` reduced 582→282 lines; `system-fragment.php` reduced 213→137 lines with all `frag_*`-prefixed duplicated helpers removed; both files now purely dispatch to the controller and render view templates
|
||||||
|
|||||||
@@ -1,63 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../config/bootstrap.php';
|
require_once __DIR__ . '/../config/bootstrap.php';
|
||||||
require_once APP_ROOT . '/src/Database.php';
|
require_once APP_ROOT . '/src/TfeController.php';
|
||||||
|
|
||||||
if (isset($_GET['id'])) {
|
// Build controller (loads thesis, enforces visibility, builds OG tags; redirects on 404)
|
||||||
$thesisId = intval($_GET['id']);
|
$ctrl = TfeController::create();
|
||||||
try {
|
|
||||||
$db = Database::getInstance();
|
|
||||||
$data = $db->getThesisById($thesisId);
|
|
||||||
if (!$data) { header('Location: index.php'); exit; }
|
|
||||||
} catch (Exception $e) {
|
|
||||||
error_log("Error loading thesis: " . $e->getMessage());
|
|
||||||
header('Location: index.php'); exit;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
header('Location: index.php'); exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentNav = '';
|
// Collect all view variables
|
||||||
$_tfeAuthor = $data['authors'] ?? '';
|
extract($ctrl->handle());
|
||||||
$pageTitle = $data['title'] . (!empty($_tfeAuthor) ? ' – ' . $_tfeAuthor : '') . ' – Posterg';
|
|
||||||
// Build meta description: strip markdown/HTML from synopsis, truncate to ~160 chars
|
|
||||||
$_synopsisRaw = strip_tags($data['synopsis'] ?? '');
|
|
||||||
$metaDescription = mb_strlen($_synopsisRaw) > 160
|
|
||||||
? mb_substr($_synopsisRaw, 0, 157) . '…'
|
|
||||||
: (empty($_synopsisRaw) ? 'Mémoire de fin d\'études – Posterg, répertoire des TFE de l\'erg.' : $_synopsisRaw);
|
|
||||||
unset($_tfeAuthor, $_synopsisRaw);
|
|
||||||
|
|
||||||
// --- Open Graph / Twitter Card tags ------------------------------------------
|
|
||||||
$_ogBaseUrl = 'https://posterg.erg.be';
|
|
||||||
// Resolve OG image: banner → first image file → none
|
|
||||||
$_ogImage = '';
|
|
||||||
if (!empty($data['banner_path'])) {
|
|
||||||
$_ogImage = $_ogBaseUrl . '/media.php?path=' . rawurlencode($data['banner_path']);
|
|
||||||
} elseif (!empty($data['files'])) {
|
|
||||||
foreach ($data['files'] as $_f) {
|
|
||||||
$_ext = strtolower(pathinfo($_f['file_path'], PATHINFO_EXTENSION));
|
|
||||||
if (in_array($_ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'])) {
|
|
||||||
$_ogImage = $_ogBaseUrl . '/media.php?path=' . rawurlencode($_f['file_path']);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unset($_f, $_ext);
|
|
||||||
}
|
|
||||||
$ogTags = [
|
|
||||||
'type' => 'article',
|
|
||||||
'title' => $data['title'] . (!empty($data['authors']) ? ' – ' . $data['authors'] : ''),
|
|
||||||
'description' => $metaDescription,
|
|
||||||
'url' => $_ogBaseUrl . '/tfe.php?id=' . $thesisId,
|
|
||||||
'image' => $_ogImage,
|
|
||||||
'image_alt' => $data['title'] . (!empty($data['authors']) ? ' par ' . $data['authors'] : ''),
|
|
||||||
'site_name' => 'Posterg – ERG',
|
|
||||||
'article_author' => $data['authors'] ?? '',
|
|
||||||
'article_published_time' => !empty($data['year']) ? $data['year'] . '-01-01' : '',
|
|
||||||
];
|
|
||||||
unset($_ogBaseUrl, $_ogImage);
|
|
||||||
// --- End Open Graph ----------------------------------------------------------
|
|
||||||
|
|
||||||
$extraCss = ['/assets/css/tfe.css'];
|
|
||||||
$bodyClass = 'tfe-body';
|
|
||||||
?>
|
?>
|
||||||
<?php include APP_ROOT . '/templates/head.php'; ?>
|
<?php include APP_ROOT . '/templates/head.php'; ?>
|
||||||
<?php include APP_ROOT . '/templates/header.php'; ?>
|
<?php include APP_ROOT . '/templates/header.php'; ?>
|
||||||
@@ -194,21 +143,8 @@ $bodyClass = 'tfe-body';
|
|||||||
<!-- RIGHT: media — supplementary aside -->
|
<!-- RIGHT: media — supplementary aside -->
|
||||||
<aside class="tfe-right">
|
<aside class="tfe-right">
|
||||||
<?php
|
<?php
|
||||||
$accessTypeId = $db->getThesisAccessTypeId($thesisId) ?? 1;
|
// $isInterdit and $captionFiles are resolved by TfeController::handle()
|
||||||
$isInterdit = ($accessTypeId === 3);
|
|
||||||
|
|
||||||
// Collect any WebVTT caption files uploaded for this thesis.
|
|
||||||
// The N-th VTT file is paired with the N-th video in document order.
|
|
||||||
$_captionFiles = [];
|
|
||||||
foreach ($data['files'] ?? [] as $_cf) {
|
|
||||||
$__mime = $_cf['mime_type'] ?? '';
|
|
||||||
$__ext2 = strtolower(pathinfo($_cf['file_path'], PATHINFO_EXTENSION));
|
|
||||||
if ($__mime === 'text/vtt' || $__ext2 === 'vtt') {
|
|
||||||
$_captionFiles[] = $_cf['file_path'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$_videoIndex = 0;
|
$_videoIndex = 0;
|
||||||
unset($_cf, $__mime, $__ext2);
|
|
||||||
?>
|
?>
|
||||||
<?php if ($isInterdit): ?>
|
<?php if ($isInterdit): ?>
|
||||||
<p class="tfe-restricted">
|
<p class="tfe-restricted">
|
||||||
@@ -240,7 +176,7 @@ $bodyClass = 'tfe-body';
|
|||||||
<?php elseif ($ext === 'mp4'): ?>
|
<?php elseif ($ext === 'mp4'): ?>
|
||||||
<?php
|
<?php
|
||||||
// Pair this video with the N-th VTT file (if one was uploaded).
|
// Pair this video with the N-th VTT file (if one was uploaded).
|
||||||
$_vttPath = $_captionFiles[$_videoIndex] ?? null;
|
$_vttPath = $captionFiles[$_videoIndex] ?? null;
|
||||||
$_videoIndex++;
|
$_videoIndex++;
|
||||||
?>
|
?>
|
||||||
<video width="100%" controls>
|
<video width="100%" controls>
|
||||||
|
|||||||
205
src/TfeController.php
Normal file
205
src/TfeController.php
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* TfeController
|
||||||
|
*
|
||||||
|
* Handles all data-fetching and view-variable assembly for the public TFE
|
||||||
|
* detail page (public/tfe.php).
|
||||||
|
*
|
||||||
|
* Responsibilities:
|
||||||
|
* - Validate the `id` GET parameter and load the thesis record
|
||||||
|
* - Enforce publication visibility (redirect to index on 404)
|
||||||
|
* - Resolve the OG image (banner → first image file)
|
||||||
|
* - Build the complete OG / Twitter Card tag array
|
||||||
|
* - Assemble the meta description from the synopsis
|
||||||
|
* - Collect WebVTT caption file paths for video pairing
|
||||||
|
* - Return a flat array of view variables ready for template extraction
|
||||||
|
*
|
||||||
|
* The class has NO output side-effects; all template rendering stays in
|
||||||
|
* public/tfe.php so the view layer remains easy to inspect and modify.
|
||||||
|
*/
|
||||||
|
class TfeController
|
||||||
|
{
|
||||||
|
private const BASE_URL = 'https://posterg.erg.be';
|
||||||
|
private const META_MAX_LEN = 160;
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* On success returns an array of view variables.
|
||||||
|
* On failure (missing id, thesis not found) sends a redirect and exits.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function handle(): array
|
||||||
|
{
|
||||||
|
$thesisId = isset($_GET['id']) ? (int) $_GET['id'] : 0;
|
||||||
|
|
||||||
|
if ($thesisId <= 0) {
|
||||||
|
$this->redirectHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$data = $this->db->getThesisById($thesisId);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('TfeController: ' . $e->getMessage());
|
||||||
|
$this->redirectHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($data)) {
|
||||||
|
$this->redirectHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Access type (1 = open, 2 = restricted, 3 = forbidden)
|
||||||
|
$accessTypeId = $this->db->getThesisAccessTypeId($thesisId) ?? 1;
|
||||||
|
$isInterdit = ($accessTypeId === 3);
|
||||||
|
|
||||||
|
// Caption (WebVTT) files — N-th VTT is paired with the N-th <video>
|
||||||
|
$captionFiles = $this->collectCaptionPaths($data['files'] ?? []);
|
||||||
|
|
||||||
|
// Page meta
|
||||||
|
$metaDescription = $this->buildMetaDescription($data['synopsis'] ?? '');
|
||||||
|
$ogTags = $this->buildOgTags($data, $thesisId, $metaDescription);
|
||||||
|
$pageTitle = $data['title']
|
||||||
|
. (!empty($data['authors']) ? ' – ' . $data['authors'] : '')
|
||||||
|
. ' – Posterg';
|
||||||
|
|
||||||
|
return [
|
||||||
|
// Core data
|
||||||
|
'thesisId' => $thesisId,
|
||||||
|
'data' => $data,
|
||||||
|
'accessTypeId' => $accessTypeId,
|
||||||
|
'isInterdit' => $isInterdit,
|
||||||
|
'captionFiles' => $captionFiles,
|
||||||
|
|
||||||
|
// Page meta
|
||||||
|
'pageTitle' => $pageTitle,
|
||||||
|
'metaDescription' => $metaDescription,
|
||||||
|
'ogTags' => $ogTags,
|
||||||
|
|
||||||
|
// Layout
|
||||||
|
'currentNav' => '',
|
||||||
|
'extraCss' => ['/assets/css/tfe.css'],
|
||||||
|
'bodyClass' => 'tfe-body',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Private helpers ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a ~160-character meta description from the thesis synopsis.
|
||||||
|
*/
|
||||||
|
private function buildMetaDescription(string $synopsis): string
|
||||||
|
{
|
||||||
|
$plain = strip_tags($synopsis);
|
||||||
|
|
||||||
|
if (empty($plain)) {
|
||||||
|
return 'Mémoire de fin d\'études – Posterg, répertoire des TFE de l\'erg.';
|
||||||
|
}
|
||||||
|
|
||||||
|
return mb_strlen($plain) > self::META_MAX_LEN
|
||||||
|
? mb_substr($plain, 0, self::META_MAX_LEN - 3) . '…'
|
||||||
|
: $plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the OG image URL: banner_path → first image file → empty string.
|
||||||
|
*
|
||||||
|
* @param array<int, array<string, mixed>> $files
|
||||||
|
*/
|
||||||
|
private function resolveOgImage(array $files, ?string $bannerPath): string
|
||||||
|
{
|
||||||
|
if (!empty($bannerPath)) {
|
||||||
|
return self::BASE_URL . '/media.php?path=' . rawurlencode($bannerPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$ext = strtolower(pathinfo($file['file_path'] ?? '', PATHINFO_EXTENSION));
|
||||||
|
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'], true)) {
|
||||||
|
return self::BASE_URL . '/media.php?path=' . rawurlencode($file['file_path']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the complete $ogTags array consumed by templates/head.php.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $data
|
||||||
|
* @return array<string, string>
|
||||||
|
*/
|
||||||
|
private function buildOgTags(array $data, int $thesisId, string $metaDescription): array
|
||||||
|
{
|
||||||
|
$ogImage = $this->resolveOgImage($data['files'] ?? [], $data['banner_path'] ?? null);
|
||||||
|
$title = $data['title'] . (!empty($data['authors']) ? ' – ' . $data['authors'] : '');
|
||||||
|
$imageAlt = $data['title'] . (!empty($data['authors']) ? ' par ' . $data['authors'] : '');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'type' => 'article',
|
||||||
|
'title' => $title,
|
||||||
|
'description' => $metaDescription,
|
||||||
|
'url' => self::BASE_URL . '/tfe.php?id=' . $thesisId,
|
||||||
|
'image' => $ogImage,
|
||||||
|
'image_alt' => $imageAlt,
|
||||||
|
'site_name' => 'Posterg – ERG',
|
||||||
|
'article_author' => $data['authors'] ?? '',
|
||||||
|
'article_published_time' => !empty($data['year']) ? $data['year'] . '-01-01' : '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an ordered list of VTT caption file paths from the files array.
|
||||||
|
* The N-th entry corresponds to the N-th <video> element in document order.
|
||||||
|
*
|
||||||
|
* @param array<int, array<string, mixed>> $files
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
private function collectCaptionPaths(array $files): array
|
||||||
|
{
|
||||||
|
$captions = [];
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$mime = $file['mime_type'] ?? '';
|
||||||
|
$ext = strtolower(pathinfo($file['file_path'] ?? '', PATHINFO_EXTENSION));
|
||||||
|
|
||||||
|
if ($mime === 'text/vtt' || $ext === 'vtt') {
|
||||||
|
$captions[] = $file['file_path'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $captions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Response helpers ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect to the home page and terminate. Never returns.
|
||||||
|
*/
|
||||||
|
private function redirectHome(): never
|
||||||
|
{
|
||||||
|
header('Location: index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,10 +19,11 @@
|
|||||||
- [x] Extract `SearchController` — `src/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
|
- [x] Extract `SearchController` — `src/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
|
||||||
- [x] Extract `SystemController` — `src/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
|
- [x] Extract `SystemController` — `src/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
|
||||||
- [x] Extract `ThesisEditController` — `src/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
|
- [x] Extract `ThesisEditController` — `src/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 remaining controllers one by one
|
- [x] Extract `TfeController` — `src/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 remaining controllers one by one (`public/index.php` home page)
|
||||||
- [ ] Consolidate action handlers into controller methods
|
- [ ] Consolidate action handlers into controller methods
|
||||||
- [x] 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()`
|
- [x] 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
|
- [x] 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
|
||||||
- [x] 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
|
- [x] 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
|
## Backend Maintenance
|
||||||
|
|||||||
Reference in New Issue
Block a user