221 lines
6.7 KiB
PHP
221 lines
6.7 KiB
PHP
<?php
|
|
|
|
namespace App\Service;
|
|
|
|
use GuzzleHttp\Client as GuzzleClient;
|
|
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
|
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
|
|
class MapTools
|
|
{
|
|
const URL_DISTANCE_MATRIX = 'https://maps.googleapis.com/maps/api/distancematrix/json';
|
|
|
|
// entity manager
|
|
protected $em;
|
|
|
|
// google maps api key
|
|
protected $gmaps_api_key;
|
|
|
|
// customer distance limit
|
|
protected $cust_dist_limit;
|
|
|
|
public function __construct(EntityManagerInterface $em, $gmaps_api_key,
|
|
$cust_dist_limit)
|
|
{
|
|
$this->em = $em;
|
|
$this->gmaps_api_key = $gmaps_api_key;
|
|
$this->cust_dist_limit = $cust_dist_limit;
|
|
}
|
|
|
|
protected function mapGetDistances(Point $point, $hubs)
|
|
{
|
|
$client = new GuzzleClient();
|
|
|
|
// origins
|
|
$origins_value = $point->getLatitude() . ',' . $point->getLongitude();
|
|
|
|
// destinations
|
|
$dests = [];
|
|
foreach ($hubs as $hub)
|
|
{
|
|
$coord = $hub->getCoordinates();
|
|
$dests[] = round($coord->getLatitude(),5) . ',' . round($point->getLongitude(), 5);
|
|
}
|
|
$dests_value = implode('|', $dests);
|
|
|
|
// google maps url
|
|
$maps_url = self::URL_DISTANCE_MATRIX;
|
|
|
|
// parameters
|
|
$gmaps_params = [
|
|
'origins' => $origins_value,
|
|
'destinations' => $dests_value,
|
|
];
|
|
|
|
//error_log(print_r($gmaps_params, true));
|
|
|
|
|
|
// query google maps api
|
|
$res = $client->request('GET', $maps_url, [
|
|
'query' => $gmaps_params,
|
|
'curl' => [
|
|
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4
|
|
],
|
|
]);
|
|
|
|
return $res->getBody();
|
|
}
|
|
|
|
public function getClosestHubs(Point $point, $limit, $time = false)
|
|
{
|
|
// get closest hubs based on st_distance function from db
|
|
$query = $this->em->createQuery('SELECT h, st_distance(h.coordinates, point(:lng, :lat)) as dist FROM App\Entity\Hub h' . ($time ? ' WHERE :time BETWEEN h.time_open AND h.time_close' : '') . ' ORDER BY dist')
|
|
->setParameter('lat', $point->getLatitude())
|
|
->setParameter('lng', $point->getLongitude());
|
|
|
|
if ($time) {
|
|
$query->setParameter('time', $time);
|
|
}
|
|
|
|
$query->setMaxResults($limit);
|
|
|
|
// error_log($query->getSql());
|
|
$result = $query->getResult();
|
|
|
|
$hubs = [];
|
|
$final_data = [];
|
|
foreach ($result as $row)
|
|
{
|
|
//error_log($row[0]->getName() . ' - ' . $row['dist']);
|
|
$hubs[] = $row[0];
|
|
|
|
// get coordinates of hub
|
|
$hub_coordinates = $row[0]->getCoordinates();
|
|
|
|
$cust_lat = $point->getLatitude();
|
|
$cust_lng = $point->getLongitude();
|
|
|
|
$hub_lat = $hub_coordinates->getLatitude();
|
|
$hub_lng = $hub_coordinates->getLongitude();
|
|
|
|
// get distance in kilometers from customer point to hub point
|
|
$dist = $this->distance($cust_lat, $cust_lng, $hub_lat, $hub_lng);
|
|
|
|
$final_data[] = [
|
|
'hub' => $row[0],
|
|
'db_distance' => $row['dist'],
|
|
'distance' => $dist,
|
|
'duration' => 0,
|
|
];
|
|
}
|
|
|
|
return $final_data;
|
|
|
|
/*
|
|
// get actual distance details with eta from google maps api
|
|
$raw_res = $this->mapGetDistances($point, $hubs);
|
|
$res = json_decode($raw_res, true);
|
|
//error_log(print_r($res, true));
|
|
|
|
// check if status is ok
|
|
if ($res['status'] != 'OK')
|
|
{
|
|
return $final_data;
|
|
// error_log('status not ok');
|
|
}
|
|
|
|
// check that the elements array is there
|
|
if (!isset($res['rows'][0]['elements']))
|
|
{
|
|
// error_log('no elements');
|
|
return $final_data;
|
|
}
|
|
|
|
foreach($res['rows'][0]['elements'] as $index => $gm_row)
|
|
{
|
|
// check status
|
|
if (isset($gm_row['status']) && $gm_row['status'] != 'OK')
|
|
{
|
|
// error_log('element row status not ok');
|
|
continue;
|
|
}
|
|
|
|
// set distance
|
|
if (isset($gm_row['distance']['value']))
|
|
$final_data[$index]['distance'] = $gm_row['distance']['value'];
|
|
|
|
// set duration
|
|
if (isset($gm_row['duration']['value']))
|
|
$final_data[$index]['duration'] = $gm_row['duration']['value'];
|
|
}
|
|
|
|
return $final_data;
|
|
*/
|
|
}
|
|
|
|
// NOTE: only the API calls this
|
|
public function getClosestOpenHubs(Point $point, $limit, $time = false)
|
|
{
|
|
// get closest hubs based on st_distance function from db
|
|
$query = $this->em->createQuery('SELECT h, st_distance(h.coordinates, point(:lng, :lat)) as dist FROM App\Entity\Hub h' . ($time ? ' WHERE h.status_open = true AND :time BETWEEN h.time_open AND h.time_close' : '') . ' ORDER BY dist')
|
|
->setParameter('lat', $point->getLatitude())
|
|
->setParameter('lng', $point->getLongitude());
|
|
|
|
if ($time) {
|
|
$query->setParameter('time', $time);
|
|
}
|
|
|
|
$query->setMaxResults($limit);
|
|
|
|
// error_log($query->getSql());
|
|
$result = $query->getResult();
|
|
|
|
$hubs = [];
|
|
$final_data = [];
|
|
foreach ($result as $row)
|
|
{
|
|
//error_log($row[0]->getName() . ' - ' . $row['dist']);
|
|
$hubs[] = $row[0];
|
|
|
|
// get coordinates of hub
|
|
$hub_coordinates = $row[0]->getCoordinates();
|
|
|
|
$cust_lat = $point->getLatitude();
|
|
$cust_lng = $point->getLongitude();
|
|
|
|
$hub_lat = $hub_coordinates->getLatitude();
|
|
$hub_lng = $hub_coordinates->getLongitude();
|
|
|
|
// get distance in kilometers from customer point to hub point
|
|
$dist = $this->distance($cust_lat, $cust_lng, $hub_lat, $hub_lng);
|
|
|
|
if ($dist < $this->cust_dist_limit)
|
|
{
|
|
$final_data[] = [
|
|
'hub' => $row[0],
|
|
'db_distance' => $row['dist'],
|
|
'distance' => $dist,
|
|
'duration' => 0,
|
|
];
|
|
}
|
|
}
|
|
|
|
error_log('nearest open hubs count: ' . count($final_data));
|
|
return $final_data;
|
|
}
|
|
|
|
protected function distance($lat1, $lon1, $lat2, $lon2)
|
|
{
|
|
if (($lat1 == $lat2) && ($lon1 == $lon2))
|
|
return 0;
|
|
|
|
$theta = $lon1 - $lon2;
|
|
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
|
|
$dist = acos($dist);
|
|
$dist = rad2deg($dist);
|
|
$miles = $dist * 60 * 1.1515;
|
|
|
|
return round(($miles * 1.609344), 1);
|
|
}
|
|
}
|