<?php
namespace App\Service;
use App\Entity\Currency;
use App\Entity\Wishlist;
use App\Interfaces\HotelMongoInterface;
use App\Interfaces\IHotels;
use App\Interfaces\OrderInterface;
use App\Interfaces\ReviewsInterface;
use App\Interfaces\SearchInterface;
use App\Interfaces\StaticDataInterface;
use App\Vendor\Helper;
use App\Vendor\Symfony\HAbstractService;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class HotelService extends HAbstractService implements IHotels
{
private PaginatorInterface $paginator;
private $lang;
private HotelMongoInterface $hm;
private ReviewsInterface $reviewsService;
private StaticDataInterface $staticDataService;
private SearchInterface $searchService;
private $searched = false;
private OrderInterface $orderService;
public function __construct(ContainerBagInterface $bag, EntityManagerInterface $em, KernelInterface $kernel, TranslatorInterface $translator,
PaginatorInterface $paginator,
HotelMongoInterface $hm,
ReviewsInterface $reviewsService, StaticDataInterface $staticDataService,SearchInterface $searchService, OrderInterface $orderService){
parent::__construct($bag,$em,$kernel, $translator);
$this->paginator = $paginator;
$this->hm = $hm;
$this->reviewsService = $reviewsService;
$this->staticDataService = $staticDataService;
$this->searchService = $searchService;
$this->orderService = $orderService;
}
public function list(Request $request, $limit = 20){
$params = $this->getRequestParams($request);
if(isset($params[0])){
$params["search"]["currency"] = $params[0]["search"]["currency"];
}
unset($params["path"]);
$request->query->remove("path");
if(isset($params["rating"]) && !empty($params["rating"]) && $params["rating"][0] == "on"){
unset($params["rating"]);
$request->query->remove("rating");
}
$searchData = [];
if(isset($params["search"]) && empty($params["search"]["status"])){
$search = $params["search"];
$currentDay = date("Y-m-d");
$checkIn = empty($search["checkin"]) ? date("Y-m-d", strtotime($currentDay . ' +1 day')) : $search["checkin"];
$checkOut = empty($search["checkout"]) ? date("Y-m-d", strtotime($checkIn . ' +1 day')) : $search["checkout"];
$guestsDefault = [
[
"adults" => 2,
"children" => []
]
];
$guests = empty($search["guests"]) ? $guestsDefault : $search["guests"];
$this->searchService->setRooms($guests);
if(!empty($search["location"])){
$searchData = $this->searchService->regionSearch($search["location"],$checkIn,$checkOut, $request->getLocale(),$search["currency"],0, $search["residency"]);
}
}
if(isset($params["page"])){
unset($params["page"]);
}
if(isset($params["search"])){
if(!empty($searchData)){
$params["id"] = $searchData["ids"];
unset($params["search"]);
} else {
$params["id"] = $searchData;
}
}
// if(empty($params['star_rating'])){
// $params['star_rating'] = [5];
// }
$criteria = $this->hm->mongoIn($params);
$hotelsDb = 'hotels_'.$request->getLocale();
$this->hm->select($hotelsDb);
$postParams = $request->request->all();
if(!empty($postParams)){
$page = $request->request->getInt('page', 1);
} else {
$page = $request->query->getInt('page', 1);
}
$skip = ($page - 1) * (int)$limit;
$sort = $request->query->get('sort');
$direction = $request->query->get('dir');
$direction = $direction == 'asc' ? 1 : -1;
$hotels = $this->hm->findBy($criteria,$limit,$skip,$sort,$direction);
/** @var Router $router */
$router = $this->container->get('router');
$searchH = $request->query->all();
foreach ($hotels as $ind=>&$hotel){
if(!empty($searchData) && !empty($searchData["hotels"])){
if(!isset($searchData["hotels"][$hotel["id"]])){
unset($hotels[$ind]);
continue;
}
foreach ($searchData["hotels"][$hotel["id"]]["rates"] as $index=>$rate){
if($rate["allotment"] < 1){
unset($searchData["hotels"][$hotel["id"]]["rates"][$index]);
}
}
if(count($searchData["hotels"][$hotel["id"]]["rates"]) == 0){
unset($hotels[$ind]);
continue;
}
$rate = $searchData["hotels"][$hotel["id"]]["rates"][0];
$price = (int)$rate["payment_options"]["payment_types"][0]["show_amount"];
$currencyCode = $rate["payment_options"]["payment_types"][0]["show_currency_code"];
$days = Helper::dateDiffInDays($search["checkin"], $search["checkout"]);
$hotel["prices"] = [
"price" => $price,
"day" => $days,
"currency" => $this->em->getRepository(Currency::class)->findOneBy(["iso" => $currencyCode])
];
$searchH["search"]["hotelId"] = $hotel["id"];
$hotel["link"] = $router->generate('app_detail_hotel_detail', ["id"=>$hotel["id"],$searchH]);
}
if(isset($hotel["serp_filters"])){
foreach ($hotel["serp_filters"] as &$serp_filter){
$serp_filter = [
"key" =>$serp_filter,
"name" =>$this->staticDataService->getSerpFilter($serp_filter, $request->getLocale()),
];
}
}
// $reviews = $this->reviewsService->getReviewsByHotelId($hotel["id"], $request->getLocale());
//
$score = "";
if(!empty($hotel["reviews"])){
$reviews = $hotel["reviews"];
$reviewsCount = count($reviews["reviews"]);
$rating = $reviews["rating"];
if($rating < 7){
$score = self::RATING["Review score"];
}
if($rating > 7 && $rating < 8){
$score = self::RATING["Good"];
}
if($rating >= 8 && $rating < 8.5 ){
$score = self::RATING["Very Good"];
}
if($rating >= 8.5 && $rating < 9 ){
$score = self::RATING["Excellent"];
}
if($rating >= 9 && $rating < 9.5 ){
$score = self::RATING["Wonderful"];
}
if($rating >= 9.5 && $rating <= 10 ){
$score = self::RATING["Exceptional"];
}
$hotel["reviews"] = [
"rating" => $rating,
"reviewsCount" => $reviewsCount,
"score" => $score
];
}
// if(empty($reviews)){
// $hotel["reviews"]["rating"] = 0;
// } else{
// $rating = $reviews["rating"];
// if(!empty($rating)){
// $whole = floor($rating);
// $remainder = $rating - $whole;
// $review["ratingGroup"] = [
// "whole" => (int)$whole,
// "remainder" => $remainder,
// ];
// }
// $hotel["reviews"] = $review;
// }
$wishlist = $this->em->getRepository(Wishlist::class)->findOneBy(["hotelId" => $hotel["id"]]);
if(!empty($wishlist)){
$hotel["wishlist"] = true;
} else {
$hotel["wishlist"] = false;
}
}
$this->hm->select($hotelsDb);
$totalCount = $this->hm->count($criteria);
if(count($hotels) == 0){
$totalCount = 0;
}
$pagination = $this->paginator->paginate(
$hotels,
$page,
$limit
);
$pagination->setItems($hotels);
$pagination->setTotalItemCount($totalCount);
foreach ($pagination->getItems() as &$item){
if(empty($item["images"])){
continue;
}
foreach ($item["images"] as &$image){
$image = str_replace('{size}','x500', $image);
}
}
return $pagination;
}
public function getByHotelId(string $hotelId, string $lang){
$collection = 'hotels_'.$lang;
$this->hm->select($collection);
$hotel = $this->hm->findByKey("id", trim($hotelId));
return $hotel;
}
public function updateOneHotelFromJson($json, $lang){
$collection = "hotel_".$lang;
$this->hm->updateOneFromJson($json, $collection);
}
public function hotelPage(string $id, Request $request){
$id = trim($id);
$params = $this->getParams();
$guests = [];
if(isset($params["search"])){
$params["search"]["language"] = $request->getLocale();
$params["search"]["hotelId"] = $id;
$guests = $params["search"]["guests"];
} else if(!empty($params[0]["search"])){
// foreach ($params[0]['search']["guests"] as &$room){
// $item["adults"] = (int)$room["adults"];
//
// if($room["children"][0] == "NaN"){
// $item["children"] = [];
// } else{
// foreach ($room["children"] as $child){
// $item["children"][] = (int)$child;
// }
// }
//
// $guests[] = $item;
// }
$params[0]["search"]["language"] = $request->getLocale();
$guests = $params[0]["search"]["guests"];
$params[0]["search"]["hotelId"] = $id;
}
$params["hotelId"] = $id;
$this->searchService->setRooms($guests);
if(isset($params["search"])){
$jsonParams = $this->searchService->generateSearchQuery(SearchInterface::HOTEL_PAGE, $params["search"]);
} else {
$jsonParams = $this->searchService->generateSearchQuery(SearchInterface::HOTEL_PAGE, $params[0]["search"]);
}
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://api.worldota.net/api/b2b/v3/search/hp/',
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);
$hotelResponseData = json_decode($response, true);
$data = [];
if(empty($hotelResponseData["data"])){
return $data["hotel"] = [];
}
if(empty($hotelResponseData["data"]["hotels"])){
return $data["hotel"] = [];
}
$hotelData = $hotelResponseData["data"]["hotels"][0]["rates"];
$hotelsDb = 'hotels_'.$request->getLocale();
$this->hm->select($hotelsDb);
// $localData = $this->hm->findByKey('id', $id);
// if(empty($localData)){
// return $data["hotel"] = [];
// }
// $localData = iterator_to_array($localData[0]);
$roomGroups = [];
unset($roomGroup);
/** @var Router $router */
$router = $this->container->get('router');
$localData = $this->getHotelInfo($id, $request->getLocale());
foreach ($localData["room_groups"] as $roomGroup){
$roomGroup["images"] = $this->hotelImages($roomGroup["images"]);
foreach ($hotelData as $hotelDatum){
if($hotelDatum["room_data_trans"]["main_name"] == $roomGroup["name_struct"]["main_name"] && $hotelDatum["room_data_trans"]["bedding_type"] == $roomGroup["name_struct"]["bedding_type"]){
$hotelDatum["partner_id"] = Helper::uuid4();
$hotelDatum["total_taxes_amount"] = $this->orderService->getTotalTaxes($hotelDatum);
$roomGroup["rates"][] = $hotelDatum;
$roomGroups[$roomGroup["name_struct"]["main_name"]] = $roomGroup;
}
}
}
foreach ($roomGroups as &$roomGroup){
if(isset($roomGroup["room_amenities"])){
$roomAmenitiesData = [];
foreach ($roomGroup["room_amenities"] as $room_amenity){
if(is_array($room_amenity)){
continue;
}
$room_amenity_item = [
"key" =>$room_amenity,
"name" =>is_array($this->staticDataService->getRoomAmenity($room_amenity, $request->getLocale())) ? "" : $this->staticDataService->getRoomAmenity($room_amenity, $request->getLocale()),
];
$roomAmenitiesData[] = $room_amenity_item;
}
$roomGroup["room_amenities"]= $roomAmenitiesData;
}
if(isset($roomGroup["rates"])){
foreach ($roomGroup["rates"] as &$rate){
if($rate["meal"] != "nomeal"){
$meal = $this->staticDataService->getMeal($rate["meal"], $request->getLocale());
$rate["meal"] = $meal;
}
if(isset($rate["amenities_data"])){
$rateAmenitiesData = [];
foreach ($rate["amenities_data"] as $rateAmenities){
if(is_array($rateAmenities)){
continue;
}
$item = [
"key" =>$rateAmenities,
"name" =>$this->staticDataService->getRoomAmenity($rateAmenities, $request->getLocale()),
];
$rateAmenitiesData[] = $item;
}
$rate["amenities_data"] = $rateAmenitiesData;
}
}
}
}
if(!empty($localData["reviews"])){
$newDetailedRatings = [];
foreach ($localData["reviews"]["detailed_ratings"] as $key=>$rating){
$newKey = $this->translator->trans($key);
$newDetailedRatings[$newKey] = $rating;
}
$localData["reviews"]["detailed_ratings"] = $newDetailedRatings;
}
$groups = [];
foreach ($roomGroups as $group){
$groups[] = $group;
}
$localData["room_groups"] = $groups;
$localData["images"] = $this->hotelImages($localData["images"]);
if(isset($localData["serp_filters"])){
foreach ($localData["serp_filters"] as &$serp_filter){
$serp_filter = [
"key" =>$serp_filter,
"name" =>$this->staticDataService->getSerpFilter($serp_filter, $request->getLocale()),
];
}
}
if(isset($localData["facts"]) && isset($localData["facts"]["electricity"]) && isset($localData["facts"]["electricity"]["sockets"])){
foreach ($localData["facts"]["electricity"]["sockets"] as &$socket){
$socket = [
"key" =>$socket,
"name" =>$this->staticDataService->getSocketType($socket, $request->getLocale()),
];
}
}
$wishlist = $this->em->getRepository(Wishlist::class)->findOneBy(["hotelId" => $localData["id"]]);
if(!empty($wishlist)){
$localData["wishlist"] = true;
} else {
$localData["wishlist"] = false;
}
$localData["link"] = $router->generate('app_detail_hotel_detail', ["id"=>$id, $params]);
return $localData;
}
public function testHotelPage(Request $request, $params){
$hotel = $this->getByHotelId($params["search"]["location"], $request->getLocale());
if(!empty($hotel)){
$localData = iterator_to_array($hotel[0]);
foreach ($localData["room_groups"] as &$roomGroup){
$roomGroup["images"] = $this->hotelImages($roomGroup["images"]);
}
$roomGroups = [];
unset($roomGroup);
foreach ($localData["room_groups"] as $roomGroup){
// foreach ($hotelData as $hotelDatum){
// if($hotelDatum["room_data_trans"]["main_name"] == $roomGroup["name_struct"]["main_name"] && $hotelDatum["room_data_trans"]["bedding_type"] == $roomGroup["name_struct"]["bedding_type"]){
// $roomGroup["rates"][] = $hotelDatum;
// $roomGroups[$roomGroup["room_group_id"]] = $roomGroup;
// }
// }
if(isset($roomGroup["room_amenities"])){
foreach ($roomGroup["room_amenities"] as &$room_amenity){
$name = $this->staticDataService->getRoomAmenity($room_amenity, $request->getLocale());
if(empty($name)){
continue;
}
$room_amenity = [
"key" =>$room_amenity,
"name" =>$this->staticDataService->getRoomAmenity($room_amenity, $request->getLocale()),
];
}
}
if(isset($roomGroup["rates"])){
foreach ($roomGroup["rates"] as &$rate){
if($rate["meal"] != "nomeal"){
$rate["meal"] = $this->staticDataService->getMeal($rate["meal"], $request->getLocale());
}
if(isset($rate["amenities_data"])){
foreach ($rate["amenities_data"] as &$rateAmenities){
$rateAmenities = [
"key" =>$rateAmenities,
"name" =>$this->staticDataService->getRoomAmenity($rateAmenities, $request->getLocale()),
];
}
}
}
}
}
$localData["room_groups"] = $roomGroups;
$localData["images"] = $this->hotelImages($localData["images"]);
if(isset($localData["serp_filters"])){
foreach ($localData["serp_filters"] as &$serp_filter){
$serp_filter = [
"key" =>$serp_filter,
"name" =>$this->staticDataService->getSerpFilter($serp_filter, $request->getLocale()),
];
}
}
if(isset($localData["facts"]) && isset($localData["facts"]["electricity"]) && isset($localData["facts"]["electricity"]["sockets"])){
foreach ($localData["facts"]["electricity"]["sockets"] as &$socket){
$socket = [
"key" =>$socket,
"name" =>$this->staticDataService->getSocketType($socket, $request->getLocale()),
];
}
}
return $localData;
}
}
public function guestsRoomsDaysCount(&$params){
$dateDiff = Helper::dateDiffInDays($params["search"]["checkin"], $params["search"]["checkout"]);
$roomsCount = count($params["search"]["guests"]);
$gustsCount = 0;
foreach ($params["search"]["guests"] as $room){
$adults = (int)$room["adults"];
if($room["children"][0] == "NaN"){
$children = 0;
} else {
$children = count($room["children"]);
}
$roomGusts = $adults + $children;
$gustsCount += $roomGusts;
}
$params["roomsCount"] = $roomsCount;
$params["guestsCount"] = $gustsCount;
$params["days"] = (int)$dateDiff;
}
public function featuredHotels($country){
/** @var Router $router */
$router = $this->container->get('router');
$collection = 'hotels_'.$this->request->getLocale();
$this->hm->select($collection);
$results = $this->hm->findBy(['$and' =>[["reviews.rating" => ['$gt' => 9]], ["star_rating"=>[ '$gt' => 4]]]],4);
$params = Helper::defaultSearchParams();
$params["search"]["residency"] = $country["cca2"];
$featuredHotels = [];
foreach ($results as $result){
$item["name"] = $result["name"];
if(!empty($result["images"]) && !empty($result["images"][0])){
$item["image"] = str_replace('{size}','240x240', $result["images"][0]);
}
$item["region"] = $result["region"]["name"];
$params["search"]["location"] = $result["region"]["id"];
$item["link"] = $router->generate('app_detail_hotel_detail', ["id"=>$result["id"], $params]);
$featuredHotels[] = $item;
}
return $featuredHotels;
}
public function randomHotels($country){
/** @var Router $router */
$router = $this->container->get('router');
$collection = 'hotels_'.$this->request->getLocale();
$this->hm->select($collection);
$results = $this->hm->findBy(['$and' =>[["reviews.rating" => ['$gt' => 5]], ["star_rating"=>[ '$gt' => 2]]]],100);
shuffle($results);
$params = Helper::defaultSearchParams();
$params["search"]["residency"] = $country["cca2"];
$featuredHotels = [];
foreach ($results as $ind=>$result){
if($ind > 4){
break;
}
$item["name"] = $result["name"];
if(!empty($result["images"]) && !empty($result["images"][0])){
$item["image"] = str_replace('{size}','240x240', $result["images"][0]);
}
$item["region"] = $result["region"]["name"];
$item["address"] = $result["address"];
$params["search"]["location"] = $result["region"]["id"];
$item["link"] = $router->generate('app_detail_hotel_detail', ["id"=>$result["id"], $params]);
$featuredHotels[] = $item;
}
return $featuredHotels;
}
private function getRequestParams(Request $request){
return array_merge($request->request->all(),$request->query->all());
}
public function hotelImages($images){
$resizedImages = [];
$sizes = [
'crop100' => '100x100',
'fit' => '1024x768',
'crop120' => '120x120',
'crop240' => '240x240',
'fit220' => 'x220',
'fit500' => 'x500',
];
foreach ($sizes as $key=>$size){
$item = [];
foreach ($images as $image){
if(empty($image)){
continue;
}
$resized = str_replace('{size}',$size, $image);
$item[] = $resized;
}
$resizedImages[$key] = $item;
}
return $resizedImages;
}
public function getHotelInfo($id, $language){
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://api.worldota.net/api/b2b/v3/hotel/info/',
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 =>'{
"id": "'.$id.'",
"language": "'.$language.'"
}',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
$res = [];
curl_close($curl);
$data = json_decode($response, true);
if($data["status"] == "ok"){
$res = $data["data"];
}
return $res;
}
}