From fcfbcc0b87b023239984e1e8bfcd7465e7ea955a Mon Sep 17 00:00:00 2001 From: edwh Date: Wed, 15 Jul 2026 10:02:04 +0100 Subject: [PATCH] RES-1858: switch address geocoding from Google to Mapbox The rest of the Mapbox geocoder plumbing (config/geocoder.php, the geocoder-php/mapbox-provider + toin0u/geocoder-laravel packages, and MAPBOX_TOKEN in .env/CI/Fly secrets) already landed on develop as part of other work and is already used for reverse geocoding in SetPlaceNetworkData. This just switches the remaining forward-geocode path, App\Helpers\Geocoder::geocode(), from a raw Google Maps HTTP call to the same app('geocoder') chain (Mapbox, falling back to GeoPlugin), matching that existing pattern. country_code now comes straight from the provider's ISO country code rather than matching the returned country name against our own country list, and the dead reverseGeocode() method (superseded by the reverseQuery() call already in SetPlaceNetworkData) is removed. Public interface, the Geocoder container binding, and the test mocks (GeocoderMock, GeocoderFailMock) are unchanged, so no other files need updating for this to work. This branch is rebuilt on current develop (~1240 commits ahead of where it last was) so CI can actually run; the frontend part of the original PR (replacing vue-google-autocomplete with a Mapbox GL widget) is intentionally not carried over - see PR comment. Co-Authored-By: Claude Fable 5 --- app/Helpers/Geocoder.php | 60 +++++++++++++++------------------------- 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/app/Helpers/Geocoder.php b/app/Helpers/Geocoder.php index 6dea4b0f96..1418ee935e 100644 --- a/app/Helpers/Geocoder.php +++ b/app/Helpers/Geocoder.php @@ -2,56 +2,40 @@ namespace App\Helpers; +use Geocoder\Provider\Mapbox\Mapbox; +use Geocoder\Query\GeocodeQuery; + class Geocoder { public function __construct() { } - private function googleKey() - { - // We have this so that we can change the key in testing. - return config('GOOGLE_API_CONSOLE_KEY') ?? env('GOOGLE_API_CONSOLE_KEY'); - } - public function geocode($location) { if ($location != 'ForceGeocodeFailure') { - $json = file_get_contents('https://maps.googleapis.com/maps/api/geocode/json?address='.urlencode($location).'&key='.$this->googleKey()); - - if ($json) { - $res = json_decode($json); - - if ($res && $res->results && count($res->results)) { - $decoded = json_decode($json)->results[0]; - - $latitude = $decoded->{'geometry'}->{'location'}->lat; - $longitude = $decoded->{'geometry'}->{'location'}->lng; - - foreach ($decoded->{'address_components'} as $component) { - if ($component->types && count($component->types) && $component->types[0] === 'country') { - $country_code = $component->short_name; - } - } - - return [ - 'latitude' => $latitude, - 'longitude' => $longitude, - 'country_code' => $country_code, - ]; - } + // Use the geocoder configured in config/geocoder.php - a chain of Mapbox (primary) and GeoPlugin + // (fallback), resolved via the container so tests can bind a mock Geocoder instead. This is the + // same pattern used by App\Console\Commands\SetPlaceNetworkData for reverse geocoding. + $geocodeResponse = app('geocoder')->geocodeQuery( + GeocodeQuery::create($location)->withData('location_type', [Mapbox::TYPE_PLACE, Mapbox::TYPE_ADDRESS]) + ); + $addressCollection = $geocodeResponse->get(); + $address = $addressCollection->get(0); + + if ($address && $address->getCoordinates()) { + // The provider gives us both the country name and its ISO code - use the code directly rather + // than trying to match the name against our own country list. + $country = $address->getCountry(); + + return [ + 'latitude' => $address->getCoordinates()->getLatitude(), + 'longitude' => $address->getCoordinates()->getLongitude(), + 'country_code' => $country ? $country->getCode() : null, + ]; } } return false; } - - public function reverseGeocode($lat, $lng) - { - $json = file_get_contents("https://maps.googleapis.com/maps/api/geocode/json?latlng=$lat,$lng&key=".$this->googleKey()); - - $decoded = json_decode($json)->results[0]; - - return $decoded; - } }