|
|
@@ -2,6 +2,7 @@
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
|
+use App\Models\Address;
|
|
|
use Illuminate\Http\Client\Pool;
|
|
|
use Illuminate\Http\Client\Response;
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
@@ -15,32 +16,15 @@ class ZipCodeCoordinatesService
|
|
|
|
|
|
public function resolve(?float $latitude, ?float $longitude, ?string $zipCode): ?array
|
|
|
{
|
|
|
- Log::info('ZipCodeCoordinates resolve entered', [
|
|
|
- 'has_latitude' => $latitude !== null,
|
|
|
- 'has_longitude' => $longitude !== null,
|
|
|
- 'zip_code' => $this->normalize($zipCode),
|
|
|
- ]);
|
|
|
-
|
|
|
if ($latitude !== null && $longitude !== null) {
|
|
|
- Log::info('ZipCodeCoordinates resolve using address coordinates', [
|
|
|
- 'latitude' => $latitude,
|
|
|
- 'longitude' => $longitude,
|
|
|
- 'zip_code' => $this->normalize($zipCode),
|
|
|
- ]);
|
|
|
-
|
|
|
return compact('latitude', 'longitude');
|
|
|
}
|
|
|
|
|
|
- Log::info('ZipCodeCoordinates fallback to zip code lookup', [
|
|
|
- 'zip_code' => $this->normalize($zipCode),
|
|
|
- 'has_latitude' => $latitude !== null,
|
|
|
- 'has_longitude' => $longitude !== null,
|
|
|
- 'reason' => 'missing_address_coordinates',
|
|
|
- ]);
|
|
|
-
|
|
|
return $this->findByZipCode($zipCode);
|
|
|
}
|
|
|
|
|
|
+ //
|
|
|
+
|
|
|
public function calculateDistance(
|
|
|
?float $originLatitude,
|
|
|
?float $originLongitude,
|
|
|
@@ -49,15 +33,6 @@ class ZipCodeCoordinatesService
|
|
|
?float $targetLongitude,
|
|
|
?string $targetZipCode,
|
|
|
): ?float {
|
|
|
- Log::info('ZipCodeCoordinates calculate distance requested', [
|
|
|
- 'origin_has_latitude' => $originLatitude !== null,
|
|
|
- 'origin_has_longitude' => $originLongitude !== null,
|
|
|
- 'origin_zip_code' => $this->normalize($originZipCode),
|
|
|
- 'target_has_latitude' => $targetLatitude !== null,
|
|
|
- 'target_has_longitude' => $targetLongitude !== null,
|
|
|
- 'target_zip_code' => $this->normalize($targetZipCode),
|
|
|
- ]);
|
|
|
-
|
|
|
$origin = $this->resolve($originLatitude, $originLongitude, $originZipCode);
|
|
|
$target = $this->resolve($targetLatitude, $targetLongitude, $targetZipCode);
|
|
|
|
|
|
@@ -68,12 +43,6 @@ class ZipCodeCoordinatesService
|
|
|
$target['longitude'] ?? null,
|
|
|
);
|
|
|
|
|
|
- Log::info('ZipCodeCoordinates calculate distance result', [
|
|
|
- 'origin_found' => $origin !== null,
|
|
|
- 'target_found' => $target !== null,
|
|
|
- 'distance_km' => $distance,
|
|
|
- ]);
|
|
|
-
|
|
|
return $distance;
|
|
|
}
|
|
|
|
|
|
@@ -82,40 +51,21 @@ class ZipCodeCoordinatesService
|
|
|
$zipCode = $this->normalize($zipCode);
|
|
|
|
|
|
if ($zipCode === null) {
|
|
|
- Log::info('ZipCodeCoordinates skipped lookup: invalid zip code');
|
|
|
-
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
if (array_key_exists($zipCode, $this->resolvedZipCodes)) {
|
|
|
- Log::info('ZipCodeCoordinates memory cache hit', [
|
|
|
- 'zip_code' => $zipCode,
|
|
|
- 'found' => $this->resolvedZipCodes[$zipCode] !== null,
|
|
|
- ]);
|
|
|
-
|
|
|
return $this->resolvedZipCodes[$zipCode];
|
|
|
}
|
|
|
|
|
|
if ($this->restoreFromCache($zipCode)) {
|
|
|
- Log::info('ZipCodeCoordinates persistent cache hit', [
|
|
|
- 'zip_code' => $zipCode,
|
|
|
- 'found' => $this->resolvedZipCodes[$zipCode] !== null,
|
|
|
- ]);
|
|
|
-
|
|
|
return $this->resolvedZipCodes[$zipCode];
|
|
|
}
|
|
|
|
|
|
if (! $this->googleGeocodingIsConfigured()) {
|
|
|
- Log::warning('ZipCodeCoordinates Google Geocoding skipped: API key is not configured');
|
|
|
-
|
|
|
return $this->resolvedZipCodes[$zipCode] = null;
|
|
|
}
|
|
|
|
|
|
- Log::info('ZipCodeCoordinates Google Geocoding lookup required', [
|
|
|
- 'zip_code' => $zipCode,
|
|
|
- 'mode' => 'single',
|
|
|
- ]);
|
|
|
-
|
|
|
$coordinates = $this->requestCoordinates($zipCode);
|
|
|
|
|
|
$this->remember($zipCode, $coordinates);
|
|
|
@@ -142,16 +92,10 @@ class ZipCodeCoordinatesService
|
|
|
}
|
|
|
|
|
|
if ($pending === []) {
|
|
|
- Log::info('ZipCodeCoordinates preload skipped: no pending zip codes');
|
|
|
-
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (! $this->googleGeocodingIsConfigured()) {
|
|
|
- Log::warning('ZipCodeCoordinates Google Geocoding preload skipped: API key is not configured', [
|
|
|
- 'pending_count' => count($pending),
|
|
|
- ]);
|
|
|
-
|
|
|
foreach ($pending as $zipCode) {
|
|
|
$this->resolvedZipCodes[$zipCode] = null;
|
|
|
}
|
|
|
@@ -159,7 +103,7 @@ class ZipCodeCoordinatesService
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- Log::info('ZipCodeCoordinates Google Geocoding lookup required', [
|
|
|
+ Log::channel('google_geocoding')->info('ZipCodeCoordinates Google Geocoding lookup required', [
|
|
|
'mode' => 'preload',
|
|
|
'pending_count' => count($pending),
|
|
|
'zip_codes_sample' => array_slice(array_values($pending), 0, 20),
|
|
|
@@ -170,6 +114,7 @@ class ZipCodeCoordinatesService
|
|
|
|
|
|
try {
|
|
|
$baseUrl = rtrim((string) config('services.google_geocoding.base_url'), '/');
|
|
|
+
|
|
|
$startedAt = microtime(true);
|
|
|
|
|
|
$responses = Http::pool(fn (Pool $pool) => array_map(
|
|
|
@@ -183,7 +128,7 @@ class ZipCodeCoordinatesService
|
|
|
$pending,
|
|
|
));
|
|
|
} catch (Throwable $exception) {
|
|
|
- Log::warning('ZipCodeCoordinates Google Geocoding preload failed', [
|
|
|
+ Log::channel('google_geocoding')->warning('ZipCodeCoordinates Google Geocoding preload failed', [
|
|
|
'pending_count' => count($pending),
|
|
|
'elapsed_ms' => isset($startedAt) ? round((microtime(true) - $startedAt) * 1000, 2) : null,
|
|
|
'error' => $exception->getMessage(),
|
|
|
@@ -199,18 +144,6 @@ class ZipCodeCoordinatesService
|
|
|
? $this->coordinatesFromResponse($response)
|
|
|
: null;
|
|
|
|
|
|
- Log::info('ZipCodeCoordinates Google Geocoding preload response', [
|
|
|
- 'zip_code' => $zipCode,
|
|
|
- 'has_response' => $response instanceof Response,
|
|
|
- 'status' => $response instanceof Response ? $response->status() : null,
|
|
|
- 'elapsed_ms' => isset($startedAt) ? round((microtime(true) - $startedAt) * 1000, 2) : null,
|
|
|
- 'found' => $coordinates !== null,
|
|
|
- 'coordinates' => $coordinates,
|
|
|
- 'body' => $coordinates === null && $response instanceof Response
|
|
|
- ? $response->json()
|
|
|
- : null,
|
|
|
- ]);
|
|
|
-
|
|
|
$this->remember($zipCode, $coordinates);
|
|
|
}
|
|
|
}
|
|
|
@@ -279,15 +212,27 @@ class ZipCodeCoordinatesService
|
|
|
return strlen($zipCode) === 8 ? $zipCode : null;
|
|
|
}
|
|
|
|
|
|
+ private function persistProviderCoordinates(string $zipCode, array $coordinates): void
|
|
|
+ {
|
|
|
+ $formattedZipCode = substr($zipCode, 0, 5).'-'.substr($zipCode, 5);
|
|
|
+
|
|
|
+ Address::query()
|
|
|
+ ->where('source', 'provider')
|
|
|
+ ->whereIn('zip_code', [$zipCode, $formattedZipCode])
|
|
|
+ ->where(function ($query) {
|
|
|
+ $query->whereNull('latitude')->orWhereNull('longitude');
|
|
|
+ })
|
|
|
+ ->update([
|
|
|
+ 'latitude' => $coordinates['latitude'],
|
|
|
+ 'longitude' => $coordinates['longitude'],
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
private function remember(string $zipCode, ?array $coordinates): void
|
|
|
{
|
|
|
$this->resolvedZipCodes[$zipCode] = $coordinates;
|
|
|
|
|
|
if ($coordinates === null) {
|
|
|
- Log::info('ZipCodeCoordinates failure not cached', [
|
|
|
- 'zip_code' => $zipCode,
|
|
|
- ]);
|
|
|
-
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -301,6 +246,8 @@ class ZipCodeCoordinatesService
|
|
|
(int) config('services.google_geocoding.cache_ttl', 2592000)
|
|
|
)
|
|
|
);
|
|
|
+
|
|
|
+ $this->persistProviderCoordinates($zipCode, $coordinates);
|
|
|
}
|
|
|
|
|
|
private function requestCoordinates(string $zipCode): ?array
|
|
|
@@ -308,7 +255,7 @@ class ZipCodeCoordinatesService
|
|
|
$startedAt = microtime(true);
|
|
|
|
|
|
try {
|
|
|
- Log::info('ZipCodeCoordinates calling Google Geocoding', [
|
|
|
+ Log::channel('google_geocoding')->info('ZipCodeCoordinates calling Google Geocoding', [
|
|
|
'zip_code' => $zipCode,
|
|
|
'base_url' => rtrim((string) config('services.google_geocoding.base_url'), '/'),
|
|
|
'connect_timeout' => (int) config('services.google_geocoding.connect_timeout', 2),
|
|
|
@@ -324,20 +271,9 @@ class ZipCodeCoordinatesService
|
|
|
->timeout((int) config('services.google_geocoding.timeout', 5))
|
|
|
->get("{$baseUrl}/maps/api/geocode/json", $this->googleQuery($zipCode));
|
|
|
|
|
|
- $coordinates = $this->coordinatesFromResponse($response);
|
|
|
-
|
|
|
- Log::info('ZipCodeCoordinates Google Geocoding response', [
|
|
|
- 'zip_code' => $zipCode,
|
|
|
- 'status' => $response->status(),
|
|
|
- 'elapsed_ms' => round((microtime(true) - $startedAt) * 1000, 2),
|
|
|
- 'found' => $coordinates !== null,
|
|
|
- 'coordinates' => $coordinates,
|
|
|
- 'body' => $coordinates === null ? $response->json() : null,
|
|
|
- ]);
|
|
|
-
|
|
|
- return $coordinates;
|
|
|
+ return $this->coordinatesFromResponse($response);
|
|
|
} catch (Throwable $exception) {
|
|
|
- Log::warning('ZipCodeCoordinates Google Geocoding request failed', [
|
|
|
+ Log::channel('google_geocoding')->warning('ZipCodeCoordinates Google Geocoding request failed', [
|
|
|
'zip_code' => $zipCode,
|
|
|
'elapsed_ms' => round((microtime(true) - $startedAt) * 1000, 2),
|
|
|
'error' => $exception->getMessage(),
|
|
|
@@ -360,11 +296,6 @@ class ZipCodeCoordinatesService
|
|
|
if (! $cached['found']) {
|
|
|
Cache::forget($cacheKey);
|
|
|
|
|
|
- Log::info('ZipCodeCoordinates negative cache ignored', [
|
|
|
- 'zip_code' => $zipCode,
|
|
|
- 'reason' => 'retry_lookup_after_previous_failure',
|
|
|
- ]);
|
|
|
-
|
|
|
return false;
|
|
|
}
|
|
|
|