Files
Verde-Web/app/Services/DropOff/DropOffPointFinder.php

63 lines
1.9 KiB
PHP

<?php
namespace App\Services\DropOff;
use App\Models\DropOffPoint;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class DropOffPointFinder
{
/**
* Return active DOPs within $radiusKm of the given coordinates,
* ordered by distance ascending. Each result has a `distance_meters`
* attribute attached.
*
* @return Collection<int, DropOffPoint>
*/
public function nearby(float $latitude, float $longitude, float $radiusKm = 5.0, int $limit = 25): Collection
{
$radiusMeters = $radiusKm * 1000;
$rows = DB::table('drop_off_points')
->whereNull('deleted_at')
->where('status', DropOffPoint::STATUS_ACTIVE)
->select('id')
->selectRaw(
'ST_Distance_Sphere(coordinates, ST_SRID(POINT(?, ?), 4326)) AS distance_meters',
[$longitude, $latitude],
)
->whereRaw(
'ST_Distance_Sphere(coordinates, ST_SRID(POINT(?, ?), 4326)) <= ?',
[$longitude, $latitude, $radiusMeters],
)
->orderBy('distance_meters')
->limit($limit)
->get();
if ($rows->isEmpty()) {
return collect();
}
$distancesById = $rows->pluck('distance_meters', 'id');
$points = DropOffPoint::with('barangay')
->whereIn('id', $rows->pluck('id'))
->get()
->keyBy('id');
return $rows->map(function ($r) use ($points, $distancesById) {
$p = $points->get($r->id);
if ($p) {
$p->distance_meters = (float) $distancesById->get($r->id);
}
return $p;
})->filter()->values();
}
public function nearest(float $latitude, float $longitude, float $maxKm = 25.0): ?DropOffPoint
{
return $this->nearby($latitude, $longitude, $maxKm, 1)->first();
}
}