<?php
namespace Diplix\KMGBundle\Service;
use Diplix\KMGBundle\Entity\TalixoItem;
use Diplix\KMGBundle\Entity\TalixoItemPlace;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use GuzzleHttp;
use Doctrine\DBAL\Driver\Connection;
use Symfony\Component\PropertyAccess\PropertyAccess;
/**
Beta key
48f78fa081264362af976bfaa0f93b29
Production key
9d548fb259e944788684860fb5d8fa71
*/
class TalixoConnector
{
const STATUS = "status";
const BODY = "body";
const URL = "url";
const METHOD = "method";
const REQUEST = "request";
const BETA_KEY = "48f78fa081264362af976bfaa0f93b29";
public static $connectionSettings = array(
'connect_timeout' => "5", // abort if no response after X seconds
'verify' => false, // we do not care if the cert is valid or not
'http_errors' => false, // do not throw exception on 4xx/5xx http responses
);
public static $transformationMap = [
"firstName"=>"first_name",
"lastName"=> "last_name",
"mobilePhone"=>"mobile",
"paymentMethod"=>"payment_method",
"bookingNumber"=>"booking_number"
];
/**
* @var GuzzleHttp\Client
*/
protected $client;
/**
* @var EntityManager
*/
protected $em;
/**
* @var Connection
*/
protected $db;
protected $serverAddress = "http://localhost/KMG/Web/web/app_dev.php/kmg/talixo-mock/";
public function __construct(EntityManagerInterface $em)
{
$this->logPath = __DIR__ . "/../../../../app/logs/talixo.log";
$this->em = $em;
$this->db = $this->em->getConnection();
// init http client (guzzle 6.x)
$this->client = new GuzzleHttp\Client($this::$connectionSettings);
}
public function setServerAddress($url)
{
$this->serverAddress = $url;
}
protected function log($dir=0,$urlOrStatus,$data)
{
$msg = "[".date("Y-m-d H:i:s")."]".($dir == 0 ? ">>>\n" : ($dir == 1 ? "<<<\n" : "(trace)" ) );
$msg .= $urlOrStatus . " : " . $data . "\n";
file_put_contents($this->logPath, $msg, FILE_APPEND);
}
protected function getUrl($cmd)
{
return rtrim($this->serverAddress,"/")."/" . $cmd;
}
protected function flattenPlace($prefix, TalixoItemPlace $place)
{
return [
$prefix."_iata_code" => $place->getIataCode(),
$prefix."_point" => $place->getAddress(),
$prefix."_place_id" => $place->getPlaceId(),
$prefix."_point_lat" => $place->getLatitude(),
$prefix."_point_lng" => $place->getLongitude(),
];
}
/**
* @param $data
* @param TalixoItemPlace|null $place
* @return TalixoItemPlace
*/
protected function erectPlace($data,TalixoItemPlace $place)
{
if (is_null($place)) $place = new TalixoItemPlace();
$place->setTalixoId($data["talixo_id"]);
$place->setLatitude($data["latitude"]);
$place->setLongitude($data["longitude"]);
$place->setAddress($data["address"]);
// [...]
return $place;
}
/**
* convert from TalixoItem to associative array
* @param TalixoItem $item
* @return array
*/
protected function flatten(TalixoItem $item)
{
$out = [];
$out = array_merge($out,$this->flattenPlace("start",$item->getStartPoint()));
$out = array_merge($out,$this->flattenPlace("end",$item->getEndPoint()));
if (!is_null($item->getStartTime()))
{
$out["start_time_date"] = $item->getStartTime()->format("Y-m-d");
$out["start_time_time"] = $item->getStartTime()->format("H:i");
}
$accessor = PropertyAccess::createPropertyAccessor();
foreach (self::$transformationMap as $fin=>$fout)
{
$out[$fout] = $accessor->getValue($item,$fin);
}
return $out;
}
/**
* convert from assoc array to TalixoItem
* @param array $data
* @param TalixoItem $item
*/
protected function erect(array $data,TalixoItem $item)
{
$item->setRaw(json_encode($data));
$pm = $data["payment_method"];
unset($data["payment_method"]);
$item->setPaymentMethod( $pm["label"] );
$accessor = PropertyAccess::createPropertyAccessor();
foreach (array_flip(self::$transformationMap) as $fx=>$fobj)
{
if (array_key_exists($fx,$data)) $accessor->setValue($item,$fobj,$data[$fx]);
}
if (array_key_exists("start_point",$data))
{
$item->setStartPoint( $this->erectPlace($data["start_point"],$item->getStartPoint()) );
}
if (array_key_exists("end_point",$data))
{
$item->setEndPoint( $this->erectPlace($data["end_point"],$item->getEndPoint()) );
}
}
protected function req($method,$cmd, $data)
{
$url = (strpos($cmd,"http") === false ? $this->getUrl($cmd) : $cmd );
$body = json_encode($data);
$this->log(0,$url,$body);
$res = $this->client->request($method,$url,[
'headers' =>[
'Content-Type' => 'application/json', // content-type text/json not supported by talixo v3
'Partner' => self::BETA_KEY
],
"body" =>$body
]);
$content = $res->getBody()->getContents();
$this->log(1,$res->getStatusCode(),$content);
return [
self::METHOD => $method,
self::URL => $url,
self::REQUEST => $data,
self::STATUS => $res->getStatusCode() ,
self::BODY => json_decode($content,true)
];
}
protected function post($cmd,$data)
{
return $this->req("POST",$cmd,$data);
}
protected function get($cmd,$data)
{
return $this->req("GET",$cmd,$data);
}
protected function check4ErrorResponse($res)
{
if ($res[self::STATUS] > 299)
{
$err = [];
$err[] = sprintf("Service error (http %d) on %s %s",$res[self::STATUS],$res[self::METHOD],$res[self::URL]);
if (array_key_exists("errors",$res[self::BODY]))
{
foreach ($res[self::BODY]["errors"] as $one)
{
$err[]= $one["id"].": " . join(",",$one["errors"]);
}
}
else
{
$err[]= "Undefined error";
}
throw new \Exception(join(";\n",$err));
}
}
public function remote2entity(TalixoItem $it, array $row)
{
$it->setRaw(json_encode($row));
$it->setBookingNumber($row["booking_number"]);
$start = TalixoItemPlace::fromArray($row["start_point"]);
$end = TalixoItemPlace::fromArray($row["end_point"]);
$it->setStartPoint($start);
$it->setEndPoint($end);
$it->setStartTime(new \DateTime($row["start_time"]));
$it->setEndTime(new \DateTime($row["end_time"]));
$it->setPin($row["pin"]);
$it->setDuration($row["duration"]);
$it->setDistance($row["distance"]);
$it->setPassengerCount($row["passengers"]);
$it->setOrigin($row["booking_origin"]);
$it->setFirstName($row["passenger"]["first_name"]);
$it->setLastName($row["passenger"]["last_name"]);
$it->setMobilePhone($row["passenger"]["mobile"]);
return $it;
}
public function booking_query(TalixoItem $item)
{
$data = $this->flatten($item);
$res = $this->post("vehicles/booking_query/",$data);
$this->check4ErrorResponse($res);
return $res;
}
public function createBooking(TalixoItem $item)
{
$data = $this->flatten($item);
$res = $this->post("bookings/",$data);
$this->check4ErrorResponse($res);
$this->erect($res[self::BODY],$item);
return $res;
}
public function bookings()
{
$res = $this->get("bookings/",[]);
$this->check4ErrorResponse($res);
$resultRows = [];
while (1)
{
$b = $res["body"];
if ($b["count"]>0)
{
foreach ($b["results"] as $row)
{
$resultRows[] = $row;
}
}
if ($b["next"]!=null)
{
$res = $this->get($b["next"],[]);
$this->check4ErrorResponse($res);
}
else
{
break;
}
}
return $resultRows;
}
}