feat: persist postcodes.io fallback results into local DB

This commit is contained in:
Ovidiu U
2026-04-22 12:18:20 +01:00
parent 1e3b246172
commit 45bf1c0d24
2 changed files with 75 additions and 4 deletions

View File

@@ -47,6 +47,11 @@ class PostcodeService
return $result;
}
private function normalisePostcode(string $value): string
{
return strtoupper(preg_replace('/\s+/', '', $value));
}
private function isFullPostcode(string $query): bool
{
return (bool) preg_match('/^[A-Z]{1,2}[0-9][0-9A-Z]?\s*[0-9][A-Z]{2}$/i', $query);
@@ -59,7 +64,7 @@ class PostcodeService
private function lookupLocalPostcode(string $postcode): ?LocationResult
{
$normalised = strtoupper(preg_replace('/\s+/', '', $postcode));
$normalised = $this->normalisePostcode($postcode);
$row = Postcode::find($normalised);
@@ -105,7 +110,7 @@ class PostcodeService
private function lookupPostcode(string $postcode): ?LocationResult
{
$normalised = strtoupper(preg_replace('/\s+/', '', $postcode));
$normalised = $this->normalisePostcode($postcode);
$url = self::BASE_URL.'/postcodes/'.$normalised;
try {
@@ -117,12 +122,23 @@ class PostcodeService
$data = $response->json('result');
return new LocationResult(
$result = new LocationResult(
query: $postcode,
displayName: $data['postcode'],
lat: $data['latitude'],
lng: $data['longitude'],
);
Postcode::updateOrCreate(
['postcode' => $normalised],
[
'outcode' => substr($normalised, 0, strlen($normalised) - 3),
'lat' => $data['latitude'],
'lng' => $data['longitude'],
],
);
return $result;
} catch (Throwable $e) {
Log::error('PostcodeService: postcode lookup failed', [
'postcode' => $postcode,
@@ -147,12 +163,22 @@ class PostcodeService
$data = $response->json('result');
return new LocationResult(
$result = new LocationResult(
query: $outcode,
displayName: $data['outcode'],
lat: $data['latitude'],
lng: $data['longitude'],
);
Outcode::updateOrCreate(
['outcode' => $normalised],
[
'lat' => $data['latitude'],
'lng' => $data['longitude'],
],
);
return $result;
} catch (Throwable $e) {
Log::error('PostcodeService: outcode lookup failed', [
'outcode' => $outcode,

View File

@@ -216,3 +216,48 @@ it('resolves an outcode from local DB without calling HTTP', function (): void {
Http::assertNothingSent();
});
// --- HTTP fallback persistence ---
it('persists a full postcode resolved via HTTP fallback', function (): void {
Http::fake([
'*/postcodes/SW1A1AA' => Http::response([
'status' => 200,
'result' => [
'postcode' => 'SW1A 1AA',
'latitude' => 51.501009,
'longitude' => -0.141588,
],
]),
]);
$this->service->resolve('SW1A 1AA');
$row = Postcode::find('SW1A1AA');
expect($row)->not->toBeNull()
->and($row->outcode)->toBe('SW1A')
->and((float) $row->lat)->toBe(51.501009)
->and((float) $row->lng)->toBe(-0.141588);
});
it('persists an outcode resolved via HTTP fallback', function (): void {
Http::fake([
'*/outcodes/PE7' => Http::response([
'status' => 200,
'result' => [
'outcode' => 'PE7',
'latitude' => 52.536397,
'longitude' => -0.210181,
],
]),
]);
$this->service->resolve('PE7');
$row = Outcode::find('PE7');
expect($row)->not->toBeNull()
->and((float) $row->lat)->toBe(52.536397)
->and((float) $row->lng)->toBe(-0.210181);
});