<?php
/**
* Elements DeMI
*
* This source file is available under the elements DeMI license version 1
*
* @copyright Copyright (c) elements.at New Media Solutions GmbH (https://www.elements.at/)
* @license elements DeMI Lizenz Version 1 (https://www.elements.at/de/demi-lizenz)
*/
namespace Elements\Bundle\DemiFrontendBundle\Controller;
use Carbon\Carbon;
use DateInterval;
use Elements\Bundle\CmsToolsBundle\Tool\Helper\ElementsCustomDateFormat;
use Elements\Bundle\DemiFrontendBundle\Event\DemiDirectInquiryEvent;
use Elements\Demi\Frontend\Service\Configuration;
use Elements\Bundle\DemiFrontendBundle\Service\ConnectedEntryProvider;
use Elements\Bundle\DemiFrontendBundle\Service\Customer;
use Elements\Bundle\DemiFrontendBundle\Service\DemiUrl;
use Elements\Bundle\DemiFrontendBundle\Service\Newsletter;
use Elements\Bundle\DemiFrontendBundle\Service\Payment;
use Elements\Bundle\DemiFrontendBundle\Service\SearchFrontend;
use Elements\Bundle\DemiFrontendBundle\Service\VacancyFrontend;
use Elements\Demi\AbstractObject;
use Elements\Demi\Accommodation\Search\Listing\VacancyLocal;
use Elements\Demi\Accommodation\Search\Parameter;
use Elements\Demi\Accommodation\Search\ResultSet;
use Elements\Demi\Accommodation\Search\Service\Vacancies\Corridor;
use Elements\Demi\CustomerFactory;
use Elements\Demi\Deskline\Accommodation\Search\Service\Vacancies\Live;
use Elements\Demi\Deskline\Config;
use Elements\Demi\Deskline\Constant\FacilityGroupTypeInterface;
use Elements\Demi\Deskline\Constant\LinkTypeInterface;
use Elements\Demi\Deskline\DSI\Request\AbstractService;
use Elements\Demi\Deskline\DSI\Request\BasicData\AvailabilityCalendar;
use Elements\Demi\Deskline\DSI\Service\ClickCount;
use Elements\Demi\Deskline\Exception;
use Elements\Demi\Deskline\Service\Search\PaymentInformation;
use Elements\Demi\Model\AccommodationProduct;
use Elements\Demi\Model\AccommodationServiceProvider;
use Elements\Demi\Model\Facility;
use Elements\Demi\Model\HousePackageContainer;
use Elements\Demi\Model\HousePackageMaster;
use Elements\Demi\Model\MealType;
use Elements\Demi\Model\Package;
use Error;
use Jaybizzle\CrawlerDetect\CrawlerDetect;
use Pimcore;
use Pimcore\Db;
use Pimcore\Mail;
use Pimcore\Model\DataObject;
use Pimcore\Templating\Renderer\IncludeRenderer;
use Pimcore\Tool;
use Pimcore\Tool\Authentication;
use Pimcore\Tool\DeviceDetector;
use Pimcore\Tool\Serialize;
use Pimcore\Translation\Translator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\GoneHttpException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class AccommodationController extends AbstractDemiController
{
protected array $enabledFeatures = [];
protected string $trustYouApiKey;
public function __construct(Configuration $demiConfigurationHelper, protected SearchFrontend $searchParams, protected VacancyFrontend $vacancyFrontend,
protected VacancyLocal $vacancyLocal, protected IncludeRenderer $renderer, protected ClickCount $clickCount, protected Corridor $corridor,
protected VacancyLocal $searchListCorridor, protected Live $vacancyLive, protected DemiUrl $demiUrl, protected PaymentInformation $paymentInfo, protected Customer $customerHelper,
protected CustomerFactory $customerFactory, protected Payment $paymentHelper, protected ConnectedEntryProvider $connectedEntryProvider, protected Translator $translator,
ElementsCustomDateFormat $elementsCustomDateFormat, protected Newsletter $newsletterHandler, ContainerInterface $container, protected SavingRequestController $savingRequestController, protected ?ValidatorInterface $emailValidator = null, array $enabledFeatures = null)
{
$this->setContainer($container);
$this->setConfiguration($demiConfigurationHelper);
$this->setElementsCustomDateFormat($elementsCustomDateFormat);
if (!is_array($enabledFeatures)) {
$this->enabledFeatures = $this->container->hasParameter("elements_demi.enabled_features") ? $this->container->getParameter("elements_demi.enabled_features") : [];
} else {
$this->enabledFeatures = $enabledFeatures;
}
if ($emailValidator === null) {
$this->emailValidator = $this->container->get('validator.email');
}
if ($this->container->hasParameter('elements_demi.trustYou.apiKey')) {
$this->trustYouApiKey = $this->container->getParameter('elements_demi.trustYou.apiKey');
}
}
public function fidDirectLinkAction(Request $request, string $guiid): RedirectResponse
{
if (preg_match('/[a-f0-9\-]+/', $guiid)) {
$serviceProvider = AccommodationServiceProvider::getByFid($guiid);
$redirect = $this->needsRedirectToCorrectUrl($request, $serviceProvider);
if ($redirect !== '') {
return $this->redirect($redirect, 301);
}
}
throw new GoneHttpException('Not found');
}
protected function redirectAccos(Request $request) : Response|bool
{
$accoId = $request->get('id');
$packageId = $request->get('pid');
if(\Pimcore\Model\Site::isSiteRequest()) {
$site = \Pimcore\Model\Site::getCurrentSite();
$targetDoc = $site->getRootDocument()->getProperty('demi_redirectTargetDocId');
if($targetDoc){
if(!empty($packageId)){
//set portal start document to get correct demi config later
$this->configuration->setDocument($targetDoc);
$mappingArrayPackages = $this->getMappingArray('HousePackageMasterMapping_Site_'.$site->getId());
$mappingArrayAccos = $this->getMappingArray('AccommodationServiceProviderMapping_Site_'.$site->getId());
$fid = $mappingArrayAccos[$accoId];
$pfid = $mappingArrayPackages[$packageId];
if (!empty($fid) && !empty($pfid)) {
$housePackageMaster = HousePackageMaster::getByFid($pfid,1);
$acco = AccommodationServiceProvider::getByFid($fid,1);
if ($acco && $housePackageMaster) {
$urlHelper = $this->demiUrl;
$params = [
'accommodation' => $acco,
'package' => $housePackageMaster
];
$correctPath = $urlHelper->__invoke($params, 'demi_acco_detail_package_page', true);
return $this->redirect($correctPath, 301);
}
}
return $this->redirect($this->configuration->getAccoParentDocument()->getFullPath(), 301);
} else {
//set portal start document to get correct demi config later
$this->configuration->setDocument($targetDoc);
$mappingArray = $this->getMappingArray('AccommodationServiceProviderMapping_Site_'.$site->getId());
if ($fid = $mappingArray[$accoId]) {
$acco = AccommodationServiceProvider::getByFid($fid,1);
if ($acco) {
$urlHelper = $this->demiUrl;
$params = [
'accommodation' => $acco,
];
$route = 'demi_acco_detail_page';
$reset = true;
$correctPath = $urlHelper->__invoke($params, $route, $reset);
return $this->redirect($correctPath, 301);
}
}
return $this->redirect($this->configuration->getAccoParentDocument()->getFullPath(), 301);
}
}
}
return false;
}
public function detailAction(Request $request, int $id, UserInterface $user = null)
{
//portal redirects for domains moving to steiermark.com
$redirectAccos = $this->redirectAccos($request);
if ($redirectAccos) {
return $redirectAccos;
}
$this->configuration->setDocument($this->document);
try {
$accommodation = DataObject\DemiAccommodationServiceProvider::getById($id);
$viewParams = $this->getAccommodationData($request, $id);
} catch (GoneHttpException $exception) {
//before running in to unavailable we could implement redirects for same domain
//not needed currently; use RedirectController::redirectAccoAction if required again
if($accommodation && !$accommodation->isPublished() && $accommodation->getProperty('feratelId')){
return $this->forward(self::class. '::redirectViaFeratelIdProperty', [
'request' => $request,
'object' => $accommodation,
'demiUrl' => $this->demiUrl
]);
}
return $this->forward(self::class. '::unavailableAction', [
'request' => $request
]);
}
$crawlerDetect = new CrawlerDetect();
if($crawlerDetect->isCrawler()){
$params = $request->query->all();
if(!empty($params)){
$canonical = $this->demiUrl->invoke(['accommodation'=>$accommodation],'demi_acco_detail_page',true);
file_put_contents(DEMI_LOG_PATH . '/blocked_crawler_request.log', "[" . Carbon::now()->format("Y-m-d H:i:s") . "] " . $crawlerDetect->getMatches(). ": " . $request->getRequestUri() .PHP_EOL, FILE_APPEND | LOCK_EX);
//bye, bye crawler
$this->redirect($canonical,303);
}
}
$redirect = $this->needsRedirectToCorrectUrl($request, $accommodation);
if ($redirect !== '') {
return $this->redirect($redirect, 301);
}
if ($redirect = $this->needsTimeStringRedirect($request)) {
return $this->redirect($redirect, 301);
}
$viewParams['isAffiliate'] = $this->setIsAffiliate();
$viewParams['trustYouApiKey'] = $this->trustYouApiKey;
/**
* @var $searchParams Parameter
*/
$ignorePrice = $request->get('enquire') || $request->get('enquirySuccess');
$searchParams = $this->searchParams->getSearchParam(null, $ignorePrice);
$viewParams['user'] = $user;
$viewParams['searchParam'] = $searchParams;
$searchParams->setAccoIds([$id]);
if ($request->get('enquire')) {
$success = $this->sendEnquire($request, $id, $searchParams, $user);
if ($success) {
$queryString = $request->getQueryString();
$queryString = str_replace('enquire', 'enquirySuccess', $queryString);
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
return $this->redirect($request->getPathInfo() . '/enquire?'.$queryString);
}
throw new Exception('can not sent enquiry - dsi saving request was not successful');
}
if ($request->get('enquirySuccess')) {
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$document = $this->configuration->getEnquireThankYouPage();
$request->query->remove('enquirySuccess');
return new Response($this->renderer->render($document, ['id' => $id]));
}
$viewParams['accommodationResultSet'] = $this->vacancyFrontend->getAccommodationResultSetLocal($searchParams,
$id);
$productSearchParams = clone $searchParams;
$productSearchParams->setSearchType(Parameter::SEARCH_TYPE_EACH_PRODUCT_SEPARATED);
$productSearchParams->setProductType('Accommodation');
$viewParams['productResultSet'] = $this->vacancyFrontend->getAccommodationResultSetLocal($productSearchParams,
$id);
if (!$searchParams->getDateFrom()) {
$viewParams['packages'] = $this->vacancyFrontend->preparePackageMasters($accommodation,
$this->vacancyLocal);
}
if ($this->enabledFeatures['destinationPackages'] ?? false) {
$packages = \Elements\Demi\Accommodation\Search\Listing\Package::getPackagesOfferedByAccommodation($accommodation, $searchParams);
if (count($packages)) {
//get rid of published packages in the past
$packages = $this->searchParams->filterDestinationPackagesDate($packages, Carbon::now(), null);
}
$viewParams['destinationPackages'] = $packages;
} else {
$viewParams['destinationPackages'] = null;
}
$housePackageMasters = $accommodation->getHousePackageMasters();
//check if Accommodation has packages
$hasPackageValidDates = false;
foreach ($housePackageMasters as $housePackageMaster) {
$validDates = $housePackageMaster->getValidDates();
if ($validDates instanceof DataObject\Fieldcollection) {
$dates = $validDates->getItems();
if (is_array($dates) && count($dates) > 0) {
foreach ($dates as $item) {
if ($item->getTo()->getTimestamp() > time()) {
$hasPackageValidDates = true;
break 2;
}
}
}
}
}
$viewParams['connectedEntries'] = $this->connectedEntryProvider->getConnectedEntriesForAcco($accommodation, $request);
$viewParams['hasHousePackages'] = $hasPackageValidDates;
$viewParams['availabilityIsChecked'] = !$searchParams->isNoDate();
$viewParams['activeTab'] = $request->get('activeTab');
$viewParams['googleMapsKey'] = Pimcore\Config::getSystemConfiguration()['services']['google']['browser_api_key'] ?? Pimcore\Config::getSystemConfiguration()['services']['google']['simple_api_key'];
$viewParams['showJsonLd'] = count($_GET) == 0;
$deviceDetector = Tool\DeviceDetector ::getInstance();
$device = $deviceDetector->isPhone() ? 'mobile' : 'desktop';
$path = $viewParams['isAffiliate'] ? 'Affiliate' : 'Accommodation';
return $this->renderTemplate('@ElementsDemiFrontend/'.$path.'/detail.'.$device.'.html.twig', $viewParams);
}
public function destinationpackageAction(Request $request, int $id, int $pid, UserInterface $user = null): Response
{
$object = Package::getById($pid);
$accommodation = AccommodationServiceProvider::getById($request->get('id'));
if (!$object || !$object->isPublished() || !$accommodation->isPublished()) {
return $this->forward(self::class. '::unavailableAction', [
'request' => $request
]);
}
$redirect = $this->needsRedirectToCorrectUrl($request, $accommodation, $object);
if ($redirect !== '') {
return $this->redirect($redirect);
}
if ($object->getValidDates()) {
$endDate = null;
foreach ($object->getValidDates()->getItems() as $item) {
if ($endDate == null) {
$endDate = $item->getDateTo();
} elseif ($endDate->lt($item->getDateTo())) {
$endDate = $item->getDateTo();
}
}
if ($endDate != null) {
$endDate = $endDate->endOfDay()->toRfc850String();
$this->addResponseHeader('X-Robots-Tag', 'unavailable_after: ' . $endDate);
}
}
/**
* @var $searchParams Parameter
*/
$searchParams = $this->searchParams->getPackageSearchParam(null, $this->editmode);
if ($request->get('enquire')) {
//TODO Enquiry is in AccommodationController ... maybe move detail to Accommodation Controller? @msteyer: Is irrelevant?
$this->sendEnquire($request, $id, $searchParams, $user);
return $this->redirect($request->getPathInfo() . '/enquire?enquirySuccess=true');
}
if ($request->get('enquirySuccess')) {
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$document = $this->configuration->getEnquireThankYouPage();
$request->query->remove('enquirySuccess');
return new Response($this->renderer->render($document, ['id' => $id, 'pid' => $pid]));
}
$viewParams = $this->getAccommodationData($request, $id, $pid);
if (!isset($_COOKIE['pimcore_admin_sid']) && !$object->isPublished() && !$this->editmode && !$request->get('pimcore_object_preview')) {
throw new GoneHttpException('Not found');
}
$viewParams['trustYouApiKey'] = $this->trustYouApiKey;
$viewParams['searchParam'] = $searchParams;
$viewParams['user'] = $user;
$viewParams['tvbPackage'] = $object;
$viewParams['availabilityIsChecked'] = ($searchParams->getDateFrom() != null);
$viewParams['activeTab'] = $request->get('activeTab');
$viewParams['googleMapsKey'] = Pimcore\Config::getSystemConfiguration()['services']['google']['browser_api_key'] ?? Pimcore\Config::getSystemConfiguration()['services']['google']['simple_api_key'];
$viewParams['showJsonLd'] = count($_GET) === 0;
$deviceDetector = Tool\DeviceDetector ::getInstance();
$device = $deviceDetector->isPhone() ? 'mobile' : 'desktop';
return $this->renderTemplate('@ElementsDemiFrontend/Accommodation/destinationpackage.'.$device.'.html.twig', $viewParams);
}
public function packageAction(Request $request, int $id, int $pid, UserInterface $user = null): Response
{
//portal redirects for domains moving to steiermark.com
$redirectAccos = $this->redirectAccos($request);
if ($redirectAccos) {
return $redirectAccos;
}
$object = HousePackageMaster::getById($pid);
$accommodation = AccommodationServiceProvider::getById($request->get('id'));
if ($accommodation === null || $object === null || !$object->isPublished() || !$accommodation->isPublished()) {
//before running in to unavailable we could implement redirects for same domain
//not needed currently; use RedirectController::redirectHousepackageAction if required again
return $this->forward(self::class. '::unavailableAction', [
'request' => $request
]);
}
$queryBuilder = Db::getConnection()->createQueryBuilder();
$queryBuilder->select('o_id from object_' . DataObject\DemiHousePackageContainer::classId())
->where('o_id in (select src_id from object_relations_' . DataObject\DemiHousePackageContainer::classId() . " where
dest_id in (select dest_id from object_relations_{$object::classId()} where src_id = $pid) and fieldname = 'products')");
$res = $queryBuilder->execute()->fetchAll();
if (!empty($res)) {
$hpc = HousePackageContainer::getById(reset($res)['o_id']);
if ($hpc instanceof HousePackageContainer) {
$viewParams['housePackageContainer'] = $hpc;
}
}
$redirect = $this->needsRedirectToCorrectUrl($request, $accommodation, $object);
if ($redirect !== '') {
return $this->redirect($redirect, 301);
}
if ($redirect = $this->needsTimeStringRedirect($request)) {
return $this->redirect($redirect, 301);
}
if ($object->getValidDates()) {
$endDate = null;
foreach ($object->getValidDates()->getItems() as $item) {
if ($endDate === null) {
$endDate = $item->getTo();
} elseif ($endDate->lt($item->getTo())) {
$endDate = $item->getTo();
}
}
if ($endDate !== null) {
$endDate = $endDate->endOfDay()->toRfc850String();
$this->addResponseHeader('X-Robots-Tag', 'unavailable_after: ' . $endDate);
}
}
$ignorePrice = $request->get('enquire') || $request->get('enquirySuccess');
$searchParams = $this->searchParams->getSearchParam(null, $ignorePrice);
if ($request->get('enquire')) {
$this->sendEnquire($request, $id, $searchParams, $user);
return $this->redirect($request->getPathInfo() . '/enquire?enquirySuccess=true');
}
if ($request->get('enquirySuccess')) {
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$document = $this->configuration->getEnquireThankYouPage();
$request->query->remove('enquirySuccess');
return new Response($this->renderer->render($document, ['id' => $id, 'pid' => $pid]));
}
$viewParams = $this->getAccommodationData($request, $id);
if ((!isset($_COOKIE['pimcore_admin_sid']) && !$this->editmode && !$object->isPublished() && !$request->get('pimcore_object_preview'))) {
throw new GoneHttpException('Not found');
}
$viewParams['trustYouApiKey'] = $this->trustYouApiKey;
$viewParams['isAffiliate'] = $this->setIsAffiliate();
$viewParams['searchParam'] = $searchParams;
$viewParams['user'] = $user;
$viewParams['housePackageMaster'] = $object;
$viewParams['availabilityIsChecked'] = !$searchParams->isNoDate();
$this->vacancyLocal->setParameter($searchParams);
$resultSet = $this->vacancyFrontend->preparePackageMasters($accommodation,
$this->vacancyLocal, $object);
$viewParams['housePackageResultSet'] = $resultSet;
$viewParams['activeTab'] = $request->get('activeTab');
$viewParams['useLts'] = false;
$viewParams['googleMapsKey'] = Pimcore\Config::getSystemConfiguration()['services']['google']['browser_api_key'] ?? Pimcore\Config::getSystemConfiguration()['services']['google']['browser_api_key'] ?? null;
$viewParams['showJsonLd'] = empty($request->query->all());
$deviceDetector = Tool\DeviceDetector ::getInstance();
$device = $deviceDetector?->isPhone() ? 'mobile' : 'desktop';
$path = $viewParams['isAffiliate'] ? 'Affiliate' : 'Accommodation';
return $this->renderTemplate('@ElementsDemiFrontend/'.$path.'/package.'.$device.'.html.twig', $viewParams);
}
private function getAccommodationData(Request $request, int $id, int $pid = null): array
{
$object = AccommodationServiceProvider::getById($id);
if ($object === null || (!isset($_COOKIE['pimcore_admin_sid']) && !$object->isPublished() && !$this->editmode && !$request->get('pimcore_object_preview'))) {
throw new GoneHttpException('Not found');
}
$user = Authentication::authenticateSession();
$activePimcoreUser = false;
if ($user) {
$activePimcoreUser = true;
}
if ($object instanceof AccommodationServiceProvider) {
if ($object->getIsTesthotel() && !(Pimcore::inDebugMode() || $activePimcoreUser)) {
throw new GoneHttpException('Not found');
}
Config::setClientKeyOverrideFromObject($object);
}
$viewParams['countingClicksUriJs'] = $this->clickCount->getClickCountUrl($object);
$viewParams['accommodation'] = $object;
// Marketinggroups
$marketingGroups = $object->getMarketingGroups();
uasort($marketingGroups, function ($a, $b) {
return $a->getOrder() < $b->getOrder();
});
foreach ($marketingGroups as $i => $iValue) {
//remove MarketingGroups which should not be shown on web
if (!$iValue->getShowOnWeb()) {
unset($marketingGroups[$i]);
}
}
$viewParams['sortedMarketingGroups'] = $marketingGroups;
// Facilities
$facilities = $object->getFacilities();
$sortedFacilities = [];
$sortedHealthMeasures = [];
if ($facilities !== null) {
foreach ($facilities as $facilityItem) {
$facility = $facilityItem->getFacility();
if ($facility instanceof Facility) {
$facGroup = $facility->getFacilityGroup();
if ($facGroup) {
if ($facGroup->getFacilityGroupType() == FacilityGroupTypeInterface::FACILITY_GROUP_TYPE_HEALTH) {
if (!isset($sortedHealthMeasures[$facGroup->getId()])) {
$data = [
'name' => $facGroup->getName(),
'keyname' => $facGroup->getDemiIconClass(),
'facilities' => []
];
$sortedHealthMeasures[$facGroup->getId()] = $data;
}
} elseif (!isset($sortedFacilities[$facGroup->getId()])) {
$data = [
'name' => $facGroup->getName(),
'keyname' => $facGroup->getDemiIconClass(),
'facilities' => []
];
$sortedFacilities[$facGroup->getId()] = $data;
}
$facName = $facility->getName();
if ($facility->getValueType() === 'IntDigit') {
$facName .= ': ' . $facilityItem->getFacilityValue();
}
if ($facGroup->getFacilityGroupType() == FacilityGroupTypeInterface::FACILITY_GROUP_TYPE_HEALTH) {
$sortedHealthMeasures[$facGroup->getId()]['facilities'][] = $facName;
} else {
$sortedFacilities[$facGroup->getId()]['facilities'][] = $facName;
}
}
}
}
}
//sort alphabetically within facility group - tosc does the same
if (!empty($sortedFacilities)) {
foreach ($sortedFacilities as $facilities) {
sort($facilities['facilities']);
}
}
$viewParams['sortedHealthMeasures'] = $sortedHealthMeasures;
$viewParams['sortedFacilities'] = $sortedFacilities;
// Impressionen
$panoLinks = $object->demiGetLinks([LinkTypeInterface::DESKLINE_LINK_PANO]);
$types = [LinkTypeInterface::DESKLINE_LINK_VIDEO_EMBED, LinkTypeInterface::DESKLINE_LINK_VIDEO, LinkTypeInterface::DESKLINE_LINK_VIDEO_VIMEO];
$videoLinks = $object->demiGetLinks($types);
if ($pid && $package = Package::getById($pid)) {
$panoLinks = array_merge($panoLinks, $package->demiGetLinks([LinkTypeInterface::DESKLINE_LINK_PANO]));
$videoLinks = array_merge($videoLinks, $package->demiGetLinks($types));
}
$linkGroups = [
'video' => $videoLinks,
'pano' => $panoLinks
];
$viewParams['impressionLinks'] = $linkGroups;
// Links
$accoLinks = $object->demiGetLinks([
LinkTypeInterface::DESKLINE_LINK_URL,
LinkTypeInterface::DESKLINE_LINK_NOTDEFINED
]);
$viewParams['accoLinks'] = $accoLinks;
$viewParams['showAvailablityCalendar'] = $this->enabledFeatures['availabilityCalenderRooms'] ?? false;
return $viewParams;
}
private function sendEnquire(Request $request, int $id, Parameter $searchParams, UserInterface $user = null): bool
{
if ($this->configuration->getDisableEnquiry()) {
return false; // Just return since detailEnquireAction is called from detailAction
}
$this->configuration->getEnquireMailServiceProvider();
$housePackageId = $request->get('pid');
/** @var AccommodationServiceProvider $acco */
$acco = AccommodationServiceProvider::getById($id);
if ($housePackageId) {
$package = HousePackageMaster::getById($housePackageId);
} else {
$package = null;
}
// date
$defaultFrom = $request->get('from-no-date') ? $this->elementsCustomDateFormat->stringToCarbon($request->get('from-no-date')) : new Carbon();
$defaultTo = $request->get('to-no-date') ? $this->elementsCustomDateFormat->stringToCarbon($request->get('to-no-date')) : new Carbon();
$fromDate = empty($request->get('from')) ? $defaultFrom : $this->elementsCustomDateFormat->stringToCarbon($request->get('from'));
$toDate = empty($request->get('to')) ? $defaultTo : $this->elementsCustomDateFormat->stringToCarbon($request->get('to'));
//nights
$nightsFromParam = $searchParams->getNights();
if (count($nightsFromParam) > 1) {
$nights = $nightsFromParam[0].'-'.$nightsFromParam[count($nightsFromParam) - 1];
$nightsForDSI = $nightsFromParam[0];
} else {
$nights = $toDate->diff($fromDate)->days;
$nightsForDSI = $toDate->diff($fromDate)->days;
}
$request->query->set('nights', $nights);
$request->query->set('from', ElementsCustomDateFormat::toString($fromDate));
$request->query->set('to', ElementsCustomDateFormat::toString($toDate));
$mailParams = $request->request->all();
$mailParams['salutation'] = AbstractObject::getById($mailParams['salutation']) ? AbstractObject::getById($mailParams['salutation'])->getTitle() : '';
$mailParams['from'] = $request->get('from');
$mailParams['to'] = $request->get('to');
$filteredKeys = array_filter(array_keys($mailParams), function ($key) {
return !str_starts_with($key, '_');
});
$mailParams = array_intersect_key($mailParams, array_flip($filteredKeys));
$this->emailValidator->validate($mailParams['email'], new Email());
$roomRows = $request->get('roomRow');
$products = [];
if ($roomRows) {
foreach ($roomRows as $key => $roomRow) {
$pid = $request->get('productId')[$key];
$mealCode = $request->get('mealCode')[$key];
$units = $request->get('count') ? $request->get('count')[$key] : 1;
$products[] = ['id' => $pid, 'mealCode' => $mealCode, 'units' => $units, 'roomRowKey' => $roomRow];
}
}
//privacy policy is no longer a checkbox
/*
if (!empty($this->configuration->getPrivacyPolicyEnquiry())) {
$ppAccepted = (bool)$request->get('pp');
} else {
$ppAccepted = true;
}
*/
//just assume ppAccepted, it no longer exists
$ppAccepted=true;
if ($this->configuration->getUseDSI()) {
$request->query->set('nights', $nightsForDSI);
$request->query->set('accoIds', [$id]);
$request->query->set('pp', $ppAccepted);
$request->query->set('price', null);
$productIds = $request->get('productId');
$request->query->set('comment', $this->getCommentForDSIEnquiry($request, $package, $products, $nightsFromParam));
if ($productIds == null || (count($productIds) > 1)) {
$request->query->set('productId', []);
} else {
$request->query->set('productId', reset($productIds));
}
$mailSent = $this->savingRequestController->serviceProviderRequestAction($request, $user);
} else {
$mailSent = $this->sendEnquireMail($mailParams, $searchParams, $request, $acco, $package, $products, $ppAccepted, false);
if ($mailSent && $this->newsletterHandler && $request->get('newsletter') === 'on') {
try {
//handle newsletter subscripton
$emptyCustomer = null;
$this->newsletterHandler->addRecipient($request->get('email'), $request->get('firstname'), $request->get('surname'), ['request' => $request], $emptyCustomer, $emptyCustomer);
} catch (\Exception $exception) {
if (Pimcore::inDebugMode()) {
//silently ignore newsletter subscription errors in live mode, show them in debug
throw $exception;
}
}
}
}
try {
$eventDispatcher = Pimcore::getEventDispatcher();
$eventDispatcher->dispatch(new DemiDirectInquiryEvent($searchParams, $request, []), DemiDirectInquiryEvent::POST_DIRECTINQUIRY_EVENT);
} catch (Error $e) {
}
return $mailSent;
}
/**
* @param Request $request
* @param $package
* @param $products
* @param $nights
*
* @return mixed|string
*/
private function getCommentForDSIEnquiry(Request $request, null|HousePackageMaster|HousePackageContainer|Package $package, array $products, int|array $nights): mixed
{
$comment = $request->get('comment');
if ($package !== null) {
$comment .= ', Package ' . $package->getName() . ':';
}
foreach ($products as $productInfo) {
$product = AbstractObject::getById($productInfo['id']);
$mealType = MealType::getById($productInfo['mealCode']);
$units = $productInfo['units'];
if ($product) {
$prodStr = '';
if ($units) {
$prodStr .= $units . 'x ';
}
$prodStr .= $product->getName();
if ($mealType) {
$prodStr .= ' | ' . $mealType->getText();
}
$comment .= $prodStr;
}
}
if ($request->get('tel')) {
$comment .= ', Tel.: '.$request->get('tel');
}
if (is_array($nights) && count($nights) > 1) {
$comment .= ", {$this->translator->trans('demi.nights')}: {$nights[0]} - {$nights[count($nights) - 1]}";
}
return $comment;
}
private function sendEnquireMail($mailParams, $searchParams, $request, $acco, $package, $products, $ppAccepted, $mailSent)
{
try {
$spamBotAddress = $request->get('address');
$mailParams['nights'] = $request->get('nights');
if (empty($spamBotAddress) && $ppAccepted) {
if ($this->configuration->getEnquireMailServiceProvider() != '') {
$fallback = $this->configuration->getEnquiryServiceProviderFallback();
$alwaysUseFallback = $this->configuration->getUseEnquiryServiceProviderFallbackAsOverride();
//sending the email
$mail = new Mail(null, null, null);
if (Tool::getClientIp() == $this->testIp) {
if ($request->get('email')) {
$mail->addTo($request->get('email'));
} else {
$mail->addTo('anna.huber.elements@gmail.com');
}
$mail->disableLogging();
} elseif (!$alwaysUseFallback && $acco->getAddress() && $acco->getAddress()->getEmail()) {
$mail->addTo(trim($acco->getAddress()->getEmail()));
} elseif ($fallback != '') {
$fallbacks = explode(',', $fallback);
foreach ($fallbacks as $fallback) {
$mail->addTo($fallback);
}
} else {
throw new Exception("can not sent enquiry - no email on acco {$acco->getId()} and no property demi_enquiryServiceProviderFallback !");
}
$mail->addReplyTo($request->get('email'));
$mail->setDocument($this->configuration->getEnquireMailServiceProvider());
$mail->setParams($mailParams);
$mail->setParam('searchParam', $searchParams);
$mail->setParam('acco', $acco);
$mail->setParam('package', $package);
$mail->setParam('products', $products);
// $this->logEnquire($acco);
$mail->send();
$mailSent = true;
} else {
throw new Exception("missing property on enquiryServiceProvider {$this->document}!");
}
if ($this->configuration->getEnquireCustomer() != '') {
//sending the email
$customerMail = new Mail(null, null, null, 'utf-8');
$customerMail->addTo($request->get('email'));
$customerMail->setDocument($this->configuration->getEnquireCustomer());
$customerMail->setParams($mailParams);
$customerMail->setParam('searchParam', $searchParams);
$customerMail->setParam('acco', $acco);
$customerMail->setParam('package', $package);
$customerMail->setParam('products', $products);
if (Tool::getClientIp() == $this->testIp) {
$customerMail->disableLogging();
}
$customerMail->send();
}
}
} catch (\Exception $e) {
$mail = new Mail(null, null, null);
$mail->setSubject('Fehler direktanfrage ');
$mail->addTo('deskline@elements.at');
$mail->text($e->getMessage());
$mail->send();
}
return $mailSent;
}
public function accommodationTeaserCompactAction(Request $request): Response
{
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$accoId = $request->get('id');
if (!$accoId) {
return new Response('no id given');
}
$searchParams = $this->searchParams->getSearchParam(null, false, false);
$searchParams->setAccoIds([$accoId]);
$productType = Parameter::PRODUCT_TYPE_ACCOMMODATION;
if ($searchParams->getSearchType() == Parameter::SEARCH_TYPE_ONE_PRODUCT_PER_PACKAGE) {
$productType = Parameter::PRODUCT_TYPE_PACKAGE;
}
if ($searchParams->getIsCorridor()) {
$this->searchListCorridor->setParameter($searchParams);
$accommodations = $this->searchListCorridor->getResultSet()->getAccommodations();
$resultSet = reset($accommodations);
} else {
$resultSet = $this->vacancyFrontend->getAccommodationResultSetLocal($searchParams,
$accoId, $productType);
}
$viewParams['accommodationResult'] = $resultSet;
$viewParams['accommodation'] = AccommodationServiceProvider::getById($accoId);
$viewParams['searchParam'] = $searchParams;
$viewParams['noDate'] = $searchParams->isNoDate();
$viewParams['freeCancellationInList'] = $this->enabledFeatures['freeCancellationInList'];
$device = DeviceDetector::getInstance()->isPhone() ? 'mobile' : 'desktop';
return $this->renderTemplate('@ElementsDemiFrontend/Accommodation/accommodationTeaserCompact.'.$device.'.html.twig', $viewParams);
}
public function lightboxTopbarContentAction(Request $request): Response
{
if ($request->get('tid')) {
return $this->forward(DestinationPackageController::class . '::lightboxTopbarContentAction', [
'request' => $request
]);
}
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$accoId = trim($request->get('id'));
$accommodation = AccommodationServiceProvider::getById($accoId);
$searchParams = $this->searchParams->getSearchParam(null, false);
$searchParams->setAccoIds([$accoId]);
$productType = Parameter::PRODUCT_TYPE_ACCOMMODATION;
if ($searchParams->getSearchType() == Parameter::SEARCH_TYPE_ONE_PRODUCT_PER_PACKAGE) {
$productType = Parameter::PRODUCT_TYPE_PACKAGE;
}
if ($searchParams->getIsCorridor()) {
$this->searchListCorridor->setParameter($searchParams);
$accommodationsCorridor = $this->searchListCorridor->getResultSet()->getAccommodations();
$resultSet = reset($accommodationsCorridor);
} elseif ($searchParams->getSearchType() == Parameter::SEARCH_TYPE_ONE_PRODUCT_PER_PACKAGE || !empty($request->get('pid'))) {
$housePackageMaster = HousePackageMaster::getById((int)$request->get('pid'));
if ($searchParams->getDateFrom() && $searchParams->getDateTo()) {
$this->vacancyLive->setSearchParameter($searchParams);
$resultSet = ResultSet\Accommodation::getById($accoId, $this->vacancyLive);
} else {
$this->vacancyLocal->setParameter($searchParams);
$resultSet = $this->vacancyFrontend->preparePackageMasters($accommodation,
$this->vacancyLocal, $housePackageMaster, false);
}
} elseif ($searchParams->getDateFrom() && $searchParams->getDateTo()) {
$adapter = $this->vacancyLive;
$adapter->setSearchParameter($searchParams);
$resultSet = ResultSet\Accommodation::getById($accoId, $adapter);
} elseif ($accommodation) {
$resultSet = $this->vacancyFrontend->getAccommodationResultSetLocal($searchParams,
$accoId, $productType);
}
$viewParams['accommodationResult'] = is_array($resultSet) ? reset($resultSet) : $resultSet;
$viewParams['accommodation'] = $accommodation;
$viewParams['housePackageMaster'] = $housePackageMaster ?? null;
$viewParams['searchParam'] = $searchParams;
$viewParams['noDate'] = $searchParams->isNoDate();
$viewParams['availabilityIsChecked'] = !$searchParams->isNoDate();
$viewParams['isList'] = $request->get('viewType') === 'list';
$viewParams['isPackageDetailPage'] = $request->get('viewType') === 'package';
return $this->renderTemplate('@ElementsDemiFrontend/Accommodation/lightboxTopbarContent.html.twig', $viewParams);
}
public function ajaxAction(Request $request): Response
{
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$accoId = $request->get('id');
$accommodation = AccommodationServiceProvider::getById((int)$accoId);
if (!$request->isXmlHttpRequest() || $accommodation === null || (!isset($_COOKIE['pimcore_admin_sid']) && !$accommodation->isPublished() && !$this->editmode && !$request->get('pimcore_object_preview'))) {
throw new GoneHttpException('Not found');
}
$packageId = $request->get('pid');
if ($packageId && Package::getById($packageId)) {
//we are dealing with TVB Package -> go to DestinationPackageController
return $this->forward(DestinationPackageController::class . '::ajaxAction', [
'request' => $request
]);
}
$requestType = $request->get('ajaxRequestType');
return match ($requestType) {
'getProductByIdAndMealcode' => $this->forward(self::class . '::ajaxGetProductByIdAndMealcodeAction', [
'request' => $request
]),
'getPaymentInformation' => $this->forward(self::class . '::ajaxGetPaymentInformationAction', [
'request' => $request
]),
'getLiveDetailProducts' => $this->forward(self::class . '::ajaxGetLiveDetailProductsAction', [
'request' => $request,
'isAffiliate' => $this->setIsAffiliate()
]),
'getCorridorMatrix' => $this->forward(self::class . '::ajaxGetCorridorMatrixAction', [
'request' => $request
]),
'getAvailabilityCalendar' => $this->forward(self::class . '::ajaxGetAvailabilityCalendarAction', [
'request' => $request
]),
default => throw new GoneHttpException('Not found - no matching request type'),
};
}
public function ajaxGetAvailabilityCalendarAction(Request $request): JsonResponse
{
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$months = $request->get('months') ? (int) $request->get('months') : 3;
$product = null;
if ($request->get('productId')) {
$product = AccommodationProduct::getById($request->get('productId'));
}
$accoId = $request->get('id');
$accommodation = AccommodationServiceProvider::getById($accoId);
if ($accommodation === null || (!isset($_COOKIE['pimcore_admin_sid']) && !$accommodation->isPublished() && !$this->editmode && !$request->get('pimcore_object_preview'))) {
throw new GoneHttpException('Not found');
}
Config::setClientKeyOverrideFromObject($accommodation);
$startDate = new Carbon();
if ($request->get('startDate')) {
$dateFormatHelper = new ElementsCustomDateFormat();
$startDate = $dateFormatHelper->stringToCarbon($request->get('startDate'));
} else {
$startDate->setDate($startDate->year, $startDate->month, 1);
}
try {
$dsiRequest = new AvailabilityCalendar(Config::getInstance(), Config::getInstance()->getSalesChannel(), $startDate, $months, $accommodation, $product);
$requestService = AbstractService::getService();
$responseXml = $requestService->makeRequest($dsiRequest, AbstractService::REQUEST_TYPE_AVAILABILITY_CALENDAR, false);
$data = [];
foreach ($responseXml->AvailabilityCalendar->AV as $dateEntry) {
$lineData = explode(',', $dateEntry);
$availablity = (int)$lineData[1];
$data[] = [
'date' => $lineData[0] . 'T00:00:00',
'availability' => max($availablity, 0),
'minStay' => $lineData[2],
'maxStay' => $lineData[3],
'intervall' => $lineData[4],
'arrival' => $lineData[5],
'departure' => $lineData[6]
];
}
} catch (Exception $desklineException) {
//no availabilities results in Exception. That is ok - return array with empty availabilities
$data = [];
$from = $startDate;
$to = clone $startDate;
$to->addMonths(3);
while($from <= $to) {
$data[] = [
'date' => $from->format('Y-m-d') . 'T00:00:00',
'availability' => 0,
'minStay' => 0,
'maxStay' => 0,
'intervall' => 0,
'arrival' => 0,
'departure' => 0
];
$from->addDay();
}
return $this->json($data);
}
return $this->json($data);
}
public function ajaxGetLiveDetailProductsAction(Request $request, bool $isAffiliate = false): JsonResponse
{
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$productArray = [];
$packageArray = [];
$isPackage = false;
$accoId = $request->get('id');
$accommodation = AccommodationServiceProvider::getById((int)$accoId);
$pId = $request->get('pid');
$housePackageMaster = HousePackageMaster::getById($pId);
$useCancellationInfo = isset($this->enabledFeatures['freeCancellationInList']);
$searchParams = $this->searchParams->getSearchParam(null, false);
$orderKey = $searchParams->getOrderKey();
$searchParams->setOrderKey(array_diff(is_string($orderKey) ? [$orderKey] : $orderKey, ['custom', 'nearbySearchAsc']));
$searchParams->setAccoIds([$accoId]);
if ($housePackageMaster) {
$packageProductIds = [];
foreach ($housePackageMaster->getProducts() as $accommodationProduct) {
$packageProductIds[] = $accommodationProduct->getId();
}
$searchParams->setProductIds($packageProductIds);
$isPackage = true;
}
$adapter = $this->vacancyLive;
$adapter->setSearchParameter($searchParams);
$accommodationResultSet = ResultSet\Accommodation::getById($accoId, $adapter);
if (($accommodationResultSet && count($accommodationResultSet->getProducts()) > 0)) {
$splitData = $this->vacancyFrontend->splitProductsAndPackages($accommodationResultSet);
$productArray = $splitData['products'];
$packageArray = $splitData['packages'];
}
$fromCorridorSearch = $request->get('corridor') == 1;
$nightsMappings = $this->configuration->getVariableNightMappings();
//only do alternative search detail page if there ist a nights mapping present
if ($nightsMappings && !$fromCorridorSearch && (!$accommodationResultSet || count($accommodationResultSet->getProducts()) < 1)) {
//no rooms found - initiate corridor search
$alternativeSeachParams = $this->getAlternativeSearchParams($searchParams, 7, 7);
$dayDiff = $alternativeSeachParams->getDateFrom()->diff($alternativeSeachParams->getDateTo());
$period = $dayDiff->format('%a');
$alternativeSeachParams->setPeriod($period);
$this->corridor->setSearchParameter($alternativeSeachParams);
$alternativeAccommodationResultSet = ResultSet\Accommodation::getById($accoId, $this->corridor);
if ($housePackageMaster && $alternativeAccommodationResultSet) {
$alternativeAccommodationResultSet = new ResultSet\HousePackageMaster($accoId, $alternativeAccommodationResultSet->getRoomRows(), $pId, $alternativeAccommodationResultSet);
}
}
if ($housePackageMaster) {
if (array_key_exists($housePackageMaster->getId(), $packageArray) && is_array($packageArray[$housePackageMaster->getId()]) && count($packageArray[$housePackageMaster->getId()]) == 0) {
$error = $this->searchParams->getSearchError($searchParams);
}
$renderedProductsData = $this->renderTemplate('@ElementsDemiFrontend/Accommodation/accommodationProductList.html.twig',
[
'accommodationResultSet' => $accommodationResultSet,
'alternativeResultSet' => $alternativeAccommodationResultSet ?? null,
'alternativeSearchParameter' => $alternativeSeachParams ?? null,
'accommodation' => $accommodation,
'searchParam' => $searchParams,
'productArray' => array_key_exists($housePackageMaster->getId(), $packageArray) ? $packageArray[$housePackageMaster->getId()] : [],
'error' => $error ?? null,
'isAffiliate' => $isAffiliate,
'tvbPackage' => null,
'fromCorridor' => $fromCorridorSearch,
'useCancellationInfo' => $useCancellationInfo
]);
} else {
if (count($productArray) == 0) {
$error = $this->searchParams->getSearchError($searchParams);
}
$renderedProductsData = $this->renderTemplate('@ElementsDemiFrontend/Accommodation/accommodationProductList.html.twig',
[
'accommodationResultSet' => $accommodationResultSet,
'alternativeResultSet' => $alternativeAccommodationResultSet ?? null,
'alternativeSearchParameter' => $alternativeSeachParams ?? null,
'accommodation' => $accommodation,
'searchParam' => $searchParams,
'productArray' => $productArray,
'error' => $error ?? null,
'isAffiliate' => $isAffiliate,
'fromCorridor' => $fromCorridorSearch,
'useCancellationInfo' => $useCancellationInfo,
'tvbPackage' => null
]);
if (count($packageArray) == 0) {
$error = $this->searchParams->getSearchError($searchParams);
}
if ($this->enabledFeatures['destinationPackages'] && $request->get('corridor') != 1) {
$destinationPackages = \Elements\Demi\Accommodation\Search\Listing\Package::getPackagesOfferedByAccommodation($accommodation, $searchParams);
} else {
$destinationPackages = null;
}
$renderedPackagesData = $this->renderTemplate('@ElementsDemiFrontend/Accommodation/accommodationPackagesList.html.twig',
[
'accommodationResultSet' => $accommodationResultSet,
'accommodation' => $accommodation,
'searchParam' => $searchParams,
'packageArray' => $packageArray,
'error' => $error ?? null,
'isAffiliate' => $isAffiliate,
'destinationPackages' => $destinationPackages
]);
}
$deviceDetector = Tool\DeviceDetector ::getInstance();
$template = '@ElementsDemiFrontend/Accommodation/searchInfoBox.desktop.html.twig';
if ($deviceDetector->isPhone()) {
$template = '@ElementsDemiFrontend/Accommodation/searchInfoBox.mobile.html.twig';
} else {
$renderedSearchInfoCompact = $this->renderTemplate('@ElementsDemiFrontend/Accommodation/searchInfoBoxCompact.desktop.html.twig',
[
'accommodationResultSet' => $accommodationResultSet,
'accommodation' => $accommodation,
'isPackage' => $isPackage,
'availabilityIsChecked' => !$searchParams->isNoDate(),
'useCancellationInfo' => $useCancellationInfo
]);
}
$renderedSearchInfoBox = $this->renderTemplate($template,
[
'accommodationResultSet' => $accommodationResultSet,
'alternativeResultSet' => $alternativeAccommodationResultSet ?? null,
'alternativeSearchParameter' => $alternativeSeachParams ?? null,
'accommodation' => $accommodation,
'isPackage' => $isPackage,
'availabilityIsChecked' => !$searchParams->isNoDate(),
'useCancellationInfo' => $useCancellationInfo
]);
//TODO @msteyrer minprice hast to be minprice rooms !
$priceObject = $this->paymentHelper->getPriceObject($accommodationResultSet ? $accommodationResultSet->getMinPrice() : 0, $accommodation);
$matches = [];
preg_match('@[0-9.|,]+@', (string) $priceObject, $matches);
$minPriceString = $matches[0];
$data = [
'status' => 'success',
'availabilityUnits' => isset($splitData['jsonArray']) ? $splitData['jsonArray'] : '',
'html_rooms' => $renderedProductsData->getContent(),
'html_packages' => isset($renderedPackagesData) ? $renderedPackagesData->getContent() : '',
'html_searchInfo' => $renderedSearchInfoBox->getContent(),
'html_searchInfoCompact' => isset($renderedSearchInfoCompact) ? $renderedSearchInfoCompact->getContent() : '',
'minPriceRooms' => $minPriceString
];
return new JsonResponse($data);
}
public function ajaxGetCorridorMatrixAction(Request $request): JsonResponse
{
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$isPackage = false;
$accoId = $request->get('id');
$accommodation = AccommodationServiceProvider::getById((int)$accoId);
$pId = $request->get('pid');
$searchParams = $this->searchParams->getSearchParam();
$searchParams->setAccoIds([$accoId]);
$dateFrom = $searchParams->getDateFrom();
$minDate = $request->get('minDate');
$data = [];
$corridor = $this->corridor;
$nrOfDays = $this->configuration->getCorridorMatrixDays();
$nights = $this->searchParams->getNightsFromRequest($request);
if ($minDate) {
//user is navigating in corridor Matrix
$dateFrom = ElementsCustomDateFormat::parseDateString($request->get('minDate'));
$minDateRooms = $dateFrom;
$newSearchParams = clone $searchParams;
$newSearchParams->setDateFrom($minDateRooms);
$dateTo = clone $dateFrom;
if ($nights[count($nights) - 1] > $nrOfDays) {
$dateTo->add(new DateInterval('P'.$nights[count($nights) - 1].'D'));
} else {
$dateTo->add(new DateInterval('P'.$nrOfDays.'D'));
}
$newSearchParams->setDateTo($dateTo);
$searchParams = $newSearchParams;
}
$corridor->setSearchParameter($searchParams);
$accommodationResultSet = ResultSet\Accommodation::getById($accoId, $corridor);
if (!empty($pId) && $accommodationResultSet) {
$accommodationResultSet = new ResultSet\HousePackageMaster($accoId, $accommodationResultSet->getRoomRows(), $pId, $accommodationResultSet);
}
$roomsFound = false;
$packagesFound = false;
if ($accommodationResultSet) {
$minDateRooms = $accommodationResultSet->getMinDateFrom($dateFrom, Parameter::PRODUCT_TYPE_ACCOMMODATION);
$minDatePackages = $accommodationResultSet->getMinDateFrom($dateFrom, Parameter::PRODUCT_TYPE_PACKAGE);
foreach ($accommodationResultSet->getProducts() as $resultSetProduct) {
if ($resultSetProduct->getProductType() == Parameter::PRODUCT_TYPE_ACCOMMODATION) {
$roomsFound = true;
} elseif ($resultSetProduct->getProductType() == Parameter::PRODUCT_TYPE_PACKAGE) {
$packagesFound = true;
}
}
} else {
$minDateRooms = $minDatePackages = $dateFrom;
}
if (!$roomsFound) {
$alternativeSeachParams = $this->getAlternativeSearchParams($searchParams, 7, 7);
}
if ($pId) {
$isPackage = true;
if (!$minDateRooms) {
$minDateRooms = $minDatePackages;
}
}
$corridorMatrixEmpty = $this->vacancyFrontend->getCorridorMatrix($accoId, $minDateRooms, $nrOfDays, $searchParams,
$nights, 'Accommodation', true);
$corridorMatrixSetRooms = $corridorMatrixEmpty;
if ($minDateRooms) {
if ($request->get('activeTab') === 'package') {
//Packages Tab is open, use mindate from packages for both
$minDateRooms = $minDatePackages;
}
if ($roomsFound) {
$corridorMatrixSetRooms = $this->vacancyFrontend->getCorridorMatrix($accoId, $minDateRooms, $nrOfDays, $searchParams,
$nights);
}
}
$corridorMatrixSetPackages = $corridorMatrixEmpty;
if ($minDatePackages) {
if ($request->get('activeTab') === 'rooms') {
//Packages Tab is open, use mindate from rooms for both
$minDatePackages = $minDateRooms;
}
if ($packagesFound) {
$corridorMatrixSetPackages = $this->vacancyFrontend->getCorridorMatrix($accoId, $minDatePackages, $nrOfDays,
$searchParams,
$nights, 'Package');
}
}
$data['status'] = 'success';
$data['rooms'] = $corridorMatrixSetRooms;
if ($isPackage) {
$data['rooms'] = $corridorMatrixSetPackages;
}
$data['packages'] = $corridorMatrixSetPackages;
if (!$minDate && !$roomsFound && !$packagesFound) {
$this->corridor->setSearchParameter($alternativeSeachParams);
$alternativeResultSet = ResultSet\Accommodation::getById($accoId, $this->corridor);
if (!empty($pId) && $alternativeResultSet) {
$alternativeResultSet = new ResultSet\HousePackageMaster($accoId, $alternativeResultSet->getRoomRows(), $pId, $alternativeResultSet);
}
if ($alternativeResultSet && $alternativeResultSet->getMinPrice()) {
$deviceDetector = Tool\DeviceDetector ::getInstance();
$template = '@ElementsDemiFrontend/Accommodation/includes/alternative-room-results.desktop.html.twig';
if ($deviceDetector->isPhone()) {
$template = '@ElementsDemiFrontend/Accommodation/includes/alternative-room-results.mobile.html.twig';
}
$renderedHtml = $this->renderView($template,
[
'alternativeResultSet' => $alternativeResultSet,
'alternativeSearchParameter' => $alternativeSeachParams,
'accommodation' => $accommodation,
]);
} else {
$inAffiliate = str_contains($request->attributes->get('_route'), 'affiliate');
$renderedHtml = $this->renderView('@ElementsDemiFrontend/Accommodation/includes/nothing-found.html.twig',
['accommodation' => $accommodation, 'showAllRoomsLink' => true, 'isAffiliate' => $inAffiliate]);
}
$data['html_noRooms'] = $data['html_noPackages'] = $renderedHtml;
} elseif (!$minDate && !$roomsFound && $packagesFound) {
$data['html_noRooms'] = $this->renderView('@ElementsDemiFrontend/Accommodation/includes/hint-other-tab.html.twig',
[
'targetTab' => 'packages',
'textTk' => 'demi.detail.hint-to-package-tab-text',
'buttonTk' => 'demi.detail.hint-to-package-tab-button'
]);
} elseif (!$minDate && $roomsFound && !$packagesFound) {
$data['html_noPackages'] = $this->renderView('@ElementsDemiFrontend/Accommodation/includes/hint-other-tab.html.twig',
[
'targetTab' => 'rooms',
'textTk' => 'demi.detail.hint-to-room-tab-text',
'buttonTk' => 'demi.detail.hint-to-room-tab-button'
]);
}
$deviceDetector = Tool\DeviceDetector ::getInstance();
$template = '@ElementsDemiFrontend/Accommodation/searchInfoBox.desktop.html.twig';
if ($deviceDetector->isPhone()) {
$template = '@ElementsDemiFrontend/Accommodation/searchInfoBox.mobile.html.twig';
} else {
$renderedSearchInfoCompact = $this->renderView('@ElementsDemiFrontend/Accommodation/searchInfoBoxCompact.desktop.html.twig',
[
'accommodationResultSet' => $accommodationResultSet,
'alternativeResultSet' => $alternativeResultSet ?? null,
'alternativeSearchParameter' => $alternativeSeachParams ?? null,
'accommodation' => $accommodation,
'isPackage' => $isPackage,
'isCorridor' => true
]);
$data['html_searchInfoCompact'] = $renderedSearchInfoCompact;
}
$renderedSearchInfoBox = $this->renderView($template,
[
'accommodationResultSet' => $accommodationResultSet,
'alternativeResultSet' => $alternativeResultSet ?? null,
'alternativeSearchParameter' => $alternativeSeachParams ?? null,
'accommodation' => $accommodation,
'isPackage' => $isPackage,
'isCorridor' => true
]);
$data['html_searchInfo'] = $renderedSearchInfoBox;
return $this->json($data);
}
public function ajaxGetProductByIdAndMealcodeAction(Request $request): JsonResponse
{
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$productId = $request->get('productId');
$mealcode = $request->get('mealcode');
$roomindex = $request->get('roomindex');
$searchParams = $this->searchParams->getSearchParam($roomindex);
$searchParams->setProductIds([$productId]);
$searchParams->setMealType($mealcode);
$searchParams->setClassifications([]);
$searchParams->setStars([]);
$p = AccommodationProduct::getById($productId);
if ($p && $p->getParent()) {
$acco = $p->getParent()->getParent();
}
if ($acco instanceof AccommodationServiceProvider) {
Config::setClientKeyOverrideFromObject($acco);
}
$this->vacancyLive->setSearchParameter($searchParams);
/**
* @var ResultSet\Product $productSet
*/
try {
$productSet = ResultSet\Product::getByIdAndMealcode($productId, $mealcode, $this->vacancyLive);
} catch (\Exception $exception) {
if (Pimcore::inDebugMode()) {
throw $exception;
}
throw new GoneHttpException('ajax request failed');
}
if ($productSet) {
$roomRows = $searchParams->getRoomrows();
$renderedPriceDetail = $this->renderView('@ElementsDemiFrontend/Includes/productPriceInfo.html.twig',
[
'productSet' => $productSet,
'roomRow' => $roomRows[0],
'searchParam' => $searchParams
]);
$priceBeforeSpecial = '';
if ($productSet->getPriceData() && $productSet->getPriceData()->getPriceBeforeSpecial() > $productSet->getPrice()) {
$priceBeforeSpecial = $productSet->getPriceData()->getPriceBeforeSpecial();
}
$jsonArray =
[
'status' => 'success',
'price' => $productSet->getPrice(),
'priceBeforeSpecial' => $priceBeforeSpecial,
'priceDetailHtml' => $renderedPriceDetail
];
} else {
$jsonArray = ['status' => 'failed'];
}
return $this->json($jsonArray);
}
public function ajaxGetPaymentInformationAction(Request $request): Response
{
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$accoId = $request->get('id');
$acco = AccommodationServiceProvider::getById($accoId);
$productId = $request->get('productId');
$product = AccommodationProduct::getById($productId);
$roomRowIndex = $request->get('roomindex');
$viewParams['bookOnRequest'] = $request->get('bookonrequest') == '1';
$params = $this->searchParams->getSearchParam($roomRowIndex);
$roomRows = $params->getRoomrows();
$roomRow = reset($roomRows);
if (!$roomRow) {
throw new GoneHttpException('incomplete ajax request - roomrow not found');
}
$viewParams['paymentInfo'] = $this->paymentInfo->getPaymentInformation($acco,
$product, $acco->getDbcode(), null, $params->getDateFrom(), $params->getDateTo(), $roomRow->getAdults(),
$roomRow->getChildAges());
return $this->renderTemplate('@ElementsDemiFrontend/Accommodation/ajaxGetPaymentInformation.html.twig', $viewParams);
}
protected function needsRedirectToCorrectUrl(Request $request, AccommodationServiceProvider $accommodation, Package|HousePackageMaster|HousePackageContainer $package = null) : string
{
$urlHelper = $this->demiUrl;
$currentPath = $request->getPathInfo();
if ($package instanceof Package) {
$routeName = 'demi_acco_detail_tvbpackage_page';
} else {
$routeName = $package ? 'demi_acco_detail_package_page' : 'demi_acco_detail_page';
}
$params = [
'accommodation' => $accommodation,
];
if ($package) {
$params['package'] = $package;
}
$reset = true;
if ($request->get('keepParams')) {
$reset = false;
$request->query->remove('keepParams');
$request->query->remove('guiid');
$request->query->set('ref', $request->getPathInfo());
}
$correctPath = $urlHelper->invoke($params, $routeName, $reset);
if ($request->get('enquirySuccess')) {
return '';
}
if ($currentPath != $correctPath) {
return $correctPath;
}
return '';
}
protected function setIsAffiliate() : bool
{
return false;
}
protected function getMappingArray(string $type): array
{
$mappingFile = __DIR__ .'/../Resources/RedirectIdMapping' . '/'.$type;
if (!file_exists($mappingFile)) {
throw new NotFoundHttpException('DeMI Redirect failed - mapping file '.$mappingFile.' missing');
}
return Serialize::unserialize(file_get_contents($mappingFile));
}
}