<?php
namespace App\Controller;
use App\Entity\AccommodationType;
use App\Entity\Property;
use App\Entity\PropertyTags;
use App\Entity\PropertyTagsApplied;
use App\Entity\Regions;
use App\Entity\Searches;
use App\Entity\SearchResults;
use App\Service\GlobalFunctions;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class NewSearchController extends AbstractController
{
/**
* @Route("/search", name="search")
*/
public function index()
{
$em = $this->getDoctrine()->getManager();
$SearchOutput = [];
// Output all rooms with staff picks at the top - shuffled
$StaffPickTag = $this->getDoctrine()->getRepository(PropertyTags::class)->find(161);
$StaffPicksApplied = $this->getDoctrine()->getRepository(PropertyTagsApplied::class)->findBy(['Tag' => $StaffPickTag]);
foreach ($StaffPicksApplied as $thisApplied) {
$AccommType = $this->getDoctrine()->getRepository(AccommodationType::class)->find($thisApplied->getRoom()->getId());
if (null == $AccommType->getProperty()) {
$GetProperty = $this->getDoctrine()->getRepository(Property::class)->findOneBy(['ListingCode' => $AccommType->getPropertyCode()]);
$AccommType->setProperty($GetProperty);
$em->persist($AccommType);
$em->flush();
}
if (1 == $AccommType->getEnabled() && 'Listed' == $AccommType->getProperty()->getListingStatus()) {
$SearchOutput[$thisApplied->getRoom()->getId()] = $AccommType;
}
}
$AllRooms = $this->getDoctrine()->getRepository(AccommodationType::class)->findAll();
foreach ($AllRooms as $thisRoom) {
if (null == $thisRoom->getProperty()) {
$GetProperty = $this->getDoctrine()->getRepository(Property::class)->findOneBy(['ListingCode' => $thisRoom->getPropertyCode()]);
$thisRoom->setProperty($GetProperty);
$em = $this->getDoctrine()->getManager();
$em->persist($thisRoom);
$em->flush();
}
if (null !== $thisRoom->getProperty()) {
if (1 == $thisRoom->getEnabled() && 'Listed' == $thisRoom->getProperty()->getListingStatus()) {
if (!array_key_exists($thisRoom->getId(), $SearchOutput)) {
if ('' == $thisRoom->getSearchHeadline() or 'Display Name of Listing' == $thisRoom->getSearchHeadline()) {
} else {
$SearchOutput[$thisRoom->getId()] = $thisRoom;
}
}
}
}
}
shuffle($SearchOutput);
$GetSearch = null;
$Regions = $this->getDoctrine()->getRepository(Regions::class)->findBy([], ['SortOrder' => 'ASC']);
$Tags = $this->getDoctrine()->getRepository(PropertyTags::class)->findBy(['TagType' => 'experience']);
$AccommTypeTags = $this->getDoctrine()->getRepository(PropertyTags::class)->findBy(['TagType' => 'accomm_type']);
$CurrentRecentlyViewed = $this->get('session')->get('recently_viewed');
$RecentString = str_replace('[', '', $CurrentRecentlyViewed);
$ExpRecent = explode(']', $RecentString);
array_pop($ExpRecent);
$RecentlyViewed = [];
$i = 0;
foreach ($ExpRecent as $ThisRecent) {
if ($i < 4) {
$GetRecent = $this->getDoctrine()->getRepository(AccommodationType::class)->findOneBy([
'RoomCode' => $ThisRecent,
]);
$RecentlyViewed[] = $GetRecent;
}
++$i;
}
return $this->render('new_search/index.html.twig', [
'rooms' => $SearchOutput,
'search' => $GetSearch,
'regions' => $Regions,
'tags' => $Tags,
'accomm_type_tags' => $AccommTypeTags,
'recentlyviewed' => $RecentlyViewed,
'search_header' => '',
]);
}
/**
* @Route("/search/{search_key}", name="search_key")
*/
public function searchkey($search_key)
{
$em = $this->getDoctrine()->getManager();
$SearchOutput = [];
$GetSearch = $this->getDoctrine()->getRepository(Searches::class)->findOneBy(['SearchKey' => $search_key]);
$SearchResults = $this->getDoctrine()->getRepository(SearchResults::class)->findBy(['Search' => $GetSearch], ['SearchRank' => 'DESC']);
foreach ($SearchResults as $thisResult) {
if ('' == $thisResult->getAccommType()->getSearchHeadline() or 'Display Name of Listing' == $thisResult->getAccommType()->getSearchHeadline()) {
} else {
$SearchOutput[] = $thisResult->getAccommType();
}
}
$Regions = $this->getDoctrine()->getRepository(Regions::class)->findBy([], ['SortOrder' => 'ASC']);
$Tags = $this->getDoctrine()->getRepository(PropertyTags::class)->findBy(['TagType' => 'experience']);
$AccommTypeTags = $this->getDoctrine()->getRepository(PropertyTags::class)->findBy(['TagType' => 'accomm_type']);
$CurrentRecentlyViewed = $this->get('session')->get('recently_viewed');
$RecentString = str_replace('[', '', $CurrentRecentlyViewed);
$ExpRecent = explode(']', $RecentString);
array_pop($ExpRecent);
$RecentlyViewed = [];
$i = 0;
foreach ($ExpRecent as $ThisRecent) {
if ($i < 4) {
$GetRecent = $this->getDoctrine()->getRepository(AccommodationType::class)->findOneBy([
'RoomCode' => $ThisRecent,
]);
$RecentlyViewed[] = $GetRecent;
}
++$i;
}
// Search Headers
$SearchHeader = '';
$SearchFilters = str_replace('[', '', $GetSearch->getSelectedFilters());
$CountFilters = substr_count($SearchFilters, ']');
if (1 == $CountFilters) {
$SingleFilter = str_replace(']', '', $SearchFilters);
$GetTag = $this->getDoctrine()->getRepository(PropertyTags::class)->find($SingleFilter);
$TagParam = $GetTag->getParams();
if ('[SH]' == substr($TagParam, 0, 4)) {
$SearchHeader = str_replace('[SH]', '', $TagParam);
}
}
return $this->render('new_search/index.html.twig', [
'rooms' => $SearchOutput,
'search' => $GetSearch,
'regions' => $Regions,
'tags' => $Tags,
'accomm_type_tags' => $AccommTypeTags,
'recentlyviewed' => $RecentlyViewed,
'search_header' => $SearchHeader,
]);
}
public function wordSearch($needle, $haystack)
{
$needle = str_replace('-', ' ', $needle);
$haystack = str_replace('-', ' ', $haystack);
/** @var string $needle */
$needle = str_replace("'", '', $needle);
/** @var string $haystack */
$haystack = str_replace("'", '', $haystack);
$needleArray = explode(' ', strtolower($needle));
$haystackArray = explode(' ', strtolower($haystack));
/*// remove any null words
if (($key = array_search("and", $needleArray)) !== false) {
unset($needleArray[$key]);
}
if (($key = array_search("the", $needleArray)) !== false) {
unset($needleArray[$key]);
}*/
$word_hits = 0;
// search words
foreach ($needleArray as $needleWord) {
if (in_array($needleWord, $haystackArray)) {
++$word_hits;
}
}
return $word_hits;
}
/**
* @Route("/searchinput", name="search_input")
*/
public function input(Request $request, GlobalFunctions $GlobalFn)
{
$em = $this->getDoctrine()->getManager();
$regions = $request->request->get('regions');
$check_in = $request->request->get('check_in');
$check_out = $request->request->get('check_out');
$guests = $request->request->get('guests');
$price_range_min = $request->request->get('price_range_min');
$price_range_max = $request->request->get('price_range_max');
$selected_filters = $request->request->get('selected_filters');
$query = $request->request->get('query');
if ('' !== $check_in) {
$check_in_exp = explode('/', $check_in);
$check_in = $check_in_exp[2].'-'.$check_in_exp[1].'-'.$check_in_exp[0];
$check_out_exp = explode('/', $check_out);
$check_out = $check_out_exp[2].'-'.$check_out_exp[1].'-'.$check_out_exp[0];
}
$Key = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'), 0, 32);
$Search = new Searches();
if ('anon.' !== $this->get('security.token_storage')->getToken()->getUser()) {
$Search->setUser($this->get('security.token_storage')->getToken()->getUser());
}
$Search->setSearchKey($Key);
$Search->setCreated(new \DateTime());
$Search->setRegions($regions);
if ('' !== $check_in) {
$Search->setCheckIn(new \DateTime($check_in));
$Search->setCheckOut(new \DateTime($check_out));
}
if ($guests > 0) {
$Search->setGuests($guests);
}
$Search->setPriceRangeMin($price_range_min);
$Search->setPriceRangeMax($price_range_max);
$Search->setSelectedFilters($selected_filters);
$Search->setQuery($query);
$em->persist($Search);
$em->flush();
// Populate Search
$AllAccomms = $this->getDoctrine()->getRepository(AccommodationType::class)->findBy(['Enabled' => 1]);
$SearchOutput = [];
// Filter regions
foreach ($AllAccomms as $thisAccomm) {
if (null == $thisAccomm->getProperty()) {
$GetProperty = $this->getDoctrine()->getRepository(Property::class)->findOneBy(['ListingCode' => $thisAccomm->getPropertyCode()]);
$thisAccomm->setProperty($GetProperty);
$em = $this->getDoctrine()->getManager();
$em->persist($thisAccomm);
$em->flush();
}
if ('' == $regions) {
if (null !== $thisAccomm->getProperty()) {
if ('Listed' == $thisAccomm->getProperty()->getListingStatus() && 1 == $thisAccomm->getEnabled()) {
$SearchOutput[$thisAccomm->getId()] = $thisAccomm;
}
}
} else {
$regions = str_replace('[', '', $regions);
$expregions = explode(']', $regions);
if (null == $thisAccomm->getRegion()) {
if (null !== $thisAccomm->getProperty()) {
$PhysAddr3 = $thisAccomm->getProperty()->getPhysAddr3();
$GetRegion = $this->getDoctrine()->getRepository(Regions::class)->findOneBy(['Name' => $PhysAddr3]);
if (null !== $GetRegion) {
$thisAccomm->setRegion($GetRegion);
}
$em->persist($thisAccomm);
$em->flush();
}
}
if (null !== $thisAccomm->getRegion()) {
foreach ($expregions as $thisRegion) {
if ($thisAccomm->getRegion()->getId() == $thisRegion) {
if ('Listed' == $thisAccomm->getProperty()->getListingStatus() && 1 == $thisAccomm->getEnabled()) {
$SearchOutput[$thisAccomm->getId()] = $thisAccomm;
}
}
}
}
if (null !== $thisAccomm->getAdditionalRegions() && !isset($SearchOutput[$thisAccomm->getId()])) {
foreach ($thisAccomm->getAdditionalRegions() as $thisRegion) {
foreach ($expregions as $thisSearchRegion) {
if ($thisRegion->getId() == $thisSearchRegion) {
if ('Listed' == $thisAccomm->getProperty()->getListingStatus() && 1 == $thisAccomm->getEnabled()) {
$SearchOutput[$thisAccomm->getId()] = $thisAccomm;
}
}
}
}
}
}
}
// Filter check in and out
if (null !== $Search->getCheckIn()) {
foreach ($SearchOutput as $AccommId => $thisAccomm) {
$Available = $GlobalFn->date_range_availability($AccommId, $Search->getCheckIn()->format('d/m/Y'), $Search->getCheckOut()->format('d/m/Y'));
if ('available' !== $Available) {
unset($SearchOutput[$AccommId]);
}
}
}
// Filter out guest numbers
if ($Search->getGuests() > 0) {
foreach ($SearchOutput as $AccommId => $thisAccomm) {
$TotalGuests = $thisAccomm->getMaxGuests() + $thisAccomm->getMaxAdditionalGuests();
if ($TotalGuests < $Search->getGuests()) {
unset($SearchOutput[$AccommId]);
}
}
}
// Filter out price range
foreach ($SearchOutput as $AccommId => $thisAccomm) {
if ($thisAccomm->getNormalPrice() < $Search->getPriceRangeMin() or $thisAccomm->getNormalPrice() > $Search->getPriceRangeMax()) {
unset($SearchOutput[$AccommId]);
}
}
// Filter out filters
if ('' !== $selected_filters) {
$selected_filters = str_replace('[', '', $selected_filters);
$expselected_filters = explode(']', $selected_filters);
array_pop($expselected_filters);
foreach ($expselected_filters as $thisFilter) {
$GetTag = $this->getDoctrine()->getRepository(PropertyTags::class)->find($thisFilter);
$GetAppliedFilters = $this->getDoctrine()->getRepository(PropertyTagsApplied::class)->findBy(['Tag' => $GetTag]);
foreach ($SearchOutput as $AccommId => $thisAccomm) {
$Matches = 0;
foreach ($GetAppliedFilters as $thisApplied) {
if ($thisApplied->getRoom()->getId() == $AccommId) {
$Matches = 1;
}
}
if (0 == $Matches) {
unset($SearchOutput[$AccommId]);
}
}
}
}
// Filter search terms
if ('' !== $Search->getQuery()) {
foreach ($SearchOutput as $AccommId => $thisAccomm) {
// Check if description matches number of words
$DescriptionHits = $this->wordSearch($Search->getQuery(), $thisAccomm->getRoomDescription());
// Check if description matches number of words
$PropertyDescriptionHits = $this->wordSearch($Search->getQuery(), $thisAccomm->getProperty()->getPropertySummary());
// Check if property name matches as above
$PropertyNameHits = $this->wordSearch($Search->getQuery(), $thisAccomm->getProperty()->getPropertyTitle()) * 5;
// Check if healine name contains any words, ranking higher the more matched words
$RoomNamePartial = $this->wordSearch($Search->getQuery(), $thisAccomm->getRoomName()) * 20;
$HeadlineNamePartial = $this->wordSearch($Search->getQuery(), $thisAccomm->getSearchHeadline()) * 50;
// Check if physaddr2 contains any words, ranking higher the more matched words
$PhysAddr2Partial = $this->wordSearch($Search->getQuery(), $thisAccomm->getProperty()->getPhysAddr2()) * 20;
// Check if physaddr2 contains any words, ranking higher the more matched words
$PhysAddr3Partial = $this->wordSearch($Search->getQuery(), $thisAccomm->getProperty()->getPhysAddr3()) * 20;
// Check if search headline or room name exact match
if (strtolower($Search->getQuery()) == strtolower($thisAccomm->getRoomName()) or strtolower($Search->getQuery()) == strtolower($thisAccomm->getSearchHeadline())) {
$Rank = 999999999;
} else {
$Rank = $PropertyDescriptionHits + $DescriptionHits + $PropertyNameHits + $RoomNamePartial + $HeadlineNamePartial + $PhysAddr2Partial + $PhysAddr3Partial;
}
if ($Rank > 0) {
$Result = new SearchResults();
$Result->setSearch($Search);
$Result->setAccommType($thisAccomm);
$Result->setRank($Rank);
$em->persist($Result);
}
}
} else {
// Add search to db if not searched
$Rank = 1;
foreach ($SearchOutput as $AccommId => $thisAccomm) {
$Result = new SearchResults();
$Result->setSearch($Search);
$Result->setAccommType($thisAccomm);
$Result->setRank($Rank);
$em->persist($Result);
++$Rank;
}
}
$em->flush();
return new Response($Key);
// Filter filters
}
}