diff --git a/src/DashboardService.php b/src/DashboardService.php index 0032b69..6df5f62 100644 --- a/src/DashboardService.php +++ b/src/DashboardService.php @@ -123,11 +123,18 @@ final class DashboardService return ['days' => [], 'stale' => true]; } $result = $this->fetch('forecast', fn() => $this->source->forecast($lat, $lon, $tz->getName()), self::ERR_FORECAST); - if ($result['data'] === null) { - return ['days' => [], 'stale' => $result['stale']]; + $daily = is_array($result['data']['daily'] ?? null) ? $result['data']['daily'] : null; + if ($daily === null) { + // Data ontbreekt (echte storing, al gemeld door fetch()), of de cache staat nog in een ouder + // formaat na een deploy dat de opgeslagen vorm wijzigde. In beide gevallen liever zichtbaar + // niets tonen dan stil een lege verwachting zonder foutmelding. + if ($result['data'] !== null) { + $this->addError(self::ERR_FORECAST); + } + return ['days' => [], 'stale' => true]; } - $days = ForecastMapper::map($result['data']['daily'] ?? []); + $days = ForecastMapper::map($daily); $hourlyByDate = HourlyForecastMapper::mapByDate($result['data']['hourly'] ?? [], $tz); foreach ($days as &$day) { $day['hourly'] = $hourlyByDate[$day['date']] ?? []; diff --git a/tests/DashboardServiceTest.php b/tests/DashboardServiceTest.php index 0b05402..a562ab3 100644 --- a/tests/DashboardServiceTest.php +++ b/tests/DashboardServiceTest.php @@ -182,6 +182,22 @@ final class DashboardServiceTest extends TestCase self::assertSame(16.4, $p['outdoor']['temp']); } + public function testLegacyCachedForecastShapeIsTreatedAsUnavailableNotSilentlyEmpty(): void + { + // Vóór 2026-09-13 cachete DashboardService het platte "daily"-blok direct onder de sleutel + // "forecast". Na de uitbreiding met uurdata verwacht de code {daily, hourly}. Een nog niet + // verlopen cache in het oude formaat mag niet stil een lege verwachting zonder foutmelding geven. + $legacyDailyOnly = json_decode((string) file_get_contents(__DIR__ . '/fixtures/forecast.json'), true)['daily']; + (new Cache($this->dir))->write('forecast', $legacyDailyOnly, (new \DateTimeImmutable('2026-09-11 12:30:00 UTC'))->getTimestamp()); + + $p = $this->service()->build(); + + self::assertSame([], $p['forecast']); + self::assertTrue($p['forecast_stale']); + self::assertSame(['forecast_unavailable'], $p['errors']); + self::assertSame(0, $this->source->calls['forecast'], 'de cache was nog vers, dus geen live call verwacht'); + } + public function testSecondBuildWithinTtlUsesCache(): void { $this->service()->build();