<?php
namespace App\Controller;
use App\Service\CanonicalRedirectHelper;
use App\Service\FormHelper;
use App\Service\RecaptchaExtension;
use Carbon\Carbon;
use Elements\Bundle\HashCashBundle\Service\HashCashService;
use Knp\Component\Pager\PaginatorInterface;
use Pimcore\Translation\Translator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Pimcore\Model\DataObject;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Pimcore\Db;
class PackageController extends AbstractController
{
private Translator $translator;
private FormHelper $formHelper;
public function __construct(Translator $translator, FormHelper $formHelper) {
$this->translator = $translator;
$this->formHelper = $formHelper;
}
public function overviewAction(Request $request, PaginatorInterface $paginator)
{
$selectedRegion = null;
if ($this->document->getProperty('region') instanceof DataObject\Region && !$this->document->getProperty('region')->getIsMainRegion()) {
$selectedRegion = $this->document->getProperty('region')->getId();
}
$selectedRegion = $request->get("regions", $selectedRegion);
$regions = new DataObject\Region\Listing();
$regionsSelect = [[
"label" => "",
"value" => "",
"disabled" => true,
"selected" => $selectedRegion ? false : true,
"class" => "sr-only",
]];
foreach ($regions as $key => $region) {
$regionsSelect[] = [
"label" => $region->getName(),
"value" => $region->getId(),
"class" => "",
"selected" => $selectedRegion && $selectedRegion == $region->getId()
];
}
$condition = [];
$optionCategories = $baseCategories = [];
if($this->getDocumentEditable('relations', 'basecategories') && !empty($this->getDocumentEditable('relations', 'basecategories')->getData())) {
foreach($this->getDocumentEditable('relations', 'basecategories') as $basecategory) {
$baseCategories[$basecategory->getId()] = $basecategory->getId();
}
$allBaseCategoryIds = $this->getChildObjectIds($baseCategories, ['packageCategory'], true);
}
if($this->getDocumentEditable('relations', 'optioncategories') && !empty($this->getDocumentEditable('relations', 'optioncategories')->getData())) {
foreach($this->getDocumentEditable('relations', 'optioncategories') as $optioncategory) {
$optionCategories[$optioncategory->getId()] = $optioncategory;
}
}
$selectedCategory = $request->get("category");
$packageCategories = new DataObject\PackageCategory\Listing();
if(!empty($allBaseCategoryIds)) {
$packageCategories->addConditionParam('o_id IN (:ids)', ['ids' => $allBaseCategoryIds ]);
}
$packageCategories->setOrderKey('name');
$packageCategories->addConditionParam("name != '' ");
$categoriesSelect = [[
"label" => "",
"value" => "",
"disabled" => true,
"selected" => $selectedCategory == null,
"class" => "sr-only",
]];
foreach ($packageCategories as $key => $packageCategory) {
if(array_key_exists($packageCategory->getId(), $optionCategories) ){
$categoriesSelect[] = [
"label" => $packageCategory->getName(),
"value" => $packageCategory->getId(),
"class" => "",
"selected" => $selectedCategory && $selectedCategory == $packageCategory->getId()
];
}
}
$selectedPrice = $request->get('price');
$priceIntervals = $this->getDocumentEditable('input', 'priceintervals') != '' ? explode(',', $this->getDocumentEditable('input', 'priceintervals')) : [];
$priceRanges = $this->getPriceRanges($priceIntervals);
$priceSelect = [[
"label" => "",
"value" => "",
"disabled" => true,
"selected" => $selectedPrice == null,
"class" => "sr-only",
]];
foreach ($priceRanges as $key => $priceRange) {
if($priceRange['from'] != '' && $priceRange['to'] != '') {
$label = $priceRange['from'] . ' - ' . $priceRange['to'] . ' €';
} elseif($priceRange['from'] != '') {
$label = '> ' . $priceRange['from'] . ' €';
} elseif($priceRange['to'] != '') {
$label = '< ' . $priceRange['to'] . ' €';
}
$priceSelect[] = [
"label" => $label ?? '',
"value" => $key,
"class" => "",
"selected" => $selectedPrice && $selectedPrice == $key
];
}
$dateFrom = $request->get('from');
if($dateFrom) {
$dateFrom = Carbon::createFromFormat('Y-m-d H:i:s', str_replace('T', ' ', $request->get('from')) );
}
$dateTo = $request->get('to');
if($dateTo) {
$dateTo = Carbon::createFromFormat('Y-m-d H:i:s', str_replace('T', ' ', $request->get('to')) );
}
$offers = new DataObject\Package\Listing();
//alle 82, busreisen: 4, ys 1
$packageTypes = $this->getDocumentEditable('multiselect', 'packageTypes')->getData();
$packageSubQueries = [];
foreach ($packageTypes as $packageType) {
if($packageType === 'styriaPackages') {
$packageSubQueries[] = '(isBusTour is null OR isBusTour = 0) AND (isYoungStyria is null OR isYoungStyria = 0)';
} elseif($packageType === 'busTour') {
$packageSubQueries[] = 'isBusTour is not null AND isBusTour = 1';
} elseif($packageType === 'isYoungStyria') {
$packageSubQueries[] = 'isYoungStyria is not null AND isYoungStyria = 1';
}
}
if(!empty($packageSubQueries)) {
$offers->addConditionParam(implode(' OR ', $packageSubQueries));
}
if($selectedRegion && ($region = DataObject\Region::getById($selectedRegion))) {
$regionsAndCommunitiesIds = $this->getChildRegionAndCommunityIds($region, true);
$subRegionCondition = [];
foreach ($regionsAndCommunitiesIds as $id) {
$subRegionCondition[] = "regions LIKE '%,object|" . $id . ",%'";
}
if(!empty($subRegionCondition)) {
$offers->addConditionParam('('. implode(' OR ', $subRegionCondition) . ')');
}
}
if($selectedCategory) {
$offers->addConditionParam("categories LIKE :cat", ['cat' => '%,' . $selectedCategory . ',%']);
} elseif(!empty($allBaseCategoryIds)) {
$subconditions = [];
foreach($allBaseCategoryIds as $baseCategoryId) {
$subconditions[] = 'categories LIKE "%,' . $baseCategoryId . ',%"';
}
if(!empty($subconditions)) {
$offers->addConditionParam('(' . implode(' OR ', $subconditions) . ')');
}
}
$offerBeginDate = [];
$offerCount = 0;
if($this->getDocumentEditable('checkbox', 'datefilter')->isChecked() && $dateFrom && $dateFrom instanceof Carbon) {
#also considering the min. nights the guest has to stay
$offerBeginDate[] = '(beginDate <= ' . $dateFrom->getTimestamp() . ' OR beginDate >= ' . $dateFrom->getTimestamp() . ')';
$offerBeginDate[] = 'endDate >= ' . $dateFrom->getTimestamp();
}
if($this->getDocumentEditable('checkbox', 'datefilter')->isChecked() && $dateTo && $dateTo instanceof Carbon) {
#also considering the min. nights the guest has to stay
$offerBeginDate[] = 'beginDate <= ' . $dateTo->getTimestamp();
} else { // if no timerange is used => show only packages that are not in the past
$offerBeginDate[] = 'endDate >= ' . Carbon::now()->getTimestamp();
}
if(!empty($offerBeginDate)){
$packagePeriod = Db::get()->createQueryBuilder();
$packagePeriod->select('o_id')->from('object_collection_PackagePeriod_78')->where(implode(' AND ', $offerBeginDate));
$ids = $packagePeriod->execute()->fetchAll();
$ids = array_map(function($a){return $a['o_id'];}, $ids);
$offerCount = count($ids);
if($offerCount > 0) {
$offers->addConditionParam('o_id IN (' . implode(',', $ids) . ')');
}
}
if($selectedPrice) {
if($priceRanges[$selectedPrice]['from'] != '' && $priceRanges[$selectedPrice]['to'] != '') {
$offers->addConditionParam("price != '' and price >= :priceFrom and price <= :priceTo", ['priceFrom' => $priceRanges[$selectedPrice]['from'], 'priceTo' => $priceRanges[$selectedPrice]['to']]);
} elseif($priceRanges[$selectedPrice]['from'] != '' ) {
$offers->addConditionParam("price != '' and price > :priceFrom", ['priceFrom' => $priceRanges[$selectedPrice]['from']]);
} elseif($priceRanges[$selectedPrice]['to'] != '') {
$offers->addConditionParam("price != '' and price < :priceTo", ['priceTo' => $priceRanges[$selectedPrice]['to']]);
}
}
// p_r($offers->getCondition()); die();
$limit = (int) $this->getDocumentEditable('numeric', 'numTeasers')->getData();
if ($limit <= 0) {
$limit = 8;
}
if($this->getDocumentEditable('checkbox', 'randomize-package')->isChecked()) {
$offers->setOrderKey("Rand(" . Carbon::today()->unix() . ")", false);
}
if($offerCount == 0){
$offers = [];
}
$paginator = $paginator->paginate($offers, (int)$request->get('page',1), $limit);
$paginator->setPageRange(3);
if ($request->isXmlHttpRequest()) {
return $this->json([
'success' => true,
'html' => $this->renderView('Package/Includes/top-offers-list.html.twig', ['paginator' => $paginator])
]);
}
return $this->renderTemplate('Package/overview.html.twig', [
'regionsSelect' => $regionsSelect,
'packageCategories' => $categoriesSelect,
'paginator' => $paginator,
'top-offers' => $offers,
'priceSelect' => $priceSelect,
'dateTo' => $dateTo,
'dateFrom' => $dateFrom,
]);
}
public function detailAction(Request $request, HashCashService $hashCashService, CanonicalRedirectHelper $redirectHelper)
{
if($request->isMethod('post')) {
$res = $this->inquiry($request, $hashCashService);
if($res instanceof RedirectResponse) {
return $res;
}
}
$package = DataObject\Package::getById($request->get('id', 0));
if (!$package){
throw new NotFoundHttpException("the requested object doesn't exist anymore");
}
if (CanonicalRedirectHelper::ENABLE_CANONICAL_REDIRECT && $redirect = $redirectHelper->canonicalRedirect($package)) {
return $redirect;
}
$topicSelect = [[
"label" => "",
"value" => "",
"disabled" => true,
"selected" => true,
"class" => "sr-only",
]];
foreach ($package->getCategories() as $cat) {
$topicSelect[] = [
"label" => $cat->getName(),
"value" => $cat->getId(),
"class" => ""
];
}
$regionSelect = [[
"label" => "",
"value" => "",
"disabled" => true,
"selected" => true,
"class" => "sr-only",
]];
foreach ($package->getRegions() as $reg) {
$regionSelect[] = [
"label" => $reg->getName(),
"value" => $reg->getId(),
"class" => ""
];
}
$adultsSelect = [[
"label" => "",
"value" => "",
"disabled" => true,
"selected" => true,
"class" => "sr-only",
]];
$childrenSelect = [[
"label" => "",
"value" => "",
"disabled" => true,
"selected" => true,
"class" => "sr-only",
]];
for($i = 0; $i <= 10; $i++) {
$val = [
"label" => $i,
"value" => $i,
"class" => ""
];
if ($i > 0) $adultsSelect[] = $val;
$childrenSelect[] = $val;
}
return $this->renderTemplate('Package/detail.html.twig', [
'package' => $package,
'packageDates' => $this->getPackageDatesTK($package, $request->getLocale()),
'topicSelect' => $topicSelect,
'regionSelect' => $regionSelect,
'adultsSelect' => $adultsSelect,
'childrenSelect' => $childrenSelect,
'errors' => $res ?? []
]);
}
/**
* @Route("/contact-modal", name="contact-modal")
* @param Request $request
*/
private function inquiry(Request $request, HashCashService $hashCashService) {
$params = [];
// p_r($hashCashService->validateProcessFrom()); die();
if ($hashCashService->validateProcessFrom()) {
$requiredParams = [
'packageId',
'packageName',
'salutation',
'firstname',
'lastname',
'email',
'arrival',
'departure',
];
$package = DataObject\Package::getById($request->get('packageId'));
$optionalParams = [
'phone',
'title',
];
if($package->getIsBusTour()) {
$requiredParams[] = 'persons';
$optionalParams[] = 'doublerooms';
$optionalParams[] = 'singlerooms';
} else {
$requiredParams[] = 'adults';
$optionalParams[] = 'children';
}
$errors = [];
if(!$package) {
$errors[] = 'no valid package';
}
if($package->getEnableCategoriesInForm()) {
$requiredParams[] = 'topic';
}
if($package->getEnableRegionsInForm()) {
$requiredParams[] = 'region';
}
foreach ($requiredParams as $param) {
if (!$request->get($param, null)) {
$errors[] = $param;
continue;
}
$params[$param] = $request->get($param);
}
if(isset($params['salutation'])) {
$params['salutation'] = $this->translator->trans($params['salutation']);
}
foreach ($optionalParams as $param) {
if ($val = $request->get($param)) {
$params[$param] = $val;
}
}
if(array_key_exists('children', $params) && $params['children'] > 0) {
$params['childAge'] = $this->formHelper->getTranslatedChildAges($request->get('ca0', []));
}
$config = $this->document->getProperty('siteConfig');
if (!$config instanceof DataObject\SiteConfig) {
$errors[] = 'config';
}
} else {
$errors[] = 'hashcash not valid';
}
if(empty($errors)) {
$arrivalDate = Carbon::createFromFormat('Y-m-d H:i:s', str_replace('T', ' ', $params['arrival']));
$params['arrival'] = $arrivalDate ? $arrivalDate->format('d.m.Y') : null;
$departureDate = Carbon::createFromFormat('Y-m-d H:i:s', str_replace('T', ' ', $params['departure']));
$params['departure'] = $departureDate ? $departureDate->format('d.m.Y') : null;
$mailDoc = $config->getTopOffersMail();
$mailDocUser = $config->getTopOffersMailUser();
$successPage = $config->getTopOffersMailSuccessPage();
if($package->getIsBusTour()) {
if($config->getTopOffersMailBusTravel()) {
$mailDoc =$config->getTopOffersMailBusTravel();
}
if($config->getTopOffersMailUserBusTravel()) {
$mailDocUser = $config->getTopOffersMailUserBusTravel();
}
if($config->getTopOffersMailSuccessPageBusTravel()) {
$successPage = $config->getTopOffersMailSuccessPageBusTravel();
}
} elseif($package->getIsYoungStyria()) {
if($config->getTopOffersMailYoungStyria()) {
$mailDoc = $config->getTopOffersMailYoungStyria();
}
if($config->getTopOffersMailUserYoungStyria()) {
$mailDocUser = $config->getTopOffersMailUserYoungStyria();
}
if($config->getTopOffersMailSuccessPageYoungStyria()) {
$successPage = $config->getTopOffersMailSuccessPageYoungStyria();
}
}
if($mailDoc) {
$notification = new \Pimcore\Mail();
//default take from backend settings
if(!\Pimcore::inDebugMode() && $package = DataObject\Package::getById($request->get('packageId', 0))) {
if(($poi = $package->getPoi()) && ($mail = $package->getPoi()->getEmail())) {
$notification->addTo($mail);
}else{
if($mail = $package->getEmail()){
$notification->addTo($mail);
}
}
}
if ($package->getIsBusTour()){
$params['items'] = ['packageId', 'packageName', 'salutation', 'firstname', 'lastname', 'email', 'arrival', 'departure', 'persons', 'doublerooms', 'singlerooms', 'message'];
} else {
$params['items'] = ['packageId', 'packageName', 'salutation', 'firstname', 'lastname', 'email', 'arrival', 'departure', 'adults', 'childAge', 'message'];
}
$notification->setDocument($mailDoc);
$notification->setParams($params);
$notification->send();
} else {
$errors[] = 'mail admin';
}
if($mailDocUser) {
$notification = new \Pimcore\Mail();
if($package->getIsBusTour()){
$params['items'] = ['packageName', 'salutation', 'firstname', 'lastname', 'email', 'arrival', 'departure', 'persons', 'doublerooms', 'singlerooms', 'message'];
} else {
$params['items'] = ['packageName', 'salutation', 'firstname', 'lastname', 'email', 'arrival', 'departure', 'adults', 'childAge', 'message'];
}
$notification->setDocument($mailDocUser);
$notification->addTo($params['email']);
$notification->setParams($params);
$notification->send();
if($successPage = $config->getTopOffersMailSuccessPage()) {
return $this->redirect($successPage->getFullPath());
}
} else {
$errors[] = 'mail user';
}
if(empty($errors) && $successPage) {
return $this->redirect($successPage->getFullPath());
}
}
return $errors;
}
protected function getChildObjectIds($parentIds = [], $filterClasses = [], $includeParents = false) {
$return = [];
if(!empty($parentIds)) {
if($includeParents) {
$return = $parentIds;
}
$paths = [];
foreach($parentIds as $parentId) {
$_obj = \Pimcore\Model\DataObject::getById($parentId);
if ($_obj instanceof \Pimcore\Model\DataObject) {
$paths[] = $_obj->getFullPath();
}
}
if(!empty($paths)) {
$condition = [];
$subcondition = [];
foreach($paths as $path) {
$subcondition[] = 'o_path LIKE "'.$path.'/%"';
}
if(!empty($subcondition)) {
$condition[] = '(' . implode(' OR ', $subcondition) . ')';
}
if(!empty($filterClasses)) {
$subcondition = [];
foreach($filterClasses as $filterClass) {
$subcondition[] = 'o_className = "'.lcfirst($filterClass).'"';
}
$condition[] = '('.implode(' OR ', $subcondition).')';
}
if(!empty($condition)) {
$list = new \Pimcore\Model\DataObject\Listing();
$list->setCondition(implode(' AND ' , $condition));
}
foreach($list as $object) {
$return[] = $object->getId();
}
}
}
return array_unique($return);
}
private function getPriceRanges(array $priceIntervals = []) {
$normalizedIntervals = [];
foreach ($priceIntervals as $entry) {
$e = trim($entry);
if (is_numeric($e) && (int)$e != 0) {
$normalizedIntervals[] = (int)$e;
}
}
sort($normalizedIntervals);
$priceRanges = [];
$last = count($normalizedIntervals ?? []) - 1;
$preventry = 0;
foreach ($normalizedIntervals as $count => $entry) {
if ($count == 0) {
$priceRanges[$count + 1] = ['to' => $entry, 'from' => ''];
} else {
$priceRanges[$count + 1] = ['from' => $preventry, 'to' => $entry];
}
$preventry = $entry;
}
if ($preventry) {
$priceRanges[$count + 2] = ['from' => $preventry, 'to' => ''];
}
return $priceRanges;
}
protected function getChildRegionAndCommunityIds(\Pimcore\Model\DataObject\Region $region, $includeParent = false) {
$lifetime = 60*30; #30 minutes
$cacheKey = md5('region-'.$region->getId().($includeParent ? '-parent' : '-children'));
if(!$ids = \Pimcore\Cache::load($cacheKey)) {
try {
$ids = $includeParent ? [$region->getId()] : [];
$regionList = new \Pimcore\Model\DataObject\Region\Listing();
$regionList->setCondition('o_path LIKE "'.$region->getFullPath().'/%"');
foreach($regionList as $_region) {
$ids[] = $_region->getId();
}
$communityList = new \Pimcore\Model\DataObject\Community\Listing();
$communityList->setCondition('o_path LIKE "'.$region->getFullPath().'/%"');
foreach($communityList as $_community) {
$ids[] = $_community->getId();
}
\Pimcore\Cache::save(array_unique($ids), $cacheKey, array("output"), $lifetime);
} catch (\Exception $e) {
}
}
return $ids;
}
private function getPackageDatesTK(DataObject\Package $package, String $lang) : string {
$packageDates = [];
$first = true;
foreach($package->getPeriods() ?: [] as $period) {
if(Carbon::now()->lte($period->getEndDate()) ) {
$date = $period->getBeginDate()->format('d.m.Y') . ' - ' . $period->getEndDate()->format('d.m.Y');
if($first) {
$first = false;
$date = $this->translator->trans('package-detail.Gültig von: ', [], null, $lang) . ' '. $date;
}
$packageDates[] = $date ;
}
}
return !empty($packageDates) ? "<div>" . implode(",</div><div>", $packageDates) . "</div>" : "";
}
}