Guard added for ArcGIS api key; ArcGIS issues in LocationController and Geocoder fixed
This commit is contained in:
parent
07399d7d45
commit
5563826a08
@ -4,6 +4,7 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Services\Location\Geocoder;
|
use App\Services\Location\Geocoder;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class LocationController extends Controller
|
class LocationController extends Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,11 +4,14 @@ namespace App\Services\Location;
|
|||||||
|
|
||||||
use \App\Models\User;
|
use \App\Models\User;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
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;
|
||||||
|
|
||||||
class Geocoder
|
class Geocoder
|
||||||
{
|
{
|
||||||
|
private bool $missingKeyWarned = false;
|
||||||
|
|
||||||
public function __construct(private array $cfg = [])
|
public function __construct(private array $cfg = [])
|
||||||
{
|
{
|
||||||
$this->cfg = config("services.geocoding");
|
$this->cfg = config("services.geocoding");
|
||||||
@ -65,6 +68,31 @@ class Geocoder
|
|||||||
return rtrim($this->cfg["arcgis"]["endpoint"], "/");
|
return rtrim($this->cfg["arcgis"]["endpoint"], "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fetch arcgis api key (log once if missing)
|
||||||
|
*/
|
||||||
|
private function arcgisKey(): ?string
|
||||||
|
{
|
||||||
|
$key = $this->cfg['arcgis']['api_key'] ?? null;
|
||||||
|
|
||||||
|
if (!$key) {
|
||||||
|
$this->warnMissingKey();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function warnMissingKey(): void
|
||||||
|
{
|
||||||
|
if ($this->missingKeyWarned) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->missingKeyWarned = true;
|
||||||
|
Log::warning('arcgis api key missing; geocoding disabled');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pull a bias from the user (zip -> centroid) and cache it
|
* pull a bias from the user (zip -> centroid) and cache it
|
||||||
*/
|
*/
|
||||||
@ -85,8 +113,13 @@ class Geocoder
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$key = $this->arcgisKey();
|
||||||
|
if (!$key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$cacheKey = "geo:bias:zip:{$zip}";
|
$cacheKey = "geo:bias:zip:{$zip}";
|
||||||
$bias = Cache::remember($cacheKey, now()->addDays(7), function () use ($zip) {
|
$bias = Cache::remember($cacheKey, now()->addDays(7), function () use ($zip, $key) {
|
||||||
$a = $this->cfg['arcgis'];
|
$a = $this->cfg['arcgis'];
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
@ -94,7 +127,7 @@ class Geocoder
|
|||||||
'category' => 'Postal',
|
'category' => 'Postal',
|
||||||
'maxLocations' => 1,
|
'maxLocations' => 1,
|
||||||
'f' => 'pjson',
|
'f' => 'pjson',
|
||||||
'token' => $a['api_key'],
|
'token' => $key,
|
||||||
'countryCode' => $a['country_code'] ?? null,
|
'countryCode' => $a['country_code'] ?? null,
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -139,17 +172,25 @@ class Geocoder
|
|||||||
private function forwardArcgis(string $query, ?array $bias): ?array
|
private function forwardArcgis(string $query, ?array $bias): ?array
|
||||||
{
|
{
|
||||||
$a = $this->cfg['arcgis'];
|
$a = $this->cfg['arcgis'];
|
||||||
|
$key = $this->arcgisKey();
|
||||||
|
if (!$key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
'singleLine' => $query,
|
'singleLine' => $query,
|
||||||
'outFields' => $a['out_fields'] ?? '*',
|
'outFields' => $a['out_fields'] ?? '*',
|
||||||
'maxLocations' => (int)($a['max_results'] ?? 5),
|
'maxLocations' => (int)($a['max_results'] ?? 5),
|
||||||
'f' => 'pjson',
|
'f' => 'pjson',
|
||||||
'token' => $a['api_key'],
|
'token' => $key,
|
||||||
'category' => $a['categories'] ?? 'POI,Address',
|
'category' => $a['categories'] ?? 'POI,Address',
|
||||||
'countryCode' => $a['country_code'] ?? null,
|
'countryCode' => $a['country_code'] ?? null,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (!empty($a['store'])) {
|
||||||
|
$params['forStorage'] = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
if ($bias && $bias['lat'] && $bias['lon']) {
|
if ($bias && $bias['lat'] && $bias['lon']) {
|
||||||
$params['location'] = $bias['lon'].','.$bias['lat'];
|
$params['location'] = $bias['lon'].','.$bias['lat'];
|
||||||
if (!empty($bias['radius_km'])) {
|
if (!empty($bias['radius_km'])) {
|
||||||
@ -181,12 +222,21 @@ class Geocoder
|
|||||||
private function reverseArcgis(float $lat, float $lon): ?array
|
private function reverseArcgis(float $lat, float $lon): ?array
|
||||||
{
|
{
|
||||||
$a = $this->cfg['arcgis'];
|
$a = $this->cfg['arcgis'];
|
||||||
|
$key = $this->arcgisKey();
|
||||||
|
if (!$key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
'location' => "{$lon},{$lat}",
|
'location' => "{$lon},{$lat}",
|
||||||
'f' => 'pjson',
|
'f' => 'pjson',
|
||||||
'token' => $a['api_key'],
|
'token' => $key,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (!empty($a['store'])) {
|
||||||
|
$params['forStorage'] = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
$res = $this->http()->get($this->arcgisBase().'/reverseGeocode', $params);
|
$res = $this->http()->get($this->arcgisBase().'/reverseGeocode', $params);
|
||||||
if (!$res->ok()) {
|
if (!$res->ok()) {
|
||||||
Log::warning('arcgis reverse geocode failed', ['status' => $res->status()]);
|
Log::warning('arcgis reverse geocode failed', ['status' => $res->status()]);
|
||||||
@ -247,8 +297,10 @@ class Geocoder
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$bias = $this->biasForUser($user);
|
||||||
|
|
||||||
return match ($provider) {
|
return match ($provider) {
|
||||||
"arcgis" => $this->arcgisSuggestions($query, $limit),
|
"arcgis" => $this->arcgisSuggestions($query, $limit, $bias),
|
||||||
default => [],
|
default => [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -256,17 +308,34 @@ class Geocoder
|
|||||||
/**
|
/**
|
||||||
* get the suggestions from arcgis
|
* get the suggestions from arcgis
|
||||||
*/
|
*/
|
||||||
private function arcgisSuggestions(string $query, int $limit): array
|
private function arcgisSuggestions(string $query, int $limit, ?array $bias = null): array
|
||||||
{
|
{
|
||||||
|
$key = $this->arcgisKey();
|
||||||
|
if (!$key) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
"singleLine" => $query,
|
"singleLine" => $query,
|
||||||
"outFields" => $this->cfg["arcgis"]["out_fields"] ?? "*",
|
"outFields" => $this->cfg["arcgis"]["out_fields"] ?? "*",
|
||||||
"maxLocations" => $limit,
|
"maxLocations" => $limit,
|
||||||
// you can bias results with 'countryCode' or 'location' here if desired
|
"category" => $this->cfg["arcgis"]["categories"] ?? "POI,Address",
|
||||||
|
"countryCode" => $this->cfg["arcgis"]["country_code"] ?? null,
|
||||||
"f" => "pjson",
|
"f" => "pjson",
|
||||||
"token" => $this->cfg["arcgis"]["api_key"],
|
"token" => $key,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if ($bias && $bias['lat'] && $bias['lon']) {
|
||||||
|
$params['location'] = $bias['lon'] . ',' . $bias['lat'];
|
||||||
|
if (!empty($bias['radius_km'])) {
|
||||||
|
$params['searchExtent'] = $this->bboxFromBias(
|
||||||
|
(float) $bias['lat'],
|
||||||
|
(float) $bias['lon'],
|
||||||
|
(float) $bias['radius_km']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($this->cfg["arcgis"]["store"])) {
|
if (!empty($this->cfg["arcgis"]["store"])) {
|
||||||
$params["forStorage"] = "true";
|
$params["forStorage"] = "true";
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user