Files
geograsim/App/php/api/glossar.php
T
Adminator 1e51ef7def Nachtrag: alle bisher untracked Ordner + hängende Änderungen mit-committen
- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/
- 12 code-workspace-Files
- STATUS-*.md
- viele M/D/R-Änderungen an bereits getrackten Files
- .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-08 02:27:02 +02:00

207 lines
8.2 KiB
PHP

<?php
/**
* Glossar API
* GET /api/glossar → alle Einträge (nur Kernfelder)
* GET /api/glossar?key=co2 → einzelner Eintrag (volles Detail für Tooltip/Seite)
* GET /api/glossar?module=klima → alle Einträge eines Moduls
* GET /api/glossar?search=treibhaus → Volltextsuche
*
* POST /api/glossar (nur Admin) → neuer Eintrag (TODO)
* PUT /api/glossar?id=42 (Admin) → bearbeiten (TODO)
*/
require_once __DIR__ . '/../config/app.php';
require_once __DIR__ . '/../config/db.php';
header('Content-Type: application/json; charset=utf-8');
$db = getDB();
// === Leichte Sprache ===
// Priorität: ?easy=1|0 (explizit) > Schüler-Session mit students.easy_language=1 > normal
if (session_status() === PHP_SESSION_NONE) session_start();
$easy = false;
if (isset($_GET['easy'])) {
$easy = $_GET['easy'] === '1';
} elseif (!empty($_SESSION['student_id'])) {
if (!isset($_SESSION['_easy_cache']) || ($_SESSION['_easy_cache']['id'] ?? null) !== $_SESSION['student_id']) {
$stmt = $db->prepare('SELECT easy_language FROM students WHERE id = ?');
$stmt->execute([$_SESSION['student_id']]);
$r = $stmt->fetch(PDO::FETCH_ASSOC);
$_SESSION['_easy_cache'] = ['id' => $_SESSION['student_id'], 'val' => !empty($r['easy_language'])];
}
$easy = $_SESSION['_easy_cache']['val'];
}
// Cache pro Variante
header($easy ? 'Cache-Control: private, max-age=60' : 'Cache-Control: public, max-age=600');
/** Liefert Easy-Variante, sonst Fallback auf normal */
function pickText(array $row, string $normalKey, string $easyKey, bool $easy) {
if ($easy && !empty($row[$easyKey])) return $row[$easyKey];
return $row[$normalKey] ?? null;
}
try {
$method = $_SERVER['REQUEST_METHOD'];
if ($method === 'GET') {
// Count-Endpoint: nur Anzahl Begriffe (für Landingpage-Pill)
if (!empty($_GET['count'])) {
$n = (int) $db->query('SELECT COUNT(*) FROM glossar')->fetchColumn();
echo json_encode(['count' => $n]);
exit;
}
// Graph-Endpoint: alle Nodes + Edges für die Mindmap
if (!empty($_GET['graph'])) {
// Nodes inkl. Module-Zuordnung
$nodes = $db->query('
SELECT g.id, g.key_slug, g.title, g.short, g.category, g.image_path,
GROUP_CONCAT(m.module_id) AS modules
FROM glossar g
LEFT JOIN glossar_modules m ON m.glossar_id = g.id
GROUP BY g.id
ORDER BY g.title
')->fetchAll(PDO::FETCH_ASSOC);
foreach ($nodes as &$n) {
$n['modules'] = $n['modules'] ? explode(',', $n['modules']) : [];
$n['id'] = (int) $n['id'];
}
unset($n);
// Edges: related-Tabelle — jede Kante einmal (kleinere id → grössere id)
$edges = $db->query('
SELECT LEAST(glossar_id, related_id) AS a, GREATEST(glossar_id, related_id) AS b
FROM glossar_related
GROUP BY a, b
')->fetchAll(PDO::FETCH_ASSOC);
foreach ($edges as &$e) {
$e['a'] = (int) $e['a'];
$e['b'] = (int) $e['b'];
}
unset($e);
echo json_encode(['nodes' => $nodes, 'edges' => $edges], JSON_UNESCAPED_UNICODE);
exit;
}
// Einzelner Eintrag per key_slug
if (!empty($_GET['key'])) {
$key = $_GET['key'];
$entry = $db->prepare('SELECT * FROM glossar WHERE key_slug = ?');
$entry->execute([$key]);
$row = $entry->fetch(PDO::FETCH_ASSOC);
if (!$row) {
http_response_code(404);
echo json_encode(['error' => 'not found']);
exit;
}
// Leichte Sprache: falls aktiv, short/text durch easy-Varianten ersetzen (Fallback auf normal)
$row['short'] = pickText($row, 'short', 'short_easy', $easy);
$row['text'] = pickText($row, 'text', 'text_easy', $easy);
$row['_easy'] = $easy; // Meta-Info fürs Frontend
// Roh-Easy-Felder entfernen, damit JSON schlank bleibt
unset($row['short_easy'], $row['text_easy']);
// Module
$mods = $db->prepare('SELECT module_id FROM glossar_modules WHERE glossar_id = ?');
$mods->execute([$row['id']]);
$row['modules'] = $mods->fetchAll(PDO::FETCH_COLUMN);
// Beispiele (inkl. optionaler Quellen-Referenz + Easy-Variante)
$ex = $db->prepare('SELECT text, text_easy, source_ref FROM glossar_examples WHERE glossar_id = ? ORDER BY sort_order');
$ex->execute([$row['id']]);
$examples = $ex->fetchAll(PDO::FETCH_ASSOC);
foreach ($examples as &$e) {
$e['text'] = pickText($e, 'text', 'text_easy', $easy);
unset($e['text_easy']);
}
unset($e);
$row['examples'] = $examples;
// Quellen
$sr = $db->prepare('SELECT ref_num, label, url, access_date FROM glossar_sources WHERE glossar_id = ? ORDER BY ref_num');
$sr->execute([$row['id']]);
$row['sources'] = $sr->fetchAll(PDO::FETCH_ASSOC);
// Links
$lk = $db->prepare('SELECT label, url FROM glossar_links WHERE glossar_id = ? ORDER BY sort_order');
$lk->execute([$row['id']]);
$row['links'] = $lk->fetchAll(PDO::FETCH_ASSOC);
// Related (mit title + key)
$rel = $db->prepare('
SELECT g.key_slug, g.title
FROM glossar_related r
JOIN glossar g ON g.id = r.related_id
WHERE r.glossar_id = ?
');
$rel->execute([$row['id']]);
$row['related'] = $rel->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($row, JSON_UNESCAPED_UNICODE);
exit;
}
// Alle Einträge eines Moduls
if (!empty($_GET['module'])) {
$mod = $_GET['module'];
$stmt = $db->prepare('
SELECT g.id, g.key_slug, g.title, g.short, g.short_easy, g.text, g.text_easy,
g.unit, g.category, g.image_path, g.animation_path
FROM glossar g
JOIN glossar_modules m ON m.glossar_id = g.id
WHERE m.module_id = ?
ORDER BY g.title
');
$stmt->execute([$mod]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as &$r) {
$r['short'] = pickText($r, 'short', 'short_easy', $easy);
$r['text'] = pickText($r, 'text', 'text_easy', $easy);
unset($r['short_easy'], $r['text_easy']);
}
unset($r);
echo json_encode($rows, JSON_UNESCAPED_UNICODE);
exit;
}
// Volltextsuche
if (!empty($_GET['search'])) {
$q = '%' . $_GET['search'] . '%';
$stmt = $db->prepare('
SELECT id, key_slug, title, short, category
FROM glossar
WHERE title LIKE ? OR short LIKE ? OR text LIKE ?
ORDER BY title
LIMIT 50
');
$stmt->execute([$q, $q, $q]);
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC), JSON_UNESCAPED_UNICODE);
exit;
}
// Alle Einträge (Übersicht) mit Modul-Zuordnungen
$stmt = $db->query('
SELECT g.id, g.key_slug, g.title, g.short, g.category, g.image_path,
GROUP_CONCAT(m.module_id) AS modules
FROM glossar g
LEFT JOIN glossar_modules m ON m.glossar_id = g.id
GROUP BY g.id
ORDER BY g.title
');
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as &$r) {
$r['modules'] = $r['modules'] ? explode(',', $r['modules']) : [];
}
echo json_encode($rows, JSON_UNESCAPED_UNICODE);
exit;
}
http_response_code(405);
echo json_encode(['error' => 'method not allowed']);
} catch (Throwable $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}