Quelltext des aktuellen Standes
<?php
declare(strict_types=1);
/**
* Deckt die Darstellung mehrtägiger Wartungstermine ab.
*
* Ein Termin über mehrere Tage gehört an jeden Tag seines Zeitraums, nicht nur
* an seinen Beginn. Das betrifft zwei Stellen: die Abfrage muss ihn finden,
* sobald er den angezeigten Monat berührt, und das Raster muss ihn auf alle
* Tage verteilen.
*/
return static function (): void {
/**
* Bildet die Zuordnung des Kalenders nach: Termin auf Tage verteilen,
* begrenzt auf den angezeigten Monat.
*
* @param array<string,?string> $termin
* @return array<string,string> Tag => Lage im Zeitraum
*/
$verteilen = static function (array $termin, int $jahr, int $monat): array {
$von = (string)$termin['date'];
$bis = !empty($termin['end_date']) ? (string)$termin['end_date'] : $von;
if ($bis < $von) {
$bis = $von;
}
$tag = max($von, sprintf('%04d-%02d-01', $jahr, $monat));
$ende = min($bis, date('Y-m-t', mktime(0, 0, 0, $monat, 1, $jahr)));
$karte = [];
while ($tag <= $ende) {
$karte[$tag] = $von === $bis
? 'single'
: ($tag === $von ? 'start' : ($tag === $bis ? 'end' : 'middle'));
$tag = date('Y-m-d', strtotime($tag . ' +1 day'));
}
return $karte;
};
// ----------------------------------------------------------------
// Verteilung auf die Tage
// ----------------------------------------------------------------
test('Ein eintägiger Termin belegt genau seinen Tag', function () use ($verteilen) {
$karte = $verteilen(['date' => '2026-09-10', 'end_date' => null], 2026, 9);
assertSame(['2026-09-10' => 'single'], $karte);
});
test('Ein Enddatum gleich dem Startdatum bleibt eintägig', function () use ($verteilen) {
$karte = $verteilen(['date' => '2026-09-10', 'end_date' => '2026-09-10'], 2026, 9);
assertSame(['2026-09-10' => 'single'], $karte);
});
test('Ein mehrtägiger Termin belegt jeden Tag dazwischen', function () use ($verteilen) {
$karte = $verteilen(['date' => '2026-09-08', 'end_date' => '2026-09-11'], 2026, 9);
assertSame(
['2026-09-08', '2026-09-09', '2026-09-10', '2026-09-11'],
array_keys($karte)
);
assertSame(['start', 'middle', 'middle', 'end'], array_values($karte));
});
test('Ein Termin über den Monatswechsel wird auf den Monat beschnitten', function () use ($verteilen) {
// Beginn im August, Ende im September: Der September zeigt seinen Teil.
$karte = $verteilen(['date' => '2026-08-30', 'end_date' => '2026-09-02'], 2026, 9);
assertSame(['2026-09-01', '2026-09-02'], array_keys($karte));
// Der Beginn liegt außerhalb – der letzte Tag bleibt trotzdem das Ende.
assertSame('middle', $karte['2026-09-01']);
assertSame('end', $karte['2026-09-02']);
});
test('Derselbe Termin erscheint auch im Vormonat', function () use ($verteilen) {
$karte = $verteilen(['date' => '2026-08-30', 'end_date' => '2026-09-02'], 2026, 8);
assertSame(['2026-08-30', '2026-08-31'], array_keys($karte));
assertSame('start', $karte['2026-08-30']);
});
test('Ein verdrehtes Enddatum erzeugt keinen leeren oder endlosen Zeitraum', function () use ($verteilen) {
$karte = $verteilen(['date' => '2026-09-10', 'end_date' => '2026-09-01'], 2026, 9);
assertSame(['2026-09-10' => 'single'], $karte);
});
test('Ein Termin außerhalb des Monats belegt keinen Tag', function () use ($verteilen) {
assertSame([], $verteilen(['date' => '2026-07-01', 'end_date' => '2026-07-05'], 2026, 9));
});
// ----------------------------------------------------------------
// Abfrage
// ----------------------------------------------------------------
test('Die Abfrage findet Termine, die den Zeitraum nur berühren', function () {
// Ein im Vormonat begonnener Termin fällt sonst ganz aus der Ansicht.
$src = (string)file_get_contents(dirname(__DIR__) . '/src/Controllers/MaintenanceController.php');
assertTrue(
str_contains($src, 'AND event_date <= ?')
&& str_contains($src, 'AND COALESCE(end_date, event_date) >= ?'),
'Die Abfrage prüft keine Überschneidung mit dem Zeitraum'
);
assertFalse(
str_contains($src, 'source = ? AND event_date BETWEEN ? AND ?'),
'Die alte, auf den Starttag begrenzte Bedingung ist noch vorhanden'
);
});
// ----------------------------------------------------------------
// Darstellung
// ----------------------------------------------------------------
test('Das Raster zeichnet den Zeitraum als durchgehenden Balken', function () {
$tpl = (string)file_get_contents(dirname(__DIR__) . '/templates/maintenance/index.php');
foreach (['mc-event-pill--start', 'mc-event-pill--middle', 'mc-event-pill--end'] as $klasse) {
assertTrue(str_contains($tpl, '.' . $klasse), 'Kein Stil für ' . $klasse);
}
assertTrue(str_contains($tpl, "\$ev['span']"), 'Die Lage im Zeitraum wird nicht ausgewertet');
});
test('Ein bereits laufender Termin wird nicht mit negativen Tagen ausgewiesen', function () {
$tpl = (string)file_get_contents(dirname(__DIR__) . '/templates/maintenance/index.php');
assertTrue(str_contains($tpl, "\$dl < 0"), 'Der laufende Fall wird nicht unterschieden');
assertTrue(str_contains($tpl, "'läuft'"), 'Für laufende Termine fehlt die Beschriftung');
});
};