diff --git a/app/components/stadionzeitung-cards.php b/app/components/stadionzeitung-cards.php index 215fa17..fb0fcee 100644 --- a/app/components/stadionzeitung-cards.php +++ b/app/components/stadionzeitung-cards.php @@ -31,7 +31,7 @@ $issues = $issues ?? [];
-

Stadionzeitung zum Heimspiel gegen

+

Stadionzeitung zum Heimspiel gegen

· Seiten diff --git a/app/components/stadionzeitung-cover.php b/app/components/stadionzeitung-cover.php index ffd2c14..1318ec8 100644 --- a/app/components/stadionzeitung-cover.php +++ b/app/components/stadionzeitung-cover.php @@ -32,7 +32,7 @@ declare(strict_types=1); * der Gegner läuft über den Initialen-Fallback der crest-Komponente. */ $issue = $issue ?? []; -$opponent = (string) ($issue['opponent'] ?? ''); +$opponent = stadionzeitung_opponent_display($issue); $date = (string) ($issue['date'] ?? ''); $teamKey = (string) ($issue['team_key'] ?? ''); $playerImage = $issue['player_image'] ?? null; diff --git a/app/components/stadionzeitung-viewer.php b/app/components/stadionzeitung-viewer.php index df4a7b1..814621a 100644 --- a/app/components/stadionzeitung-viewer.php +++ b/app/components/stadionzeitung-viewer.php @@ -26,7 +26,7 @@ $total = count($images); if ($images === []) { return; } -$opponent = (string) ($issue['opponent'] ?? ''); +$opponent = stadionzeitung_opponent_display($issue); // Live-Daten nur laden, wenn die Ausgabe tatsächlich eine Live-Seite enthält. $hasLive = false; diff --git a/app/helpers.php b/app/helpers.php index d404e07..6b0f6ed 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -992,6 +992,22 @@ function stadionzeitung_teaser(array $issue): string return trim((string) ($issue['interview']['teaser'] ?? '')); } +/** + * Der Name des Gegners, wie er GEDRUCKT wird — Cover, Archivzeile, Kopf, Meta. + * + * `opponent` muss die BFV-Schreibweise tragen, weil die Gegnerseite damit ihre + * Tabellenzeile und ihre Begegnung in matchcenter.json findet (exakter + * Namensvergleich). Bei Spielgemeinschaften ist das eine Zeile wie + * „(SG1) TSV Wirsberg I/ FC Kupferberg I", die auf einem Cover nichts zu + * suchen hat. `opponent_short` ist deshalb der im Chat gepflegte Anzeigename + * („Wirsberg/Kupferberg"); fehlt er, bleibt es beim vollen Namen. + */ +function stadionzeitung_opponent_display(array $issue): string +{ + $short = trim((string) ($issue['opponent_short'] ?? '')); + return $short !== '' ? $short : trim((string) ($issue['opponent'] ?? '')); +} + /** * Welche Mannschaften bekommen in einer Ausgabe eine Gegnerseite — die EINE * Logik dafür, benutzt von bin/stadionzeitung-add.php (Seitenplanung) UND @@ -999,10 +1015,19 @@ function stadionzeitung_teaser(array $issue): string * oder Daten ohne Seite entstehen. * * Immer: die tragende Mannschaft (Gegner = `opponent`, Tag = `date`). - * Zusätzlich, wenn die Ausgabe eine `veranstaltung` (Slug) mit Zeitraum trägt - * (Sportfest-Ausgabe): jede weitere Mannschaft aus matchcenter.json mit einem - * HEIMspiel in diesem Zeitraum — drei Heimspiele am Fest, drei Gegnerseiten. - * Der Gegner ist dann der andere Verein der Begegnung. Reihenfolge wie in + * Zusätzlich auf zwei Wegen, die sich nicht in die Quere kommen: + * + * 1. `veranstaltung` (Slug) mit Zeitraum — die Sportfest-Ausgabe: jede weitere + * Mannschaft aus matchcenter.json mit einem HEIMspiel in diesem Zeitraum. + * Am Fest spielen alle zuhause, das ist der Aufhänger. + * 2. `gegner_teams` (Liste von Team-Keys, im Chat gepflegt) — für ein normales + * Spielwochenende, an dem auch die anderen Mannschaften antreten. Genommen + * wird ihr nächstes Spiel im Fenster von zwei Tagen vor bis drei Tage nach + * dem Ausgabedatum, AUCH auswärts: der Gegner der Frauen ist auch dann eine + * Seite wert, wenn wir zu ihm fahren. Ohne Spiel in diesem Fenster entsteht + * keine Seite; bin/stadionzeitung-add.php meldet das. + * + * Der Gegner ist jeweils der andere Verein der Begegnung. Reihenfolge wie in * matchcenter.json (= config 'matchcenter.teams'). * * Rückgabe: [team_key => ['opponent' => string, 'date' => 'YYYY-MM-DD']] @@ -1013,14 +1038,19 @@ function stadionzeitung_gegner_fixtures(array $issue): array $issueTeam = (string) ($issue['team_key'] ?? ''); $issueOpponent = trim((string) ($issue['opponent'] ?? '')); - $von = ''; - $bis = ''; + $eventVon = ''; + $eventBis = ''; $veranstaltung = veranstaltung_find((string) ($issue['veranstaltung'] ?? '')); if ($veranstaltung !== null) { - $von = (string) ($veranstaltung['date_start'] ?? ''); - $bis = (string) ($veranstaltung['date_end'] ?? $von); + $eventVon = (string) ($veranstaltung['date_start'] ?? ''); + $eventBis = (string) ($veranstaltung['date_end'] ?? $eventVon); } + $extraTeams = array_values(array_filter(array_map( + static fn ($k): string => trim((string) $k), + is_array($issue['gegner_teams'] ?? null) ? $issue['gegner_teams'] : [] + ))); + $fixtures = []; foreach (json_load('matchcenter')['teams'] ?? [] as $team) { $key = (string) ($team['key'] ?? ''); @@ -1033,18 +1063,32 @@ function stadionzeitung_gegner_fixtures(array $issue): array } continue; } + + // Weg 2: ausdrücklich benannte Mannschaft, Fenster ums Ausgabedatum, + // Heim wie auswärts. Steht sie in `gegner_teams`, gilt dieses Fenster + // und nicht der Veranstaltungszeitraum. + if (in_array($key, $extraTeams, true) && $date !== '') { + $von = date('Y-m-d', strtotime($date . ' -2 days')); + $bis = date('Y-m-d', strtotime($date . ' +3 days')); + $nurHeim = false; + } else { + $von = $eventVon; + $bis = $eventBis; + $nurHeim = true; + } if ($von === '') { continue; } foreach ($team['next_matches'] ?? [] as $match) { - if (empty($match['is_home'])) { + $istHeim = !empty($match['is_home']); + if ($nurHeim && !$istHeim) { continue; } $matchDate = substr((string) ($match['kickoff'] ?? ''), 0, 10); if ($matchDate < $von || $matchDate > $bis) { continue; } - $opponent = trim((string) ($match['away'] ?? '')); + $opponent = trim((string) ($istHeim ? ($match['away'] ?? '') : ($match['home'] ?? ''))); if ($opponent === '' || $opponent === 'SPIELFREI') { continue; } @@ -1140,14 +1184,53 @@ function stadionzeitung_build_snapshot(array $issue): array } } + // `opponent` behält die BFV-Schreibweise (der Namensvergleich oben + // hängt daran), gedruckt wird `opponent_display`: bei der tragenden + // Mannschaft der Kurzname der Ausgabe, sonst der volle Name. + $gegnerDisplay = strcasecmp($gegnerName, trim((string) ($issue['opponent'] ?? ''))) === 0 + ? stadionzeitung_opponent_display($issue) + : $gegnerName; + + // Tabellenausschnitt statt zweier loser Platz-Ziffern im Kopf: ein + // Fenster um beide Mannschaften herum (mit einer Zeile Luft davor + // und dahinter). Liegen sie weit auseinander, werden es zwei + // Blöcke — gerendert wird beides mit der geteilten + // league-table-Komponente, nie mit einer zweiten Tabelle. + $ausschnitt = []; + if ($ownRow !== null && $opponentRow !== null && $table !== []) { + $ranks = [(int) ($ownRow['rank'] ?? 0), (int) ($opponentRow['rank'] ?? 0)]; + sort($ranks); + $fenster = static function (int $von, int $bis) use ($table): array { + return array_values(array_filter($table, static function (array $row) use ($von, $bis): bool { + $rank = (int) ($row['rank'] ?? 0); + return $rank >= $von && $rank <= $bis; + })); + }; + if ($ranks[1] - $ranks[0] <= 5) { + $block = $fenster($ranks[0], $ranks[1]); + if ($block !== []) { + $ausschnitt[] = $block; + } + } else { + foreach ($ranks as $rank) { + $block = $fenster($rank, $rank + 1); + if ($block !== []) { + $ausschnitt[] = $block; + } + } + } + } + $gegner[$key] = [ 'team_name' => (string) ($team['name'] ?? ''), 'opponent' => $gegnerName, + 'opponent_display' => $gegnerDisplay, 'league' => (string) ($team['league'] ?? ''), 'season' => (string) ($team['season'] ?? ''), 'fixture' => $fixture, 'own' => $ownRow, 'opponent_stats' => $opponentRow, + 'table_excerpt' => $ausschnitt, ]; } diff --git a/app/pages/stadionzeitung-ausgabe.php b/app/pages/stadionzeitung-ausgabe.php index 23837c8..bea6f52 100644 --- a/app/pages/stadionzeitung-ausgabe.php +++ b/app/pages/stadionzeitung-ausgabe.php @@ -78,14 +78,14 @@ $firstImage = $issue['images'][0] ?? null; $cover = ($firstImage !== null && ($firstImage['type'] ?? 'image') === 'image') ? $firstImage : null; $meta = [ - 'title' => 'Stadionzeitung gegen ' . $issue['opponent'] . ($isDruck ? ' (Druckfassung)' : ''), - 'description' => 'Stadionzeitung zum Heimspiel gegen ' . $issue['opponent'] . ' am ' . german_date($issue['date']) . ' – digital zum Durchblättern.', + 'title' => 'Stadionzeitung gegen ' . stadionzeitung_opponent_display($issue) . ($isDruck ? ' (Druckfassung)' : ''), + 'description' => 'Stadionzeitung zum Heimspiel gegen ' . stadionzeitung_opponent_display($issue) . ' am ' . german_date($issue['date']) . ' – digital zum Durchblättern.', 'scripts' => [$isDruck ? 'stadionzeitung-druck.js' : 'stadionzeitung-viewer.js'], 'schema' => page_schema([ ['name' => 'Startseite', 'slug' => ''], ['name' => 'Fußball', 'slug' => 'fussball'], ['name' => 'Stadionzeitung', 'slug' => 'stadionzeitung'], - ['name' => 'Gegen ' . $issue['opponent'], 'slug' => 'stadionzeitung/' . $issue['slug']], + ['name' => 'Gegen ' . stadionzeitung_opponent_display($issue), 'slug' => 'stadionzeitung/' . $issue['slug']], ]), ]; if ($cover !== null) { @@ -113,7 +113,7 @@ $druckBlaetter = (int) ceil($druckSeiten / 4); -

Gegen

+

Gegen