feat: resolve full postcodes from local DB before HTTP

This commit is contained in:
Ovidiu U
2026-04-22 12:09:19 +01:00
parent 55c81fab7b
commit 9fa9ea7835
2 changed files with 53 additions and 1 deletions

View File

@@ -2,6 +2,7 @@
namespace App\Services; namespace App\Services;
use App\Models\Postcode;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -33,7 +34,7 @@ class PostcodeService
} }
$result = match (true) { $result = match (true) {
$this->isFullPostcode($query) => $this->lookupPostcode($query), $this->isFullPostcode($query) => $this->lookupLocalPostcode($query) ?? $this->lookupPostcode($query),
$this->isOutcode($query) => $this->lookupOutcode($query), $this->isOutcode($query) => $this->lookupOutcode($query),
default => $this->lookupPlace($query), default => $this->lookupPlace($query),
}; };
@@ -55,6 +56,34 @@ class PostcodeService
return (bool) preg_match('/^[A-Z]{1,2}[0-9][0-9A-Z]?$/i', $query); return (bool) preg_match('/^[A-Z]{1,2}[0-9][0-9A-Z]?$/i', $query);
} }
private function lookupLocalPostcode(string $postcode): ?LocationResult
{
$normalised = strtoupper(preg_replace('/\s+/', '', $postcode));
$row = Postcode::find($normalised);
if ($row === null) {
return null;
}
return new LocationResult(
query: $postcode,
displayName: $this->formatPostcode($normalised),
lat: $row->lat,
lng: $row->lng,
);
}
private function formatPostcode(string $normalised): string
{
// Insert the single space before the last 3 chars ("SW1A1AA" -> "SW1A 1AA").
if (strlen($normalised) < 5) {
return $normalised;
}
return substr($normalised, 0, -3).' '.substr($normalised, -3);
}
private function lookupPostcode(string $postcode): ?LocationResult private function lookupPostcode(string $postcode): ?LocationResult
{ {
$normalised = strtoupper(preg_replace('/\s+/', '', $postcode)); $normalised = strtoupper(preg_replace('/\s+/', '', $postcode));

View File

@@ -1,5 +1,6 @@
<?php <?php
use App\Models\Postcode;
use App\Services\ApiLogger; use App\Services\ApiLogger;
use App\Services\LocationResult; use App\Services\LocationResult;
use App\Services\PostcodeService; use App\Services\PostcodeService;
@@ -171,3 +172,25 @@ it('returns null and does not throw on API failure', function (): void {
expect($result)->toBeNull(); expect($result)->toBeNull();
}); });
// --- Local DB (full postcode) ---
it('resolves a full postcode from local DB without calling HTTP', function (): void {
Postcode::create([
'postcode' => 'SW1A1AA',
'outcode' => 'SW1A',
'lat' => 51.501009,
'lng' => -0.141588,
]);
Http::fake(); // any HTTP call will be recorded
$result = $this->service->resolve('SW1A 1AA');
expect($result)->toBeInstanceOf(LocationResult::class)
->and($result->displayName)->toBe('SW1A 1AA')
->and($result->lat)->toBe(51.501009)
->and($result->lng)->toBe(-0.141588);
Http::assertNothingSent();
});