verlangeAnmeldung(); $this->render('auswertungen/index.php', [ 'titel' => 'Auswertungen', 'gruppen' => Bericht::nachGruppe(), 'letzte' => Bericht::letzte(), 'typen' => Auswertung::TYPEN, 'anzahl' => Bericht::anzahl(), ]); } /** Ein Bericht aus einer Standardvorlage – die Filter stehen in der Adresse. */ public function bericht(): void { $this->verlangeAnmeldung(); $this->zeige(null, $this->filterAusQuery()); } /** Ein gespeicherter Bericht. */ public function gespeichert(array $params): void { $this->verlangeAnmeldung(); $gespeichert = Bericht::find((int)$params['id']); if ($gespeichert === null) { View::redirect('/auswertungen', 'Diesen Bericht gibt es nicht.', 'fehler'); } Bericht::benutzt((int)$gespeichert['id']); $this->zeige($gespeichert, $this->filterFuer($gespeichert)); } /** * „Speichern“ überschreibt den geöffneten Bericht, „Speichern unter“ legt * unter neuem Namen an. Beides landet hier – der Unterschied steckt allein * darin, ob eine Id mitkommt. */ public function speichern(): void { $this->verlangeAnmeldung(); $filter = Auswertung::normalisiere($_POST); $name = $this->post('name'); $gruppe = (int)$this->post('gruppe_id'); $id = (int)$this->post('bericht_id'); // Eine neue Gruppe darf direkt im Speichern-Dialog entstehen; wer sie // erst anlegen müsste, verlöre den eingestellten Filter. $neueGruppe = $this->post('neue_gruppe'); if ($neueGruppe !== '') { try { $gruppe = Berichtsgruppe::findenOderAnlegen($neueGruppe); } catch (\Throwable $e) { View::redirect('/auswertungen', $e->getMessage(), 'fehler'); } } try { if ($id > 0 && Bericht::find($id) !== null) { Bericht::speichern($id, $name, $filter, $gruppe); } else { $id = Bericht::anlegen($name, $filter, $gruppe); } } catch (\Throwable $e) { View::redirect( '/auswertungen/bericht?' . $this->alsQuery($filter), $e->getMessage(), 'fehler' ); } View::redirect('/auswertungen/bericht/' . $id, 'Bericht „' . $name . '“ gespeichert.'); } public function loeschen(array $params): void { $this->verlangeAnmeldung(); $bericht = Bericht::find((int)$params['id']); if ($bericht === null) { View::redirect('/auswertungen', 'Diesen Bericht gibt es nicht.', 'fehler'); } Bericht::loeschen((int)$bericht['id']); View::redirect('/auswertungen', 'Bericht „' . $bericht['name'] . '“ gelöscht.'); } /** Die Buchungen hinter einer Berichtszeile. */ public function drilldown(): void { $this->verlangeAnmeldung(); $filter = $this->filterAusQuery(); $zeile = Auswertung::zeilenbuchungen( $filter, $this->query('zeile'), $this->query('spalte'), $this->query('ast') === '1' ); // Nicht „daten“ nennen: View::render() extrahiert mit EXTR_SKIP, und // eine gleichnamige lokale Variable dort bliebe unangetastet – die View // bekäme dann das gesamte Datenarray statt dieses einen Eintrags. $this->render('auswertungen/drilldown.php', [ 'titel' => $zeile['name'], 'zeile' => $zeile, 'zurueck' => $this->berichtsadresse($filter, $this->query('bericht_id')), ]); } /** Derselbe Bericht als CSV-Datei. */ public function csv(): void { $this->verlangeAnmeldung(); $filter = $this->filterAusQuery(); $bericht = Auswertung::bericht($filter); $id = (int)$this->query('bericht_id'); if ($id > 0) { $gespeichert = Bericht::find($id); if ($gespeichert !== null) { $bericht['name'] = (string)$gespeichert['name']; } } $inhalt = BerichtExport::csv($bericht); header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename="' . BerichtExport::dateiname($bericht) . '"'); header('Content-Length: ' . strlen($inhalt)); echo $inhalt; } // ── Berichtsgruppen ────────────────────────────────────────────────────── public function gruppen(): void { $this->verlangeAnmeldung(); $this->render('auswertungen/gruppen.php', [ 'titel' => 'Berichtsgruppen', 'gruppen' => Bericht::nachGruppe(), ]); } public function gruppeAnlegen(): void { $this->verlangeAnmeldung(); try { Berichtsgruppe::anlegen($this->post('name'), (int)$this->post('sortierung')); } catch (\Throwable $e) { View::redirect('/auswertungen/gruppen', $e->getMessage(), 'fehler'); } View::redirect('/auswertungen/gruppen', 'Berichtsgruppe angelegt.'); } public function gruppeSpeichern(array $params): void { $this->verlangeAnmeldung(); try { Berichtsgruppe::speichern((int)$params['id'], $this->post('name'), (int)$this->post('sortierung')); } catch (\Throwable $e) { View::redirect('/auswertungen/gruppen', $e->getMessage(), 'fehler'); } View::redirect('/auswertungen/gruppen', 'Berichtsgruppe gespeichert.'); } public function gruppeLoeschen(array $params): void { $this->verlangeAnmeldung(); Berichtsgruppe::loeschen((int)$params['id']); View::redirect('/auswertungen/gruppen', 'Berichtsgruppe gelöscht; ihre Berichte bleiben erhalten.'); } // ── Innereien ──────────────────────────────────────────────────────────── /** * Stellt die Berichtsansicht dar. * * @param array|null $gespeichert * @param array $filter */ private function zeige(?array $gespeichert, array $filter): void { $bericht = Auswertung::bericht($filter); if ($gespeichert !== null) { $bericht['name'] = (string)$gespeichert['name']; } $this->render('auswertungen/bericht.php', [ 'titel' => ($gespeichert['name'] ?? $bericht['typname']) . ($gespeichert === null ? '' : ' – ' . $bericht['typname']), 'bericht' => $bericht, 'gespeichert' => $gespeichert, 'gruppen' => Berichtsgruppe::alle(), 'konten' => Konto::alle(), 'kategorien' => Kategorie::baumFlach(), 'klassen' => Klasse::alle(), 'vorgaben' => Zeitraum::VORGABEN, 'aufteilungen' => Zeitraum::AUFTEILUNGEN, 'zeilensummen' => Auswertung::ZEILENSUMMEN, 'typen' => Auswertung::TYPEN, 'query' => $this->alsQuery($bericht['filter']), ]); } /** * Der Filter für einen gespeicherten Bericht: aus der Datenbank, sofern die * Filterleiste nicht gerade etwas anderes gesendet hat. Das Formular setzt * dazu ein Feld `angepasst` – ohne dieses Kennzeichen wäre nicht zu * unterscheiden, ob ein fehlender Parameter „nicht gesendet“ oder * „abgewählt“ bedeutet. * * @param array $gespeichert * @return array */ private function filterFuer(array $gespeichert): array { return $this->query('angepasst') === '1' ? $this->filterAusQuery() : Bericht::filter($gespeichert); } /** @return array */ private function filterAusQuery(): array { return Auswertung::normalisiere($_GET); } /** * Der Filter als Query-String – für den CSV-Link, den Drilldown und den Weg * zurück. * * @param array $filter */ private function alsQuery(array $filter): string { return http_build_query(array_map( static fn(mixed $wert): mixed => is_bool($wert) ? ($wert ? '1' : '0') : $wert, $filter + ['angepasst' => '1'] )); } /** * Zurück zum Bericht: zum gespeicherten, wenn es einen gibt, sonst zur * Vorlage mit denselben Filtern. * * @param array $filter */ private function berichtsadresse(array $filter, string $id): string { $query = $this->alsQuery($filter); return (int)$id > 0 ? '/auswertungen/bericht/' . (int)$id . '?' . $query : '/auswertungen/bericht?' . $query; } }