so-manager-dev.com/app/Services/GoogleMapsService.php
2025-09-19 19:01:21 +09:00

185 lines
5.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services;
use Exception;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
/**
* Google Maps API サービス
* SHJ-1本人確認自動処理で距離計算に使用
*/
class GoogleMapsService
{
protected $apiKey;
protected $baseUrl;
protected $config;
public function __construct()
{
$this->apiKey = config('shj1.apis.google_maps.api_key');
$this->baseUrl = config('shj1.apis.google_maps.base_url');
$this->config = config('shj1.distance.google_maps_config');
}
/**
* 2点間の距離を計算Google Maps Distance Matrix API使用
*
* @param string $origin 出発地(住所)
* @param string $destination 目的地(住所)
* @return array ['distance_meters' => int, 'distance_text' => string, 'status' => string]
* @throws Exception
*/
public function calculateDistance(string $origin, string $destination): array
{
try {
$url = "{$this->baseUrl}/distancematrix/json";
$params = [
'origins' => $origin,
'destinations' => $destination,
'units' => $this->config['units'] ?? 'metric',
'mode' => $this->config['mode'] ?? 'walking',
'language' => $this->config['language'] ?? 'ja',
'region' => $this->config['region'] ?? 'jp',
'key' => $this->apiKey,
];
$response = Http::timeout(30)->get($url, $params);
if (!$response->successful()) {
throw new Exception("Google Maps API request failed: " . $response->status());
}
$data = $response->json();
// APIエラーチェック
if ($data['status'] !== 'OK') {
throw new Exception("Google Maps API error: " . $data['status']);
}
$element = $data['rows'][0]['elements'][0];
if ($element['status'] !== 'OK') {
throw new Exception("Distance calculation failed: " . $element['status']);
}
return [
'distance_meters' => $element['distance']['value'],
'distance_text' => $element['distance']['text'],
'duration_text' => $element['duration']['text'] ?? null,
'status' => 'success'
];
} catch (Exception $e) {
Log::error('Google Maps distance calculation error', [
'origin' => $origin,
'destination' => $destination,
'error' => $e->getMessage()
]);
throw $e;
}
}
/**
* 住所から座標を取得Geocoding API使用
*
* @param string $address 住所
* @return array ['lat' => float, 'lng' => float]
* @throws Exception
*/
public function geocodeAddress(string $address): array
{
try {
$url = "{$this->baseUrl}/geocode/json";
$params = [
'address' => $address,
'language' => $this->config['language'] ?? 'ja',
'region' => $this->config['region'] ?? 'jp',
'key' => $this->apiKey,
];
$response = Http::timeout(30)->get($url, $params);
if (!$response->successful()) {
throw new Exception("Google Geocoding API request failed: " . $response->status());
}
$data = $response->json();
if ($data['status'] !== 'OK') {
throw new Exception("Google Geocoding API error: " . $data['status']);
}
$location = $data['results'][0]['geometry']['location'];
return [
'lat' => $location['lat'],
'lng' => $location['lng']
];
} catch (Exception $e) {
Log::error('Google Maps geocoding error', [
'address' => $address,
'error' => $e->getMessage()
]);
throw $e;
}
}
/**
* 座標から直線距離を計算Haversine formula
* Google Maps APIが利用できない場合のフォールバック
*
* @param float $lat1 緯度1
* @param float $lon1 経度1
* @param float $lat2 緯度2
* @param float $lon2 経度2
* @return int 距離(メートル)
*/
public function calculateStraightLineDistance(float $lat1, float $lon1, float $lat2, float $lon2): int
{
$earthRadius = 6371000; // 地球の半径(メートル)
$dLat = deg2rad($lat2 - $lat1);
$dLon = deg2rad($lon2 - $lon1);
$a = sin($dLat / 2) * sin($dLat / 2) +
cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
sin($dLon / 2) * sin($dLon / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$distance = $earthRadius * $c;
return round($distance);
}
/**
* 距離詳細文字列を生成SHJ-1の要求仕様に準拠
*
* @param int $parkId 駐輪場ID
* @param int $distanceMeters 距離(メートル)
* @param string $method 計算方法
* @return string
*/
public function generateDistanceDetailString(int $parkId, int $distanceMeters, string $method = 'google_maps'): string
{
return $parkId . "/" . $parkId . "/二点間距離:" . $distanceMeters . "m (" . $method . ")";
}
/**
* APIキーが設定されているかチェック
*
* @return bool
*/
public function isApiKeyConfigured(): bool
{
$dummyKey = env('GOOGLE_MAPS_API_KEY') === 'dummy_google_maps_api_key_replace_with_real_one';
return !empty($this->apiKey) && !$dummyKey;
}
}