| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071 |
- <?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}
- ");
- }
- }
|