viewDir = __DIR__ . '/Views'; Auth::startSession(); if (isset($_SESSION['flash'])) { $this->flash = $_SESSION['flash']; unset($_SESSION['flash']); } } public function render(string $template, array $daten = []): void { $daten['flash'] = $this->flash; $daten['aktuellerPfad'] = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH); extract($daten, EXTR_SKIP); include $this->viewDir . '/' . $template; } public static function redirect(string $pfad, string $meldung = '', string $typ = 'erfolg'): void { Auth::startSession(); if ($meldung !== '') { $_SESSION['flash'][] = ['typ' => $typ, 'meldung' => $meldung]; } header('Location: ' . $pfad); exit; } public static function h(mixed $wert): string { return htmlspecialchars((string)$wert, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } /** * Beträge im deutschen Format. Das Leerzeichen vor dem Euro-Zeichen ist * geschützt, sonst rutscht das Zeichen in schmalen Tabellenspalten allein * in die nächste Zeile. */ public static function betrag(mixed $wert, bool $mitWaehrung = true): string { $text = number_format((float)$wert, 2, ',', '.'); return $mitWaehrung ? $text . "\u{00A0}€" : $text; } /** * Stückzahlen. Fonds werden in Bruchteilen geführt, Aktien in ganzen * Stücken – dieselbe Spalte trägt beides, deshalb sechs Nachkommastellen * ohne die Nullen, die niemand liest: „12“ statt „12,000000“. */ public static function stueck(mixed $wert): string { return rtrim(rtrim(number_format((float)$wert, 6, ',', '.'), '0'), ','); } /** * Monatsnamen auf Deutsch. Nicht über date('F') oder IntlDateFormatter – * date() ist immer englisch und intl ist keine Standarderweiterung. Der * Budgetplaner und die Auswertungen greifen später ebenfalls hierauf zu. */ public const MONATE = [ 1 => 'Januar', 2 => 'Februar', 3 => 'März', 4 => 'April', 5 => 'Mai', 6 => 'Juni', 7 => 'Juli', 8 => 'August', 9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Dezember', ]; /** Kurzform für schmale Spalten (zwölf Monatsspalten im Budgetplaner). */ public const MONATE_KURZ = [ 1 => 'Jan', 2 => 'Feb', 3 => 'Mär', 4 => 'Apr', 5 => 'Mai', 6 => 'Jun', 7 => 'Jul', 8 => 'Aug', 9 => 'Sep', 10 => 'Okt', 11 => 'Nov', 12 => 'Dez', ]; public static function monat(int $monat, bool $kurz = false): string { $namen = $kurz ? self::MONATE_KURZ : self::MONATE; return $namen[$monat] ?? (string)$monat; } /** Wochentagskürzel, Montag zuerst – wie MONATE nicht über date() oder intl. */ public const WOCHENTAGE = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']; public static function wochentag(?string $datum): string { if (!$datum) { return ''; } $zeit = strtotime(substr($datum, 0, 10)); if ($zeit === false) { return ''; } // date('N') zählt Montag als 1. return self::WOCHENTAGE[(int)date('N', $zeit) - 1] ?? ''; } public static function datum(?string $datum): string { if (!$datum) { return '–'; } $d = \DateTime::createFromFormat('Y-m-d', substr($datum, 0, 10)); return $d ? $d->format('d.m.Y') : $datum; } /** CSS-Klasse für Beträge: negative Werte werden rot dargestellt. */ public static function betragKlasse(mixed $wert): string { return (float)$wert < 0 ? 'betrag negativ' : 'betrag'; } /** * Das Symbol der Abgleichspalte im Kontoblatt. Vier Zustände, in dieser * Reihenfolge zu lesen: gefunden, nicht gefunden, Abruf gescheitert – und * der graue Kreis für alles, was mit dem Bargeld-Tool nichts zu tun hat. * * Die Zeichen stehen als Text und nicht als Grafik da: Sie erben damit * Schriftgröße und – beim Ausrufezeichen ausdrücklich gewünscht – die * Farbe des übrigen Textes, in jedem Farbschema. * * Eigenständige Methode statt einer Schleife im Kontoblatt, weil auch die * Schnellzuordnung (kontoblatt.js) dasselbe Symbol braucht, ohne die Seite * neu zu laden. */ public static function bargeldMarke(?string $status, ?string $hinweis): string { $hinweis = trim((string)$hinweis); [$zeichen, $klasse, $standardtitel] = match ($status) { 'gefunden' => ['✓', 'gefunden', 'Im Bargeld-Tool gefunden'], 'fehlt' => ['✗', 'fehlt', 'Im Bargeld-Tool nicht gefunden'], 'fehler' => ['!', 'fehler', 'Der Abruf beim Bargeld-Tool ist gescheitert'], default => ['●', 'neutral', 'Wird nicht mit dem Bargeld-Tool abgeglichen'], }; return '' . $zeichen . ''; } /** * Farbschema für das data-thema-Attribut: 'hell', 'dunkel' oder '' für die * Systemvorgabe. Fällt auf die Systemvorgabe zurück, wenn die Einstellung * nicht lesbar ist – die Fehlerseite muss auch ohne Datenbank darstellbar * bleiben. */ public static function thema(): string { try { $thema = \Finanzmanager\Models\Einstellung::get('darstellung_thema', 'system'); } catch (\Throwable) { return ''; } return in_array($thema, ['hell', 'dunkel'], true) ? $thema : ''; } }