feat: DashboardService with per-source cache and stale fallback, FixtureSource

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-11 14:39:03 +02:00
co-authored by Claude Fable 5.1
parent 89e1e544c5
commit 216b6616fc
6 changed files with 471 additions and 1 deletions
+57
View File
@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Weerscherm\Tests;
use Weerscherm\WeatherSource;
/** Testdubbel: geeft per methode een array terug of gooit de ingestelde exception, en telt de aanroepen. */
final class FakeSource implements WeatherSource
{
/** @var array<string, array|\Throwable> */
public array $responses = [];
/** @var array<string, int> */
public array $calls = ['stations' => 0, 'measure' => 0, 'forecast' => 0];
/** @var array<string, array> */
public array $lastArgs = [];
public static function fromFixtures(): self
{
$s = new self();
$s->responses = [
'stations' => json_decode((string) file_get_contents(__DIR__ . '/fixtures/getstationsdata.json'), true)['body'],
'measure' => json_decode((string) file_get_contents(__DIR__ . '/fixtures/getmeasure.json'), true)['body'],
'forecast' => json_decode((string) file_get_contents(__DIR__ . '/fixtures/forecast.json'), true)['daily'],
];
return $s;
}
public function stationsData(): array
{
return $this->answer('stations', []);
}
public function measure(string $deviceId, string $moduleId, int $begin, int $end): array
{
return $this->answer('measure', func_get_args());
}
public function forecast(float $lat, float $lon, string $timezone): array
{
return $this->answer('forecast', func_get_args());
}
private function answer(string $key, array $args): array
{
$this->calls[$key]++;
$this->lastArgs[$key] = $args;
$r = $this->responses[$key] ?? new \RuntimeException("geen response voor $key");
if ($r instanceof \Throwable) {
throw $r;
}
return $r;
}
}