<?php
namespace App\Controller;
use App\Twig\DemiExtension;
use App\Twig\LinkGenerator;
use Carbon\Carbon;
use Elements\Bundle\CmsToolsBundle\Tool\Helper\FunctionsHelper;
use Elements\Bundle\DemiFrontendBundle\Service\DemiUrl;
use Elements\Bundle\DemiFrontendBundle\Service\Teaser;
use Pimcore\Config;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Model\DataObject\Data\GeoCoordinates;
use Elements\Demi\Model\Listing\Infrastructure as InfrastructureListing;
use Pimcore\Model\DataObject\DemiFilterObject;
use Pimcore\Model\DataObject\DemiInfrastructure;
use Pimcore\Model\DataObject\DemiInfrastructureTopic;
use Pimcore\Model\DataObject\Region;
use Pimcore\Model\Document\Editable\Relations;
use Pimcore\Model\Document\Page;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class InteractiveMapController extends AbstractController
{
/**
* @param Request $request
* @param DemiExtension $demiExtension
* @param Config $config
*/
public function mapAction(Request $request, DemiExtension $demiExtension, Config $config)
{
$selection = $this->getSelectedFiltersFromRequest($request);
return $this->renderTemplate('InteractiveMap/map.html.twig', [
'selection' => $selection
]);
}
public function flexMapAction(Request $request, DemiExtension $demiExtension, Config $config) {
$selection = $this->getSelectedFlexFiltersFromRequest($request);
return $this->renderTemplate('InteractiveMap/flexMap.html.twig', [
'selection' => $selection
]);
}
/**
* @Route("/{_locale}/im/pois", name="im_pois")
* @param Request $request
* @param Config $config
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function pois(Request $request, Config $config) {
$pois = [];
$excursionCategories = $request->get('excursionFilter', []);
$culinaryCategories = $request->get('culinaryFilter', []);
$infraCategories = $request->get('infrastructureFilter', []);
$transitCategories = $request->get('transitFilter', []);
// show all if only location filter is set
$showAll = $request->get('location-lat', false) && $request->get('location-lng', false) && empty($excursionCategories) && empty($culinaryCategories) && empty($infraCategories) && empty($transitCategories);
if ($showAll && empty($excursionCategories)) {
$document = Page::getById($request->get('docId'));
if ($document instanceof Page) {
$relation = $document->getEditable('excursionTopics');
if ($relation instanceof Relations && !$relation->isEmpty()) {
foreach($relation->getElements() as $topic) {
$excursionCategories[] = $topic->getId();
}
}
}
}
if ($showAll && empty($culinaryCategories)) {
if (!$document instanceof Page) {
$document = Page::getById($request->get('docId'));
}
if ($document instanceof Page) {
$relation = $document->getEditable('culinaryTopics');
if ($relation instanceof Relations && !$relation->isEmpty()) {
foreach($relation->getElements() as $topic) {
$culinaryCategories[] = $topic->getId();
}
}
}
}
if ($showAll && empty($infraCategories)) {
if (!$document instanceof Page) {
$document = Page::getById($request->get('docId'));
}
if ($document instanceof Page) {
$relation = $document->getEditable('infraTopics');
if ($relation instanceof Relations && !$relation->isEmpty()) {
foreach($relation->getElements() as $topic) {
$infraCategories[] = $topic->getId();
}
}
}
}
if ($showAll && empty($transitCategories)) {
if (!$document instanceof Page) {
$document = Page::getById($request->get('docId'));
}
if ($document instanceof Page) {
$relation = $document->getEditable('transitTopics');
if ($relation instanceof Relations && !$relation->isEmpty()) {
foreach($relation->getElements() as $topic) {
$transitCategories[] = $topic->getId();
}
}
}
}
$infraListing = $this->getInfraList($excursionCategories, $request, $showAll);
foreach($infraListing as $infra) {
if ($position = $infra->getPosition()) {
$poiData = [
'id' => $infra->getId(),
'poiStyle' => 'sightseeing',
'lat' => $position->getLatitude(),
'lng' => $position->getLongitude(),
'detailInfoBoxUrl' => $this->generateUrl('im_info-box', ['id' => $infra->getId(), '_locale' => $request->getLocale(), 'poiStyle'=> 'sightseeing'])
];
$pois[] = $poiData;
}
}
$infraListing = $this->getInfraList($culinaryCategories, $request, $showAll);
foreach($infraListing as $infra) {
if ($position = $infra->getPosition()) {
$poiData = [
'id' => $infra->getId(),
'poiStyle' => 'gastronomy',
'lat' => $position->getLatitude(),
'lng' => $position->getLongitude(),
'detailInfoBoxUrl' => $this->generateUrl('im_info-box', ['id' => $infra->getId(), '_locale' => $request->getLocale(), 'poiStyle'=> 'gastronomy'])
];
$pois[] = $poiData;
}
}
$infraListing = $this->getInfraList($infraCategories, $request, $showAll);
foreach($infraListing as $infra) {
if ($position = $infra->getPosition()) {
$poiData = [
'id' => $infra->getId(),
'poiStyle' => 'infrastructure',
'lat' => $position->getLatitude(),
'lng' => $position->getLongitude(),
'detailInfoBoxUrl' => $this->generateUrl('im_info-box',
['id' => $infra->getId(), '_locale' => $request->getLocale(), 'poiStyle' => 'infrastructure'])
];
$pois[] = $poiData;
}
}
$infraListing = $this->getInfraList($transitCategories, $request, $showAll);
foreach($infraListing as $infra) {
if ($position = $infra->getPosition()) {
$poiData = [
'id' => $infra->getId(),
'poiStyle' => 'traffic',
'lat' => $position->getLatitude(),
'lng' => $position->getLongitude(),
'detailInfoBoxUrl' => $this->generateUrl('im_info-box',
['id' => $infra->getId(), '_locale' => $request->getLocale(), 'poiStyle' => 'traffic'])
];
$pois[] = $poiData;
}
}
return $this->json([
'success' => true,
'pois' => $pois
]);
}
/**
* @Route("/{_locale}/im/flex/pois", name="ifm_pois")
* @param Request $request
* @param Config $config
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function flexPois(Request $request, Config $config) {
$pois = [];
$document = Page::getById($request->get('documentId'));
if($document) {
$blockName = "filterblock";
$topicInputId = "topics_id";
$topicRelationsId = "topics";
$topicIconName = "topics_icon";
$filters = $document->getEditable($blockName) ? $document->getEditable($blockName)->getElements() : [];
$topicCategories = $this->getTopicsFromRequestByBlock($request, $filters, $topicInputId);
// show all if only location filter is set
$showAll = $this->showAllTopics($request, $topicCategories);
$categories = [];
if (!empty($filters)){
foreach ($filters as $filter) {
//if there is no topic preselected => use all topics from relations field
if($filter->getInput($topicInputId) &&
($input = $filter->getInput($topicInputId)->getData()) &&
$filter->getSelect($topicIconName) &&
($icon = $filter->getSelect($topicIconName)->getData())
) { // no input && no icon => do nothing
$categories[$input]['icon'] = $icon;
if(empty($topicCategories[$input]) && $showAll) { // get all from relations
if($filter->getRelations($topicRelationsId) instanceof Relations &&
($relations = $filter->getRelations($topicRelationsId)->getElements())
) {
foreach ($relations as $topic) {
$categories[$input]["topics"][] = $topic->getId();
}
}
} else { // use all from request
$categories[$input]["topics"] = $topicCategories[$input];
}
}
}
}
//for every filter get every category
foreach ($categories as $topicName => $cat) {
$infraListing = $this->getInfraList($cat["topics"], $request, $showAll);
foreach($infraListing as $infra) {
if ($position = $infra->getPosition()) {
$poiData = [
'id' => $infra->getId(),
'poiStyle' => $cat["icon"],
'lat' => $position->getLatitude(),
'lng' => $position->getLongitude(),
'detailInfoBoxUrl' => $this->generateUrl('im_info-box', ['id' => $infra->getId(), '_locale' => $request->getLocale(), 'poiStyle'=> $cat["icon"]])
];
$pois[] = $poiData;
}
}
}
}
return $this->json([
'success' => true,
'pois' => $pois
]);
}
/**
* @Route("/{_locale}/im/info-box/{id}", name="im_info-box")
* @param Request $request
* @param string $id
* @param LinkGenerator $linkGenerator
* @param DemiUrl $demiUrl
* @param Teaser $teaserHelper
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function infoBox(Request $request, string $id, LinkGenerator $linkGenerator, Teaser $teaserHelper) {
$object = AbstractObject::getById($id);
if ($object instanceof DemiInfrastructure) {
return $this->json([
'success' => true,
'html' => $this->renderView('InteractiveMap/infoBox.html.twig', [
'image' => $teaserHelper->getInfrastructureImage($object),
'type' => $request->get('poiStyle', false),
'name' => $object->getName(),
'link' => $linkGenerator->generate($object),
'text' => @$object->getShortDescription($request->getLocale(), Carbon::now())
])
]);
}
return $this->json([
'success' => false,
'error' => 'object not supported'
]);
}
/**
* @Route("/{_locale}/im/selected-filter", name="im_selected-filter")
* @param Request $request
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function selectedFilters(Request $request) {
$selection = $this->getSelectedFiltersFromRequest($request);
return $this->json([
'success' => true,
'html' => $this->renderView('InteractiveMap/selectedFilter.html.twig', [
'selection' => $selection
])
]);
}
/**
* @Route("/{_locale}/im/flex/selected-filter", name="ifm_selected-filter")
* @param Request $request
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function selectedFlexFilters(Request $request) {
$selection = $this->getSelectedFlexFiltersFromRequest($request);
return $this->json([
'success' => true,
'html' => $this->renderView('InteractiveMap/selectedFilter.html.twig', [
'selection' => $selection
])
]);
}
protected function getSelectedFiltersFromRequest(Request $request) {
$selection = [];
$excursionCategories = $request->get('excursionFilter', []);
$culinaryCategories = $request->get('culinaryFilter', []);
$infraCategories = $request->get('infrastructureFilter', []);
$transitCategories = $request->get('transitFilter', []);
$region = $request->get('region', false);
$search = $request->get('search', false);
$lat = $request->get('location-lat');
$lng = $request->get('location-lng');
if ($regionObject = Region::getById($region)) {
$selection['region'] = $regionObject->getName();
}
if ($lat && $lng && $search) {
$selection['search'] = $search;
}
foreach($excursionCategories as $categoryId) {
if ($category = DemiInfrastructureTopic::getById($categoryId)) {
$selection['categories']['excursionFilter[]'][$categoryId] = $category->getName();
}
}
foreach($culinaryCategories as $categoryId) {
if ($category = DemiInfrastructureTopic::getById($categoryId)) {
$selection['categories']['culinaryFilter[]'][$categoryId] = $category->getName();
}
}
foreach($infraCategories as $categoryId) {
if ($category = DemiInfrastructureTopic::getById($categoryId)) {
$selection['categories']['infrastructureFilter[]'][$categoryId] = $category->getName();
}
}
foreach($transitCategories as $categoryId) {
if ($category = DemiInfrastructureTopic::getById($categoryId)) {
$selection['categories']['transitFilter[]'][$categoryId] = $category->getName();
}
}
return $selection;
}
protected function getSelectedFlexFiltersFromRequest(Request $request, $blockName = "filterblock", $topicInputId = "topics_id") {
$selection = [];
$document = Page::getById($request->get('docId'));
if($document) {
$filters = $document->getEditable($blockName) ? $document->getEditable($blockName)->getElements() : [];
} else {
$filters = $this->getDocumentEditable("block", $blockName)->getElements();
}
$categories = $this->getTopicsFromRequestByBlock($request, $filters, $topicInputId);
$region = $request->get('region', false);
$search = $request->get('search', false);
$lat = $request->get('location-lat');
$lng = $request->get('location-lng');
if ($regionObject = Region::getById($region)) {
$selection['region'] = $regionObject->getName();
}
if ($lat && $lng && $search) {
$selection['search'] = $search;
}
foreach($categories as $key => $categoryInputs) {
foreach($categoryInputs as $categoryId) {
if ($category = DemiInfrastructureTopic::getById($categoryId)) {
$selection['categories'][($key . '[]')][$categoryId] = $category->getName();
}
}
}
return $selection;
}
protected function getInfraList($categories, Request $request, bool $showAll) {
if (empty($categories) && !$showAll) {
return [];
}
$functionsHelper = new FunctionsHelper();
$poiListing = new InfrastructureListing();
$poiListing->addConditionParam('name IS NOT NULL AND name != "" AND documents IS NOT NULL AND documents != "" AND descriptions IS NOT NULL AND descriptions != "" AND active = 1');
if (!empty($categories)) {
$poiListing->setCategory($categories);
}
// Region Condition
if ($request->get('region', false)) {
if ($region = Region::getById($request->get('region'))) {
if ($region->getDemiFilterObject() instanceof DemiFilterObject) {
$items = $region->getDemiFilterObject()->getFilterElements();
$regionIds = [];
foreach($items ?: [] as $item) {
$regionIds[] = $item->getId();
}
if (!empty($regionIds)) {
$poiListing->setRegions($regionIds);
}
}
}
}
// Vicinity Condition
if ($request->get('location-lat', false) && $request->get('location-lng', false)) {
$poiListing->addConditionParam($functionsHelper->getGeoDistanceQuery(new GeoCoordinates($request->get('location-lat'), $request->get('location-lng')), 'position') . ' <= 10');
}
return $poiListing;
}
private function getTopicsFromRequestByBlock(Request $request, array $filters, string $topicInputId) : array
{
$categories = [];
if (!empty($filters)){
foreach ($filters as $filter) {
if ($filter->getInput($topicInputId) && ($input = $filter->getInput($topicInputId)->getData())){
$categories[$input] = $request->get($input, []);
}
}
}
return $categories;
}
private function showAllTopics(Request $request, array $categories)
{
$showAll = $request->get('location-lat', false) && $request->get('location-lng', false);
if($showAll) {
foreach ($categories as $topicCategory) {
if(!empty($topicCategory)) {
$showAll = false;
break;
}
}
}
return $showAll;
}
}