| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 |
- <?php
- namespace App\Services;
- use Illuminate\Contracts\Database\Query\Expression;
- use Illuminate\Support\Facades\DB;
- class DistanceService
- {
- private const EARTH_RADIUS_KM = 6371;
- public static function calculate(?float $lat1, ?float $lng1, ?float $lat2, ?float $lng2): ?float
- {
- if ($lat1 === null || $lng1 === null || $lat2 === null || $lng2 === null) {
- return null;
- }
- $lat1Rad = deg2rad($lat1);
- $lat2Rad = deg2rad($lat2);
- $lng1Rad = deg2rad($lng1);
- $lng2Rad = deg2rad($lng2);
- $cosValue = cos($lat1Rad) * cos($lat2Rad) * cos($lng2Rad - $lng1Rad)
- + sin($lat1Rad) * sin($lat2Rad);
- $cosValue = min(1.0, max(-1.0, $cosValue));
- return round(self::EARTH_RADIUS_KM * acos($cosValue), 1);
- }
- public static function sqlExpression(
- ?float $clientLatitude,
- ?float $clientLongitude,
- string $targetLatCol = 'provider_address.latitude',
- string $targetLngCol = 'provider_address.longitude',
- string $alias = 'distance_km'
- ): Expression {
- if ($clientLatitude === null || $clientLongitude === null) {
- return DB::raw("NULL as {$alias}");
- }
- return DB::raw("
- CASE
- WHEN {$targetLatCol} IS NOT NULL
- AND {$targetLngCol} IS NOT NULL
- THEN ROUND((
- ".self::EARTH_RADIUS_KM." * acos(
- least(1, greatest(-1,
- cos(radians({$clientLatitude}))
- * cos(radians({$targetLatCol}))
- * cos(radians({$targetLngCol}) - radians({$clientLongitude}))
- + sin(radians({$clientLatitude}))
- * sin(radians({$targetLatCol}))
- ))
- )
- )::numeric, 1)
- ELSE NULL
- END as {$alias}
- ");
- }
- }
|