<?php
namespace App\Controller;
use App\Elastica\AdvertisementSearch;
use App\Elastica\ReviewSearch;
use App\Elastica\ReviewMapSearch;
use App\Entity\Review;
use App\Entity\Search;
use App\Service\GeocodingService;
use App\Form\SearchAdvertisementForm;
use Knp\Component\Pager\Pagination\AbstractPagination;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Cocur\Slugify\SlugifyInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
class SearchController extends AbstractController
{
private $slugify;
/**
* @var TranslatorInterface
*/
private $translator;
private $cacheManager;
private $kernel;
private $parameterBag;
public function __construct(SlugifyInterface $slugify, TranslatorInterface $translator, KernelInterface $kernel,CacheManager $cacheManager,ParameterBagInterface $parameterBag)
{
$this->translator = $translator;
$this->slugify = $slugify;
$this->kernel = $kernel;
$this->cacheManager = $cacheManager;
$this->parameterBag = $parameterBag;
}
/**
* Show search results
* @param Request $request
* @param AdvertisementSearch $advertisementSearch
* @param ReviewMapSearch $reviewSearch
* @return Response
* @Route("/search", options={"expose"=true}, name="advertisement_search")
*/
public function showSearchAction(Request $request, AdvertisementSearch $advertisementSearch,ReviewMapSearch $reviewSearch)
{
$form = $this->createForm(SearchAdvertisementForm::class, null, [
'action' => $this->generateUrl('advertisement_search'),
'method' => 'GET',
]);
$form->handleRequest($request);
$searchTerms = $request->query->all();
/*if(!property_exists($searchTerms, 'sort')){
$searchTerms['sort'] = 'updatedAt';
$searchTerms['direction'] = 'desc';
}*/
$em = $this->getDoctrine()->getManager();
if(isset($searchTerms['advantages'])){
$list = [];
foreach($searchTerms['advantages'] as $ad){
$advantage = $em->getRepository("App\Entity\Advantage")->find($ad);
if($advantage!=null){
$list[]= $advantage->getName();
}
}
$searchTerms['advantages'] = implode(",",$list);
}
$departmentName = null ;
if(array_key_exists('department',$searchTerms) && isset($searchTerms['department'])){
$departmentName = $searchTerms['department'];
}
$userSearchTerms = $searchTerms;
$userSearchTerms['publisherType'] = Review::PUBLISHER_TYPE_RESIDENT;
$advertisementSearchResults = $advertisementSearch->searchPaginated($searchTerms,$departmentName,25);
$userReviewDataList = $reviewSearch->getStat($userSearchTerms);
$adValues = $this->getAdValues($advertisementSearchResults);
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'html' => $this->renderView('ajax/search.html.twig', [
'advertisements' => $advertisementSearchResults,
'sortValue' => $request->query->get('sort'),
'directionValue' => $request->query->get('direction'),
]),
'markers' => $adValues
]
);
}
$advertisementsFromRenter = array_filter($advertisementSearchResults->getItems(), function ($result) {
return !$result->getOwner() && !in_array($result->getUser()->getRoles(), ['ROLE_PRO']);
});
$sortValue = $request->query->get('sort');
$directionValue = $request->query->get('direction');
return $this->render('advertisement/search.html.twig', [
'advertisements' => $advertisementSearchResults,
'noAdvertisementFromRenter' => sizeof($advertisementsFromRenter) == 0,
'sortValue' => isset($sortValue) ? $sortValue : 'updatedAt',
'directionValue' => isset($directionValue) ? $directionValue : 'desc',
'form' => $form->createView(),
'searchTerm' => '',
'js_vars' => [
'adData' => [
'advertisements' => $adValues,
'reviews' => [
'user' => $userReviewDataList,
],
'flux' => $this->getFlux($searchTerms),
]
]
]);
}
/**
* Show search results
* @param Request $request
* @return Response
* @Route("/search/autocomplete", options={"expose"=true}, name="autocomplete_search")
*/
public function autoCompleteAction(Request $request)
{
$searchTerm = $request->query->get('keyword');
$data = [];
if(isset($searchTerm)){
$searchTerm = trim($searchTerm);
$data = $this->searchPlace($searchTerm);
}
return new JsonResponse([
'error' => false,
'data' => $data
]);
}
/**
* Register a search request
* @param Request $request
* @return Response
* @Route("/search/register", methods={"POST"}, name="register_search")
*/
public function registerSearchAction(Request $request)
{
$query = $request->query->all();
$agencyContactAllowed = filter_var($request->request->get('agencyContactAllowed'), FILTER_VALIDATE_BOOLEAN);
$search = new Search();
$search->setUser($this->getUser());
$search->setQuery($query);
$search->setAgencyContactAllowed($agencyContactAllowed);
if (empty($search->getQuery())) {
return new JsonResponse(['error' => 'No valid query params'], 400);
}
$em = $this->getDoctrine()->getManager();
$em->persist($search);
$em->flush();
return new JsonResponse(["success" => true], 200);
}
/**
* @Route("/advertisement/search/{id}/remove", methods={"POST"},name="remove_search")
* @param Search $search
* @return JsonResponse
*/
public function removeSearchAction(Search $search)
{
$error = false;
if ($this->getUser()->getId() !== $search->getUser()->getId()) {
$error = true;
}
$em = $this->getDoctrine()->getManager();
$em->remove($search);
$em->flush();
return new JsonResponse(["error" => $error]);
}
/**
* @param AbstractPagination $advertisements
* @return array
*/
public function getAdValues(AbstractPagination $advertisements)
{
$adValues = [];
foreach ($advertisements->getItems() as $advertisement) {
$image = null;
foreach($advertisement->getFiles() as $file){
if(file_exists(realpath($this->kernel->getRootDir() . '/../public/uploads/pictures/'.$file->getPath()))){
$image = $file;
break;
}
}
$surfacePrice = "";
if ($advertisement->getSale() == 1) {
$surfacePrice = $advertisement->getSurface() !== 0
? (int)$advertisement->getPrice() / $advertisement->getSurface()
: 0;
}
if ($advertisement->getCreatorType() == 'agency') {
$role = "agence";
} elseif ($advertisement->getCreatorType() == 'owner') {
$role = "proprietaire";
} else {
$role = "locataire";
}
$slug = $this->translator->transchoice('label.advertisement.title',$advertisement->getRoomNumber(), ['%category%'=>$this->translator->trans($advertisement->getCategory()),'%type%'=>$this->translator->trans($advertisement->getTypeLabel()), '%roomNumber%'=> $this->translator->trans($advertisement->getRoomNumber()), '%surface%'=>$this->translator->trans($advertisement->getSurface())]);
$adValues[] = [
"id" => $advertisement->getId(),
"slug" => $this->slugify->slugify($slug),
"latitude" => $advertisement->getLatitude(),
"longitude" => $advertisement->getLongitude(),
"hasImage" => true,
"image" => ($image ? $this->cacheManager->getBrowserPath('/uploads/pictures/' . $image->getPath(), 'thumb') : '/images/default-picture.png'),
"type" => $advertisement->getType(),
"typeLabel" => $this->translator->trans($advertisement->getTypeLabel()),
"saleLabel" => $advertisement->getSaleLabel(),
"roomnumber" => $advertisement->getRoomNumber(),
"surface" => $advertisement->getSurface(),
"price" => $advertisement->getPrice(),
"city" => $advertisement->getCity(),
"surfacePrice" => $surfacePrice,
"role" => $role,
];
}
return $adValues;
}
private function getFlux($searchTerms){
$city = null;
$em = $this->getDoctrine()->getManager();
$results = [];
$qb = $em->getRepository('App\Entity\FluxRss')->createQueryBuilder('flux')
->select("flux.longitude,flux.latitude,flux.city,flux.region,flux.department")
->where('flux.type=:type')
->setParameter('type', 'city')
->groupBy('flux.longitude')
->addGroupBy('flux.latitude')
->addGroupBy('flux.city')
->addGroupBy('flux.region')
->addGroupBy('flux.department');
$query = $qb->getQuery();
$cities = $query->getResult();
foreach ($cities as $cityItem) {
$qb = $em->getRepository('App\Entity\FluxRss')->createQueryBuilder('flux')
->addSelect("flux.title,flux.link,flux.city,flux.department,flux.region,flux.postalCode")
->where('flux.type=:type')
->andWhere('flux.city=:city')
->andWhere('flux.longitude=:longitude')
->andWhere('flux.latitude=:latitude')
->setParameter('type', 'city')
->setParameter('city', $cityItem['city'])
->setParameter('longitude', $cityItem['longitude'])
->setParameter('latitude', $cityItem['latitude'])
->orderBy('flux.title', 'ASC');
$query = $qb->getQuery();
$result = $query->getResult();
$results[] = [
'specific' => false,
'longitude' => $cityItem['longitude'],
'latitude' => $cityItem['latitude'],
'city_id' => 1,
'city_name' => $cityItem['city'],
'selected' => $this->isFocused($searchTerms,null,$cityItem['city'],$cityItem['department'],$cityItem['region']) ,
'data' => $result
];
}
$qb = $em->getRepository('App\Entity\FluxRss')->createQueryBuilder('flux')
->addSelect("flux.id,flux.title,flux.link,flux.longitude,flux.latitude,flux.city,flux.department,flux.region,flux.postalCode,flux.pinColor")
->where('flux.type=:type')
->setParameter('type', 'address')
->orderBy('flux.title', 'ASC');
if(array_key_exists("postalCode",$searchTerms) && $searchTerms['postalCode']!=""){
$qb = $qb->andWhere("flux.postalCode=:postalCode OR flux.postalCode is null OR flux.postalCode='' ")->setParameter('postalCode', $searchTerms['postalCode']);
}
if(array_key_exists("city",$searchTerms) && $searchTerms['city']!=""){
$qb = $qb->andWhere('flux.city=:city')->setParameter('city', $searchTerms['city']);
}
if(array_key_exists("department",$searchTerms) && $searchTerms['department']!=""){
$qb = $qb->andWhere('flux.department=:department')->setParameter('department', $searchTerms['department']);
}
$query = $qb->getQuery();
$specificFlux = $query->getResult();
foreach ($specificFlux as $flux) {
$results[] = [
'longitude' => $flux['longitude'],
'latitude' => $flux['latitude'],
'flux_name' => $flux['title'],
'flux_link' => $flux['link'],
'pin_color' => $flux['pinColor'],
'selected' => $this->isFocused($searchTerms,$flux['postalCode'],$flux['city'],$flux['department'],$flux['region']) ,
'specific' => true,
'flux_id' => $flux['id'],
];
}
return $results;
}
private function isFocused($searchTerms,$postalCode,$city,$department,$region){
$isFocused = false;
if(array_key_exists("region",$searchTerms) && $searchTerms['region']!="" && $searchTerms['region']==$region){
$isFocused = true;
}else if(array_key_exists("department",$searchTerms) && $searchTerms['department']!="" && $searchTerms['department']==$department){
$isFocused = true;
}else if(array_key_exists("city",$searchTerms) && $searchTerms['city']!="" && $searchTerms['city']==$city){
$isFocused = true;
}else if($postalCode!=null && array_key_exists("postalCode",$searchTerms) && $searchTerms['postalCode']!="" && $searchTerms['postalCode']==$postalCode){
$isFocused = true;
}else{
$isFocused = false;
}
return $isFocused;
}
private function searchPlace($initialSearchTerm): array
{
$em = $this->getDoctrine()->getManager();
//$searchTerm = iconv('UTF-8', 'ASCII//TRANSLIT', $searchTerm);
$searchTerm = "%".$initialSearchTerm . "%";
$RAW_QUERY = "SELECT * ,MATCH(full_text_search) AGAINST(:initialSearchTerm IN BOOLEAN MODE) as relevance FROM `place` WHERE full_text_search like :searchTerm AND ( department IN ( 'Guadeloupe','Guyane','Réunion','Martinique','Mayotte','Nouvelle-Calédonie','Polynésie française','Saint-pierre-et-Miquelon','Wallis-et-Futuna')) ORDER BY relevance desc,postal_code,label LIMIT 10";
$statement = $em->getConnection()->prepare($RAW_QUERY);
$statement->bindValue("searchTerm", $searchTerm);
$statement->bindValue("initialSearchTerm", $initialSearchTerm);
$result =$statement->execute();
return $result->fetchAllAssociative();
}
}