resq/src/Service/MapTools.php
2018-01-30 19:47:39 +08:00

129 lines
3.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;
public function __construct(EntityManagerInterface $em, $gmaps_api_key)
{
$this->em = $em;
$this->gmaps_api_key = $gmaps_api_key;
}
protected function mapGetDistances(Point $point, $outlets)
{
$client = new GuzzleClient();
// origins
$origins_value = $point->getLatitude() . ',' . $point->getLongitude();
// destinations
$dests = [];
foreach ($outlets as $outlet)
{
$coord = $outlet->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]);
return $res->getBody();
}
public function getClosestOutlets(Point $point, $limit, $time = false)
{
// get closest outlets based on st_distance function from db
$query = $this->em->createQuery('SELECT o, st_distance(o.coordinates, point(:lng, :lat)) as dist FROM App\Entity\Outlet o' . ($time ? ' WHERE :time BETWEEN o.time_open AND o.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();
$outlets = [];
$final_data = [];
foreach ($result as $row)
{
//error_log($row[0]->getName() . ' - ' . $row['dist']);
$outlets[] = $row[0];
$final_data[] = [
'outlet' => $row[0],
'db_distance' => $row['dist'],
'distance' => 0,
'duration' => 0,
];
}
// get actual distance details with eta from google maps api
$raw_res = $this->mapGetDistances($point, $outlets);
$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;
}
}