<?php
namespace App\Service;
use App\Interfaces\HotelMongoInterface;
use App\Interfaces\SearchInterface;
use App\Vendor\Symfony\HAbstractService;
use App\Vendor\Symfony\UserException;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class SearchService extends HAbstractService implements SearchInterface
{
private array $guests = [];
private HotelMongoInterface $hotelMongo;
private LoggerInterface $zstLogger;
public function __construct(ContainerBagInterface $bag, EntityManagerInterface $em, KernelInterface $kernel, HotelMongoInterface $hotelMongo, TranslatorInterface $translator, LoggerInterface $zstLogger)
{
parent::__construct($bag, $em, $kernel,$translator);
$this->translator = $translator;
$this->hotelMongo = $hotelMongo;
$this->zstLogger = $zstLogger;
}
/**
* @param int $regionId
* @param string $checkIn
* @param string $checkOut
* @param array $gusts
* @param string $language
* @param string $currency
* @param int $hotelsLimit
* @param string $residency
* @return array
*/
public function regionSearch(int $regionId, string $checkIn, string $checkOut, string $language, string $currency = "", int $hotelsLimit = 0, string $residency = ""): array
{
$params = get_defined_vars();
$data = $this->sendData( self::REGION_SEARCH,$params);
return $data;
}
/**
* @param float $latitude
* @param float $longitude
* @param int $radius
* @param string $checkIn
* @param string $checkOut
* @param array $gusts
* @param string $language
* @param string $currency
* @param string $residency
* @return array
*/
public function geoSearch(float $latitude, float $longitude, int $radius, string $checkIn, string $checkOut, string $language, string $currency = "", string $residency = ""): array
{
$params = get_defined_vars();
$data = $this->generateSearchQuery( self::GEO_SEARCH,$params);
return $data;
}
/**
* @param array $ids
* @param string $checkIn
* @param string $checkOut
* @param array $gusts
* @param string $language
* @param string $currency
* @param string $residency
* @return array
*/
public function hotelsSearch(array $ids, string $checkIn, string $checkOut, string $language, string $currency = "", string $residency = ""): array
{
$params = get_defined_vars();
$result = $this->sendData( self::HOTELS_SEARCH,$params);
return $result;
}
/**
* @param string $search
* @param string $language
* @return array
*/
public function hotelSearchAutocomplete(string $search, string $language): array
{
return [];
}
/**
* @param string $id
* @param string $checkIn
* @param string $checkOut
* @param array $gusts
* @param string $language
* @param string $currency
* @param string $residency
* @return array
*/
public function hotelPage(string $id, string $checkIn, string $checkOut, string $language, string $currency = "", string $residency = ""): array
{
return [];
}
/**
* @param array $rooms
* @throws UserException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/
public function setRooms(array $rooms){
$children = [];
if(empty($rooms)){
throw new \Exception("rooms is required");
}
if(count($rooms) > (int)$this->bag->get('rooms_count')){
throw new UserException($this->translator->trans('roomsCount', ['{number}' => $this->bag->get('rooms_count')]));
}
foreach ($rooms as $room){
if(!empty($room["children"])){
$children = explode(',', $room["children"][0]);
foreach ($children as $key=>&$c){
if($c == 'NaN'){
unset($children[$key]);
continue;
}
$children[$key] = intval($c);
}
}
$roomChildrenCount = count($children);
if($roomChildrenCount > (int)$this->bag->get('children_count')){
throw new UserException($this->translator->trans('childrenCount', ['{number}' => $this->bag->get('children_count')]));
}
foreach ($children as $child){
if((int)$child > (int)$this->bag->get('children_age')){
throw new UserException($this->translator->trans('childrenAge', ['{year}' => $this->bag->get('children_age')]));
}
}
$roomGuests = [
"adults" => empty($room["adults"]) ? 2 :(int)$room["adults"],
"children" => $children
];
$this->guests[] = $roomGuests;
}
}
public function generateSearchQuery($type, $params = []){
if(!empty($params["checkIn"])){
$params["checkin"] = $params["checkIn"];
}
if(!empty($params["checkOut"])){
$params["checkout"] = $params["checkOut"];
}
$currentDay = date("Y-m-d");
$checkIn = empty($params["checkin"]) ? date("Y-m-d", strtotime($currentDay . ' +1 day')) : $params["checkin"];
$checkOut = empty($params["checkout"]) ? date('Y-m-d', strtotime($checkIn . ' +1 day')) : $params["checkout"];
$language = empty($params["language"]) ? $this->request->getLocale() : $params["language"];
if(empty($this->guests)){
$this->guests = [
[
"adults" => empty($room["adults"]) ? 2 :(int)$room["adults"],
"children" => !empty($room["children"]) ? $room["children"] : []
]
];
}
$query = [
"checkin" => $checkIn,
"checkout" => $checkOut,
"language" => $language,
"guests" => $this->guests,
"residency"=> $params["residency"],
];
if($type == self::REGION_SEARCH){
$query["region_id"] = $params["regionId"];
}
if($type == self::GEO_SEARCH){
$query["latitude"] = $params["latitude"];
$query["longitude"] = $params["longitude"];
$query["radius"] = $params["radius"];
}
if($type == self::HOTELS_SEARCH){
$query["ids"] = $params["ids"];
}
if($type == self::HOTEL_PAGE){
$query['id'] = trim($params["hotelId"]);
}
$query["currency"] = empty($params["currency"]) ? "RUB" : $params["currency"];
if(!empty($hotelsLimit)){
$query["hotels_limit"] = $hotelsLimit;
}
return json_encode($query);
}
public function searchAutocomplete($params){
$search = [
"query" => $params["search"],
"language" => $params["lang"],
];
$postData = json_encode($search);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://api.worldota.net/api/b2b/v3/search/multicomplete/',
CURLOPT_USERPWD => $this->bag->get('zstd_user').":".$this->bag->get('zstd_pass'),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>$postData,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
$error = curl_error($curl);
$data = json_decode($response, true);
curl_close($curl);
if($data["status"] == "ok" && empty($data["error"])){
return $data["data"];
} else {
return $data["error"];
}
}
private function sendData($type, $params){
$jsonParams = $this->generateSearchQuery($type, $params);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://api.worldota.net/api/b2b/v3/search/serp/region/',
CURLOPT_USERPWD => $this->bag->get('zstd_user').":".$this->bag->get('zstd_pass'),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>$jsonParams,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
$respArray = json_decode($response, true);
if(empty($respArray["data"])){
return [];
}
foreach ($respArray["data"]["hotels"] as $ind=>$datum){
foreach ($datum["rates"] as $rIndex =>$rate){
if($rate["allotment"] == 0){
unset($datum["rates"][$rIndex]);
}
}
if(count($datum["rates"]) < 1){
unset($datum["hotels"][$ind]);
}
}
$resp = json_encode($respArray["data"]["hotels"]);
$session = $this->request->getSession();
if($session->has("search_result")){
$session->remove("search_result");
}
$session->set("search_result", $resp);
return $this->getIds();
}
private function getIds(){
$session = $this->request->getSession();
$regions = json_decode($session->get("search_result"), true);
$hotels = [];
$ids = [];
foreach ($regions as $region){
if(isset($region["rates"]) && !empty($region["rates"])){
$ids[] = $region["id"];
$hotels[$region["id"]] = $region;
}
}
return ["ids" => $ids, "hotels" => $hotels];
}
}