<?php
namespace Aqarmap\Bundle\MainBundle\Controller;
use Aqarmap\Bundle\BuyerAlertsBundle\Entity\RecentSearches;
use Aqarmap\Bundle\FeatureToggleBundle\Service\FeatureToggleManager;
use Aqarmap\Bundle\ListingBundle\Entity\Location;
use Aqarmap\Bundle\ListingBundle\Entity\PropertyType;
use Aqarmap\Bundle\ListingBundle\Entity\Section;
use Aqarmap\Bundle\ListingBundle\Form\AdvancedSearchType;
use Aqarmap\Bundle\ListingBundle\Form\FullAdvancedFilterType;
use Aqarmap\Bundle\ListingBundle\Form\MultipleSearchFormType;
use Aqarmap\Bundle\ListingBundle\Repository\SectionRepository;
use Aqarmap\Bundle\ListingBundle\Service\AdvancedFilterFormTypeManager;
use Aqarmap\Bundle\ListingBundle\Service\AdvancedSearchFormTypeManager;
use Aqarmap\Bundle\ListingBundle\Service\CustomFieldService;
use Aqarmap\Bundle\ListingBundle\Service\ListingManager;
use Aqarmap\Bundle\MainBundle\Contract\CacheManagerInterface;
use Aqarmap\Bundle\MainBundle\Service\HomeSubMenuService;
use Aqarmap\Bundle\MainBundle\Service\MobileDetectionService;
use Aqarmap\Bundle\MainBundle\Service\Setting;
use Aqarmap\Bundle\MainBundle\Service\SiteMapService;
use Aqarmap\Bundle\UserBundle\Services\UserActivityService;
use Predis\ClientInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class DefaultController extends AbstractController
{
public const LISTING_COUNTER_CACHE_KEY = 'listing_counter';
/**
* @var UserActivityService
*/
private $activityService;
/**
* @var ClientInterface
*/
private $redisClient;
/**
* @var HomeSubMenuService
*/
private $homeSubMenuService;
/**
* @var CustomFieldService
*/
private $customFieldService;
/**
* @var AdvancedSearchFormTypeManager
*/
private $advancedSearchFormTypeManager;
/**
* @var Setting
*/
private $setting;
/**
* @var AuthorizationCheckerInterface
*/
private $authorizationChecker;
/**
* @var MobileDetectionService
*/
private $mobileDetectionService;
/**
* @var SiteMapService
*/
private $siteMapService;
/**
* @var AdvancedFilterFormTypeManager
*/
private $advancedFilterFormTypeManager;
/**
* @var TranslatorInterface
*/
private $translator;
public function __construct(
FeatureToggleManager $featureToggleManager,
UserActivityService $activityService,
ClientInterface $redisClient,
HomeSubMenuService $homeSubMenuService,
CustomFieldService $customFieldService,
AdvancedSearchFormTypeManager $advancedSearchFormTypeManager,
Setting $setting,
AuthorizationCheckerInterface $authorizationChecker,
MobileDetectionService $mobileDetectionService,
SiteMapService $siteMapService,
AdvancedFilterFormTypeManager $advancedFilterFormTypeManager,
TranslatorInterface $translator,
CacheManagerInterface $cacheManager
) {
$this->activityService = $activityService;
$this->redisClient = $redisClient;
$this->homeSubMenuService = $homeSubMenuService;
$this->customFieldService = $customFieldService;
$this->advancedSearchFormTypeManager = $advancedSearchFormTypeManager;
$this->setting = $setting;
$this->authorizationChecker = $authorizationChecker;
$this->mobileDetectionService = $mobileDetectionService;
$this->siteMapService = $siteMapService;
$this->advancedFilterFormTypeManager = $advancedFilterFormTypeManager;
$this->translator = $translator;
}
/**
* Homepage action.
*
* @Route("/", name="homepage", methods={"GET"})
*/
public function home(SectionRepository $sectionRepository, ListingManager $listingManager): Response
{
return $this->render('@AqarmapMain/Default/homepage.v2.html.twig', [
'recent_searches' => $this->getRecentSearch(),
'searchableSections' => $sectionRepository->getSearchableSection(),
'listingsCount' => $listingManager->getListingsCount(),
]);
}
/**
* Search filters page v2.
*
* @Route("/search-page-filters", name="listing_search_page_filters", methods={"GET"})
*/
public function searchPageFilters(Request $request, SectionRepository $sectionRepository): Response
{
$searchForm = $this->createAdvancedSearchForm();
$multipleSearchForm = $this->createMultipleSearchForm();
$mobileDetecton = $this->getMobileInfo($request);
$filterForm = $this->setAdvancedFilterFormData($request);
$context = array_merge($mobileDetecton, [
'section' => null,
'searchForm' => $searchForm->createView(),
'advancedFilter' => $filterForm->createView(),
'customFieldIds' => $this->customFieldService->getCustomFieldIds(),
'multipleSearchForm' => $multipleSearchForm->createView(),
'searchableSections' => $sectionRepository->getSearchableSection(),
'featureToggle' => $this->activityService->getFeatureToggles(),
'subLocations' => $this->homeSubMenuService->getSubLocations($request->getLocale()),
'subPropertyTypes' => $this->homeSubMenuService->getSubPropertyTypes($request->getLocale()),
]);
return $this->render('@AqarmapMain/Default/searchPageFilters.html.twig', $context);
}
/**
* Set User Agent In Cookies.
*
* @Route ("/set-user-agent", name="desktop_site")
*/
public function setUserAgent(Request $request): RedirectResponse
{
$response = new RedirectResponse($request->headers->get('referer') ?: $this->generateUrl('homepage'));
$cookie = new Cookie('user-agent', 'User-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36');
$response->headers->setCookie($cookie);
$response->prepare($request);
$response->send();
return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
}
/**
* remove User Agent In Cookies.
*
* @Route ("/unset-user-agent", name="mobile_site")
*/
public function unsetUserAgent(Request $request): RedirectResponse
{
$response = new RedirectResponse($request->headers->get('referer'));
$response->headers->clearCookie('user-agent');
$response->prepare($request);
$response->send();
return $this->redirect($request->headers->get('referer') ?: $this->generateUrl('homepage'));
}
/**
* Add Listing Notifier.
*
* @return JsonResponse
*
* @Route("/add_listing_notifier", name="add_listing_notifier", options={"expose"=true})
*/
public function addListingNotifier(Request $request)
{
if (!$request->cookies->has('add_listing_notifier')) {
$response = new Response();
$time = time() + (86400 * 30);
$response->headers->setCookie(new Cookie('add_listing_notifier', true, $time));
$response->sendHeaders();
}
return new Response();
}
/**
* Close request a expiry.
*
* @return JsonResponse
*
* @Route("/close-alert-request", name="close_alert_request", options={"expose"=true})
*/
public function closeAlertRequest(Request $request)
{
if (!$request->cookies->has($request->get('name'))) {
$response = new Response();
$time = time() + (86400 * 30);
$response->headers->setCookie(new Cookie($request->get('name'), true, $time));
$response->sendHeaders();
}
return new Response();
}
/**
* Sitemaps flow.
*
* @Route ("/sitemap/flow", name="sitemap_flow", methods={"GET"})
* @Route ("/sitemap/flow/{section}", name="sitemap_section_flow", methods={"GET"})
* @Route ("/sitemap/flow/{section}/{property_type}", name="sitemap_section_property_type_flow", methods={"GET"})
* @Route ("/sitemap/flow/{section}/{property_type}/{location}",
* name="sitemap_section_property_type_location_flow",
* requirements={"location": ".+[^/]"},
* methods={"GET"}
* )
*
* @ParamConverter("section", options={"mapping": {"section": "slug"}})
* @ParamConverter("propertyType", options={"mapping": {"property_type": "slug"}})
* @ParamConverter("location", options={"mapping": {"location": "slug"}})
*
* @return RedirectResponse
*/
public function sitemapFlow(Request $request, ?Section $section = null, ?PropertyType $propertyType = null, ?Location $location = null)
{
$em = $this->getDoctrine()->getManager();
$return = [
'section' => $section,
'propertyType' => $propertyType,
'location' => $location,
];
if (!$section) {
$return['searchableSections'] = $em
->getRepository(Section::class)
->getSearchableSection();
} else {
$return['searchableProperties'] = $this->siteMapService
->getSearchableProperties($section->getId(), $request->getLocale())->getResult();
}
$locationsRepository = $em->getRepository(Location::class);
if ($propertyType && !$location) {
$return['searchableLocations'] = $this->siteMapService
->getSearchableLocations($propertyType->getId(), $request->getLocale())->getResult();
}
if ($location) {
$children = $this->siteMapService
->getLocationChildrenFlatResults($location->getId(), $propertyType->getId(), $request->getLocale());
if (empty($children)) {
return $this->redirect($this->generateUrl('search', [
'section_slug' => $section->getSlug(),
'property_type_slug' => $propertyType->getSlug(),
'location_slug' => $location->getSlug(),
]));
}
$locationPath = $locationsRepository->getLocationPathNodes($location);
$return['parentLocationBuild'] = $locationsRepository->buildTree($locationPath, [
'decorate' => true,
'rootOpen' => '',
'rootClose' => '',
'childOpen' => function ($firstLeafLocation) use ($section, $propertyType, $location) {
$url = $this->generateUrl('sitemap_section_property_type_location_flow', [
'section' => $section->getSlug(),
'property_type' => $propertyType->getSlug(),
'location' => $firstLeafLocation['slug'],
]);
if ($firstLeafLocation['id'] == $location->getId()) {
$url = $this->generateUrl('search', [
'section_slug' => $section->getSlug(),
'property_type_slug' => $propertyType->getSlug(),
'location_slug' => $firstLeafLocation['slug'],
]);
}
return '<li>'.
'<a
title="'.
$this->translator->trans('layout.title.header', [
'%section%' => $section->getTitle(),
'%property_type%' => $propertyType->getTitle(),
'%location%' => $firstLeafLocation['title'],
])
.'"
href="'.$url.'">';
},
'childClose' => '</a></li>',
]);
$return['locationBuild'] = $locationsRepository->buildTree($children, [
'decorate' => true,
'childOpen' => function ($childLocation) use ($section, $propertyType, $children) {
$url = $this->generateUrl('sitemap_section_property_type_location_flow', [
'section' => $section->getSlug(),
'property_type' => $propertyType->getSlug(),
'location' => $childLocation['slug'],
]);
if (1 == \count($children)) {
$url = $this->generateUrl('search', [
'section_slug' => $section->getSlug(),
'property_type_slug' => $propertyType->getSlug(),
'location_slug' => $childLocation['slug'],
]);
}
return '<li>'.
'<a
title="'.
$this->translator->trans('layout.title.header', [
'%section%' => $section->getTitle(),
'%property_type%' => $propertyType->getTitle(),
'%location%' => $childLocation['title'],
])
.'"
href="'.$url.'">';
},
'childClose' => '</a></li>',
]);
}
return $this->render('@AqarmapMain/Default/sitemapFlow.html.twig', $return);
}
/**
* Sitemaps.
*
* @Route ("/sitemap", name="sitemap", methods={"GET"})
*
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function sitemap(): RedirectResponse
{
return $this->redirect($this->generateUrl('sitemap_flow'), Response::HTTP_FOUND);
}
/**
* Expo.
*
* @Route("/expo", name="expo_landing", options={"expose"=true})
*/
public function expo(): Response
{
return $this->render('@AqarmapMain/Expo/landingPage.html.twig');
}
/**
* Gets mobile info.
*
* @return array
*/
protected function getMobileInfo(Request $request)
{
$userAgent = $request->cookies->get('user-agent');
if (!$userAgent) {
$userAgent = $request->headers->get('user-agent');
}
return $this->mobileDetectionService->getInfo($userAgent);
}
/**
* Advanced Search Form.
*/
protected function createAdvancedSearchForm(): FormInterface
{
return $this
->advancedSearchFormTypeManager
->setAction($this->generateUrl('listing_advanced_search'))
->setFormType(AdvancedSearchType::class)
->setMethodType('Post')
->setSettings($this->setting)
->applyOptions()
->createForm();
}
/**
* Multiple Search Form.
*/
protected function createMultipleSearchForm(): FormInterface
{
return $this
->advancedSearchFormTypeManager
->setAction($this->generateUrl('listing_multiple_search'))
->setFormType(MultipleSearchFormType::class)
->setMethodType('Post')
->setSettings($this->setting)
->applyOptions()
->createForm();
}
/**
* Gets recent user's search.
*/
protected function getRecentSearch(): array
{
$searches = [];
if ($this->authorizationChecker->isGranted('ROLE_EXPERIMENT')) {
$searches = $this
->getDoctrine()
->getManager()
->getRepository(RecentSearches::class)
->findBy(['user' => $this->getUser()], ['updatedAt' => 'DESC'], 9);
}
return $searches;
}
/**
* Advanced Search Form.
*/
protected function createAdvancedFilterForm(): FormInterface
{
$customFields = $this->redisClient->get('customFields');
return $this->advancedFilterFormTypeManager
->setAction($this->generateUrl('listing_filter_search'))
->setFormType(FullAdvancedFilterType::class)
->setMethodType('Post')
->setSettings($this->setting)
->setCustomFields($customFields ? unserialize($customFields) : [])
->applyOptions()
->createForm();
}
/**
* Set Advanced Filters FormData.
*/
private function setAdvancedFilterFormData(Request $request)
{
$filterForm = $this->createAdvancedFilterForm();
$filterForm->get('minPrice')->setData($request->query->get('minPrice'));
$filterForm->get('maxPrice')->setData($request->query->get('maxPrice'));
$filterForm->get('minArea')->setData((int) $request->query->get('minArea'));
$filterForm->get('maxArea')->setData((int) $request->query->get('maxArea'));
$filterForm->get('section')->setData($request->query->get('section'));
$filterForm->get('propertyType')->setData($request->query->get('propertyType'));
$filterForm->get('location')->setData($request->query->get('location'));
return $filterForm;
}
}