feat: persist postcodes.io fallback results into local DB
This commit is contained in:
@@ -47,6 +47,11 @@ class PostcodeService
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function normalisePostcode(string $value): string
|
||||||
|
{
|
||||||
|
return strtoupper(preg_replace('/\s+/', '', $value));
|
||||||
|
}
|
||||||
|
|
||||||
private function isFullPostcode(string $query): bool
|
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);
|
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
|
private function lookupLocalPostcode(string $postcode): ?LocationResult
|
||||||
{
|
{
|
||||||
$normalised = strtoupper(preg_replace('/\s+/', '', $postcode));
|
$normalised = $this->normalisePostcode($postcode);
|
||||||
|
|
||||||
$row = Postcode::find($normalised);
|
$row = Postcode::find($normalised);
|
||||||
|
|
||||||
@@ -105,7 +110,7 @@ class PostcodeService
|
|||||||
|
|
||||||
private function lookupPostcode(string $postcode): ?LocationResult
|
private function lookupPostcode(string $postcode): ?LocationResult
|
||||||
{
|
{
|
||||||
$normalised = strtoupper(preg_replace('/\s+/', '', $postcode));
|
$normalised = $this->normalisePostcode($postcode);
|
||||||
$url = self::BASE_URL.'/postcodes/'.$normalised;
|
$url = self::BASE_URL.'/postcodes/'.$normalised;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -117,12 +122,23 @@ class PostcodeService
|
|||||||
|
|
||||||
$data = $response->json('result');
|
$data = $response->json('result');
|
||||||
|
|
||||||
return new LocationResult(
|
$result = new LocationResult(
|
||||||
query: $postcode,
|
query: $postcode,
|
||||||
displayName: $data['postcode'],
|
displayName: $data['postcode'],
|
||||||
lat: $data['latitude'],
|
lat: $data['latitude'],
|
||||||
lng: $data['longitude'],
|
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) {
|
} catch (Throwable $e) {
|
||||||
Log::error('PostcodeService: postcode lookup failed', [
|
Log::error('PostcodeService: postcode lookup failed', [
|
||||||
'postcode' => $postcode,
|
'postcode' => $postcode,
|
||||||
@@ -147,12 +163,22 @@ class PostcodeService
|
|||||||
|
|
||||||
$data = $response->json('result');
|
$data = $response->json('result');
|
||||||
|
|
||||||
return new LocationResult(
|
$result = new LocationResult(
|
||||||
query: $outcode,
|
query: $outcode,
|
||||||
displayName: $data['outcode'],
|
displayName: $data['outcode'],
|
||||||
lat: $data['latitude'],
|
lat: $data['latitude'],
|
||||||
lng: $data['longitude'],
|
lng: $data['longitude'],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Outcode::updateOrCreate(
|
||||||
|
['outcode' => $normalised],
|
||||||
|
[
|
||||||
|
'lat' => $data['latitude'],
|
||||||
|
'lng' => $data['longitude'],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return $result;
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
Log::error('PostcodeService: outcode lookup failed', [
|
Log::error('PostcodeService: outcode lookup failed', [
|
||||||
'outcode' => $outcode,
|
'outcode' => $outcode,
|
||||||
|
|||||||
@@ -216,3 +216,48 @@ it('resolves an outcode from local DB without calling HTTP', function (): void {
|
|||||||
|
|
||||||
Http::assertNothingSent();
|
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);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user