<?php
namespace App\Controller;
use App\Service\CanonicalRedirectHelper;
use App\Twig\LinkGenerator;
use Elements\Bundle\AlpsteinBundle\Services\AlpsteinConfig;
use Elements\Bundle\CmsToolsBundle\Tool\Helper\FunctionsHelper;
use Knp\Component\Pager\PaginatorInterface;
use Pimcore\Model\DataObject;
use Pimcore\Model\DataObject\AlpsteinCategory;
use Pimcore\Model\DataObject\AlpsteinRegion;
use Pimcore\Model\DataObject\AlpsteinTour;
use Pimcore\Model\DataObject\Region;
use Pimcore\Model\Document\Editable;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
class TourController extends AbstractController
{
public function overviewAction(Request $request, PaginatorInterface $paginator)
{
$viewParams = [];
// Load Kategorien
$alpsteinFiltering = new AlpsteinTour\Listing();
$alpsteinFiltering->addConditionParam("name != '' AND name IS NOT NULL");
// caching filterdata using a file in private var folder. not sure why pimcore cache doesn't work here. it hits some kind of limit of 50 elements in cache
// also this way the generation of filter data can be outsources to a command
$filename = PIMCORE_PRIVATE_VAR . '/tourFilterData-Cache-' . $request->getLocale() . '.json';
if (file_exists($filename) && filemtime($filename) > strtotime('-1 day') && !$request->get('cache-new')) {
$filteringData = json_decode(file_get_contents($filename), true);
} else {
$filteringData = [];
}
if (empty($filteringData)) {
$filteringData = [
'length' => [
'min' => 0.0,
'max' => 0.0
],
'duration' => [
'min' => 0.0,
'max' => 0.0
],
'altitude' => [
'min' => 0.0,
'max' => 0.0
],
'categories' => [],
'regions' => []
];
foreach( $alpsteinFiltering as $tour ){
// get All Filters
// Length
$length = ( (float)$tour->getLength() / 1000) + 1;
if( $filteringData['length']['max'] < $length ){
$filteringData['length']['max'] = number_format( $length, 1, '.', '' );
}
// Duration
$duration = (int)($tour->getTimeMin()/60) + 1;
if( $filteringData['duration']['max'] < $duration ){
$filteringData['duration']['max'] = $duration;
}
// Altitude
$altitude = (int)$tour->getElevationAscent();
if( $filteringData['altitude']['max'] < $altitude ){
$filteringData['altitude']['max'] = $altitude;
}
// Categories
foreach( $tour->getCategory() as $cat ){
if( $cat instanceof AlpsteinCategory ){
$filteringData['categories'][$cat->getId()] = [
'id' => $cat->getId(),
'name' => $cat->getName()
];
}
}
}
asort( $filteringData['categories'] );
// Regions
$regions = new Region\Listing();
$regions->addConditionParam('alpsteinRegions != "" AND alpsteinRegions IS NOT NULL');
$regions->setOrderKey('sorting');
foreach($regions as $region) {
$filteringData['regions'][$region->getId()] = [
'id' => $region->getId(),
'name' => $region->getName()
];
}
file_put_contents($filename, json_encode($filteringData));
}
// Filter Ergebnis
$tourListing = new AlpsteinTour\Listing();
$tourListing->addConditionParam("name != '' AND name IS NOT NULL");
/** @var Editable\Numeric $qsEditable */
$qsEditable = $this->getDocumentEditable('numeric', 'qs');
// disable for now --> should be reactivated when ranking is filled in every tour
// if (!$qsEditable->isEmpty()) {
// $tourListing->addConditionParam("ranking >= " . $qsEditable->getData());
// }
// Prefilter Region/Tour Type
/** @var AlpsteinRegion[] $regions */
if ($regions = $this->getDocumentEditable('relations', 'regions')) {
$regionsCond = [];
foreach ($regions as $region) {
if ($region instanceof Region) {
foreach ($region->getAlpsteinRegions() ?: [] as $alpsteinRegion) {
// not needed as alpstein adds all regions and subregions to tour
// foreach (self::getAllSubRegionIds($alpsteinRegion) ?: [] as $subRegionId) {
// $regionsCond[] = 'regions LIKE "%,' . $subRegionId . ',%"';
// }
$regionsCond[] = 'regions LIKE "%,' . $alpsteinRegion->getId() . ',%"';
}
} else if ($region instanceof AlpsteinRegion) {
foreach (self::getAllSubRegionIds($region) ?: [] as $subRegionId) {
$regionsCond[] = 'regions LIKE "%,' . $subRegionId . ',%"';
}
$regionsCond[] = 'regions LIKE "%,' . $region->getId() . ',%"';
}
}
if (!empty($regionsCond)) {
$tourListing->addConditionParam('(' . implode(' OR ', $regionsCond) . ')');
}
}
/** @var AlpsteinCategory[] $categories */
$filteringData['childCategories'] = [];
if ($categories = $this->getDocumentEditable('relations', 'categories')) {
$categoriesCond = [];
foreach ($categories as $category) {
foreach ($category->getChildren() ?: [] as $childCategory) {
if ($childCategory instanceof AlpsteinCategory) {
$categoriesCond[] = 'category LIKE "%,' . $childCategory->getId() . ',%"';
$filteringData['childCategories'][] = $childCategory;
}
}
$categoriesCond[] = 'category LIKE "%,' . $category->getId() . ',%"';
}
if (!empty($categoriesCond)) {
$tourListing->addConditionParam('(' . implode(' OR ', $categoriesCond) . ')');
}
}
if ($community = DataObject\Community::getById($request->get('community'))) {
$viewParams['community'] = $community;
$functionsHelper = new FunctionsHelper();
if (false) { // seems to be more acurate than radius search because radius search only considers starting point
$communityCond = [];
foreach ($community->getAlpsteinObjects() ?: [] as $alpsteinRegion) {
if ($alpsteinRegion instanceof DataObject\AlpsteinCommunity) {
$communityCond[] = 'communities LIKE "%,' . $alpsteinRegion->getId() . ',%"';
} else if ($alpsteinRegion instanceof AlpsteinRegion) {
$communityCond[] = 'regions LIKE "%,' . $alpsteinRegion->getId() . ',%"';
}
}
if (!empty($communityCond)) {
$tourListing->addConditionParam('(' . implode(' OR ', $communityCond) . ')');
}
} else if (!empty($community->getDetailRelatedTours())) {
$ids = [];
foreach($community->getDetailRelatedTours() as $relatedTour) {
$ids[] = $relatedTour->getId();
}
if (!empty($ids)) {
$tourListing->addConditionParam('o_id IN (' . implode(',', $ids) . ')');
}
} else {
$radius = $community->getDetailRadiusTour() ?: 10;
$tourListing->addConditionParam($functionsHelper->getGeoDistanceQuery(new DataObject\Data\GeoCoordinates($community->getGeoposition()->getLatitude(), $community->getGeoposition()->getLongitude()), 'startingPoint') . ' <= ' . $radius);
}
}
// Filter Keyword
if( $request->get('tourKeyword') ){
$tourListing->addConditionParam('name LIKE :keyword', [ 'keyword' => '%' . $request->get('tourKeyword') . '%' ]);
}
// Filter Public Transport Friendly
if ($request->get('publicTransportFriendly')) {
$tourListing->addConditionParam('IFNULL(publicTransportFriendly, 0) = 1');
}
// Filter Categories
if( $request->get('tourCategory', 0) && $request->get('tourCategory') != 'all' ){
$category = AlpsteinCategory::getById($request->get('tourCategory'));
if ($category instanceof AlpsteinCategory) {
$categoriesCond = [];
foreach ($category->getChildren() ?: [] as $childCategory) {
if ($childCategory instanceof AlpsteinCategory) {
$categoriesCond[] = 'category LIKE "%,' . $childCategory->getId() . ',%"';
}
}
$categoriesCond[] = 'category LIKE "%,' . $category->getId() . ',%"';
if (!empty($categoriesCond)) {
$tourListing->addConditionParam('(' . implode(' OR ', $categoriesCond) . ')');
}
}
$tourListing->addConditionParam('category LIKE :catId', [ 'catId' => '%,' . $request->get('tourCategory') . ',%' ]);
}
// Filter Difficulty
if( $request->get('tourDifficulty', 0) && $request->get('tourDifficulty') != 'all' ){
$tourListing->addConditionParam('ratingDifficulty = :difficulty', [ 'difficulty' => $request->get('tourDifficulty') ]);
}
// Filter Startpunkt
if( $request->get('tourStart', 0) && $request->get('tourStart') != 'all' ){
$tourListing->addConditionParam('startingPointDesc = :tourStart', [ 'tourStart' => $request->get('tourStart') ]);
}
// Filter Region
if( $request->get('tourRegion', 0) && $request->get('tourRegion') != 'all' ){
$region = DataObject::getById($request->get('tourRegion'));
$regionsCond = [];
if ($region instanceof Region) {
foreach ($region->getAlpsteinRegions() ?: [] as $alpsteinRegion) {
$regionsCond[] = 'regions LIKE "%,' . $alpsteinRegion->getId() . ',%"';
}
} else if ($region instanceof AlpsteinRegion) {
foreach (self::getAllSubRegionIds($region) ?: [] as $subRegionId) {
$regionsCond[] = 'regions LIKE "%,' . $subRegionId . ',%"';
}
$regionsCond[] = 'regions LIKE "%,' . $region->getId() . ',%"';
}
if (!empty($regionsCond)) {
$tourListing->addConditionParam('(' . implode(' OR ', $regionsCond) . ')');
}
}
// Filter Properties
if( $request->get('tourProperty', 0) && $request->get('tourProperty') != 'all' ){
$tourListing->addConditionParam('tourProperties LIKE :property', ['property' => '%,' . $request->get('tourProperty') . ',%']);
}
// Filter Strecke
if( $request->get('rangeLengthMin', 0) || $request->get('rangeLengthMax', 0) ){
$streckeMin = ((float) $request->get('rangeLengthMin', 0)) * 1000;
$streckeMax = ((float) $request->get('rangeLengthMax', $filteringData['length']['max'])) * 1000;
$tourListing->addConditionParam('( IFNULL(length, 0) >= :lengthMin AND IFNULL(length, 0) <= :lengthMax )', [ 'lengthMin' => $streckeMin, 'lengthMax' => $streckeMax ]);
}
// Filter Dauer
if( $request->get('durationMin', 0) || $request->get('durationMax', 0) ){
$timeMin = ((float) $request->get('durationMin', 0)) * 60;
$timeMax = ((float) $request->get('durationMax', $filteringData['duration']['max'])) * 60;
$tourListing->addConditionParam('( IFNULL(timeMin, 0) >= :timeMin AND IFNULL(timeMin, 0) <= :timeMax )', [ 'timeMin' => $timeMin, 'timeMax' => $timeMax ]);
}
// Filter Altitude
if( $request->get('altitudeMin', 0) || $request->get('altitudeMax', 0) ){
$altitudeMin = (float) $request->get('altitudeMin', 0);
$altitudeMax = (float) $request->get('altitudeMax', $filteringData['altitude']['max']);
// $tourListing->addConditionParam('( (elevationMaxAltitude - elevationMinAltitude) >= :altitudeMin AND (elevationMaxAltitude - elevationMinAltitude) <= :altitudeMax )', [ 'altitudeMin' => $altitudeMin, 'altitudeMax' => $altitudeMax ]);
$tourListing->addConditionParam('( IFNULL(elevationAscent, 0) >= :altitudeMin AND IFNULL(elevationAscent, 0) <= :altitudeMax )', [ 'altitudeMin' => $altitudeMin, 'altitudeMax' => $altitudeMax ]);
}
$sorting = $this->getDocumentEditable('select', 'tour_sorting')?->getData();
if(!empty($sorting)) {
$tourListing->setOrderKey($sorting, false);
}
// Paginator
$paginator = $paginator->paginate( $tourListing, $request->get('page', 1), 16 );
$paginator->setPageRange( 3 );
$viewParams['tourListing'] = $paginator;
$viewParams['filterData'] = $filteringData;
if ($request->isXmlHttpRequest()) {
return $this->json([
'success' => true,
'html' => $this->renderView('Tour/container.html.twig', $viewParams)
]);
}
return $this->renderTemplate('Tour/overview.html.twig', $viewParams);
}
public function detailAction(Request $request, AlpsteinConfig $alpsteinConfig, AlpsteinTour $id, CanonicalRedirectHelper $redirectHelper)
{
$object = $id;
if( !$object || ( !$object->isPublished() && !$this->editmode && !$request->get('pimcore_object_preview') && !$_COOKIE['pimcore_admin_sid'] ) ) {
throw new NotFoundHttpException("The requested object doesn't exist anymore");
}
if (CanonicalRedirectHelper::ENABLE_CANONICAL_REDIRECT && $redirect = $redirectHelper->canonicalRedirect($object)) {
return $redirect;
}
if (!empty($object->getManualRecommendation())) {
$recommendations = $object->getManualRecommendation();
} else {
$recommendations = new AlpsteinTour\Listing();
$recommendations->addConditionParam('name != "" AND name IS NOT NULL AND o_id != ' . $object->getId());
if (!$object->getDisableRadiusLimitation()) {
$functionsHelper = new FunctionsHelper();
$recommendations->addConditionParam($functionsHelper->getGeoDistanceQuery($object->getStartingPoint(), 'startingPoint') . ' < 10');
}
$categoryCondition = [];
if (!empty($object->getSimilarCategories())) {
$categories = $object->getSimilarCategories();
} else {
$categories = $object->getCategory();
}
foreach ($categories ?: [] as $category) {
$categoryCondition[] = 'category LIKE "%,' . $category->getId() . ',%"';
}
if (!empty($categoryCondition)) {
$recommendations->addConditionParam('(' . implode(' OR ', $categoryCondition) . ')');
}
$recommendations->setLimit(7);
$recommendations->setOrderKey('RAND()', false);
}
return $this->renderTemplate('Tour/detail.html.twig', [
'tour' => $object,
'alpsteinConfig' => $alpsteinConfig,
'recommendations' => $recommendations
]);
}
public static function getAllSubRegionIds(AlpsteinRegion $region) {
$ids = [];
foreach($region->getSubRegions() ?: [] as $subRegion) {
$ids[] = $subRegion->getId();
$ids = array_merge($ids, self::getAllSubRegionIds($subRegion));
}
return $ids;
}
/**
* @param Request $request
* @return RedirectResponse
* @Route("{_locale}/api/{type}/326442/tour-redirect/{foreignId}", name="pia_map", requirements={"type"="alpstein|contwise"})
*/
public function mapPiaLink(Request $request, LinkGenerator $linkGenerator) {
$tour = AlpsteinTour::getByAlpsteinId($request->get('foreignId'), 1) ?? AlpsteinTour::getByGeneralSolutionsId($request->get('foreignId'), 1);
if(!$tour) {
throw new NotFoundHttpException("invalid tour");
}
$url = $linkGenerator->generate($tour);
if(!$url) {
throw new NotFoundHttpException("Redirect not possible");
}
return new RedirectResponse($url);
}
}