feat: resolve full postcodes from local DB before HTTP
This commit is contained in:
@@ -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));
|
||||||
|
|||||||
@@ -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();
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user