src/Controller/SearchController.php line 79

Open in your IDE?
  1. <?php
  2. namespace Slivki\Controller;
  3. use Slivki\Entity\Offer;
  4. use Slivki\Entity\UserGroup;
  5. use Slivki\Services\DeviceTypeService;
  6. use Slivki\Services\Seo\SeoResourceService;
  7. use Symfony\Component\Routing\Annotation\Route;
  8. use Slivki\Entity\Banner;
  9. use Slivki\Entity\Category;
  10. use Slivki\Entity\City;
  11. use Slivki\Entity\GeoLocation;
  12. use Slivki\Entity\User;
  13. use Slivki\Services\CacheService;
  14. use Slivki\Services\SearchService;
  15. use Slivki\Services\SolrIndex;
  16. use Slivki\Util\CommonUtil;
  17. use Symfony\Component\HttpFoundation\JsonResponse;
  18. use Symfony\Component\HttpFoundation\RedirectResponse;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use Symfony\Component\HttpFoundation\Response;
  21. use Symfony\Component\Validator\Constraints\DateTime;
  22. class SearchController extends SiteController {
  23.     const OFFERS_PER_PAGE 44;
  24.     const ACTIVE_OFFERS_PER_PAGE 44;
  25.     const PAST_OFFERS_ON_FIRST_PAGE 4;
  26.     const PAST_OFFERS_PER_PAGE 44;
  27.     const SUGGEST_MAX_RESULT 5;
  28.     const CACHE_NAME 'search-5-';
  29.     const DEBUG_MODE false;
  30.     const ACTIVE_OFFERS_ROWS_PER_PAGE 20;
  31.     const ACTIVE_OFFERS_ROWS_PER_PAGE_MOBILE 8;
  32.     const SEARCH_OFFERS 0;
  33.     const SEARCH_SALES 1;
  34.     const SEARCH_PARTNER_OFFERS 2;
  35.     const SEARCH_INSTALLMENTS 5;
  36.     const SEARCH_FLIERS 6;
  37.     const SEARCH_PHOTO_GUIDES 7;
  38.     /**
  39.      * @Route("/search")
  40.      */
  41.     public function searchAction(
  42.         Request $request,
  43.         SearchService $searchService,
  44.         DeviceTypeService $deviceTypeService
  45.     ): Response {
  46.         ini_set('memory_limit''2g');
  47.         $isMobileDevice $deviceTypeService->isMobileDevice($request);
  48.         $searchText $request->query->get('text');
  49.         $searchText mb_strtolower(trim($searchText));
  50.         $response = new Response();
  51.         $redirect $this->checkForRedirect($searchText$request);
  52.         if ($redirect) {
  53.             return new RedirectResponse($redirect['url']);
  54.         }
  55.         $entityManager $this->getDoctrine()->getManager();
  56.         $banners $entityManager->getRepository(Banner::class)->findBy(['typeID' => Banner::TYPE_SEARCH_BANNER'active' => true'positionRow' => 1]);
  57.         $banner null;
  58.         if ($banners) {
  59.             $banner $banners[random_int(0count($banners) - 1)];
  60.         }
  61.         $secondBanners $entityManager->getRepository(Banner::class)->findBy(['typeID' => Banner::TYPE_SEARCH_BANNER'active' => true'positionRow' => 2]);
  62.         $secondBanner null;
  63.         if ($secondBanners) {
  64.             $secondBanner $secondBanners[random_int(0count($secondBanners) - 1)];
  65.         }
  66.         $sortBy $request->query->get('sortBy''default');
  67.         $distance $request->query->getInt('distance');
  68.         $isVoice $request->query->getBoolean('isVoice');
  69.         $cityID null;
  70.         $currentCityID $request->getSession()->get(City::CITY_ID_SESSION_KEYCity::DEFAULT_CITY_ID);
  71.         $userLocation $request->cookies->get(User::CURRENT_LOCATION_COOKIEGeoLocation::DEFAULT_LOCATION);
  72.         if ($this->getUser() && $this->getUser()->hasRole(UserGroup::ROLE_ADS_FREE)) {
  73.             $searchBanner '';
  74.             $searchBannerSecond '';
  75.         } else {
  76.             $searchBanner $this->renderView($isMobileDevice 'Slivki/mobile/banner/banner.html.twig' 'Slivki/banners/search_banner.html.twig', [
  77.                 'banner' => $banner,
  78.                 'additionalClass' => 'd-block d-sm-none',
  79.             ]);
  80.             $searchBannerSecond $this->renderView($isMobileDevice 'Slivki/mobile/banner/banner.html.twig' 'Slivki/banners/search_banner.html.twig', [
  81.                 'banner' => $secondBanner,
  82.                 'additionalClass' => 'd-block d-sm-none',
  83.             ]);
  84.         }
  85.         $searchResultHtml str_replace(
  86.             [
  87.                 '<!--::searchBanner::-->',
  88.                 '<!--::searchBannerSecond::-->',
  89.                 '---slivkis---',
  90.             ],
  91.             $currentCityID === City::TASHKENT_CITY_ID
  92.                 ? ['''''']
  93.                 : [
  94.                     $searchBanner,
  95.                     $searchBannerSecond,
  96.                     $request->cookies->get('slivkis'),
  97.                 ],
  98.             $searchService->search(
  99.                 $searchText,
  100.                 $sortBy,
  101.                 $distance,
  102.                 $userLocation,
  103.                 $isMobileDevice,
  104.                 true,
  105.                 false,
  106.                 $this->getUser() ? $this->getUser()->getID() : null,
  107.                 $cityID,
  108.                 $currentCityID,
  109.                 $isVoice,
  110.             ),
  111.         );
  112.         if ($isMobileDevice) {
  113.             $searchResultHtml str_replace(
  114.                 $currentCityID === City::TASHKENT_CITY_ID
  115.                     ? ['''']
  116.                     : [
  117.                         '<!--::searchBanner2::-->',
  118.                         '<!--::searchBannerSecond2::-->',
  119.                     ],
  120.                 [
  121.                     $this->renderView('Slivki/mobile/banner/banner.html.twig', [
  122.                         'banner' => $banner,
  123.                         'additionalClass' => 'd-none d-sm-block',
  124.                     ]),
  125.                     $this->renderView('Slivki/mobile/banner/banner.html.twig', [
  126.                         'banner' => $secondBanner,
  127.                         'additionalClass' => 'd-none d-sm-block',
  128.                     ]),
  129.                 ],
  130.                 $searchResultHtml,
  131.             );
  132.         }
  133.         $content $this->renderView($isMobileDevice 'Slivki/mobile/search/index.html.twig' 'Slivki/search/index.html.twig', [
  134.             'searchResultHtml' => $searchResultHtml,
  135.             'searchText' => $searchText,
  136.             'currentLocationCookie' => $request->cookies->get('currentLocation')
  137.         ]);
  138.         $response->setContent($content);
  139.         return $response;
  140.     }
  141.     /** @Route("/search/all_entities_more") */
  142.     public function searchAllEntitiesMoreAction(Request $requestSearchService $searchServiceSolrIndex $solrIndex) {
  143.         ini_set('memory_limit''2G');
  144.         $searchText $request->query->get('text');
  145.         $searchText mb_strtolower(trim($searchText));
  146.         $sortBy $request->query->get('sortBy');
  147.         $page $request->query->getInt('page');
  148.         $distance $request->query->getInt('distance');
  149.         $cityID $request->query->getInt('cityID');
  150.         $searchResult $solrIndex->searchAll($searchText$cityID);
  151.         if ($searchResult['count'] == 0) {
  152.             $searchResult $solrIndex->searchAll($searchService->transformToCyrillic($searchText), $cityID);
  153.         }
  154.         $userLocation $request->cookies->get(User::CURRENT_LOCATION_COOKIEGeoLocation::DEFAULT_LOCATION);
  155.         $isMobileDevice CommonUtil::isMobileDevice($request);
  156.         $allFoundEntities $searchService->getAllFoundEntities($userLocation$searchText$searchResult$sortBy$distance$isMobileDevice$page);
  157.         $data['allFoundEntities'] = &$allFoundEntities;
  158.         $data['activeOffers'] = &$allFoundEntities;
  159.         $data['searchText'] = $searchText;
  160.         $data['totalColumnAmount'] = self::getMobileDevice($request) ? 4;
  161.         $data['cityID'] = $cityID;
  162.         return $this->render($isMobileDevice 'Slivki/mobile/search/result.html.twig' 'Slivki/search/all_results.html.twig'$data);
  163.     }
  164.     public function checkForRedirect($searchText$request) {
  165.         $data = [];
  166.         switch ($searchText) {
  167.             case "личный кабинет":
  168.                 $url "/profile";
  169.                 $data['url'] = $url;
  170.                 break;
  171.             case "код":
  172.                 $url "/profile";
  173.                 if (self::getMobileDevice($request)) {
  174.                     $url "/profile#profilePromocodeTab";
  175.                 }
  176.                 $data['url'] = $url;
  177.                 break;
  178.             case "коды":
  179.                 $url "/profile";
  180.                 if (self::getMobileDevice($request)) {
  181.                     $url "/profile#profilePromocodeTab";
  182.                 }
  183.                 $data['url'] = $url;
  184.                 break;
  185.             case "промокоды":
  186.                 $url "/profile";
  187.                 if (self::getMobileDevice($request)) {
  188.                     $url "/profile#profilePromocodeTab";
  189.                 }
  190.                 $data['url'] = $url;
  191.                 break;
  192.             case "мои коды":
  193.                 $url "/profile";
  194.                 if (self::getMobileDevice($request)) {
  195.                     $url "/profile#profilePromocodeTab";
  196.                 }
  197.                 $data['url'] = $url;
  198.                 break;
  199.             case "мои промокоды":
  200.                 $url "/profile";
  201.                 if (self::getMobileDevice($request)) {
  202.                     $url "/profile#profilePromocodeTab";
  203.                 }
  204.                 $data['url'] = $url;
  205.                 break;
  206.             case "код скидки":
  207.                 $url "/profile";
  208.                 if (self::getMobileDevice($request)) {
  209.                     $url "/profile#profilePromocodeTab";
  210.                 }
  211.                 $data['url'] = $url;
  212.                 break;
  213.             case "новые":
  214.                 $url SeoResourceService::NEW_OFFERS_CATEGORY_URL;
  215.                 $data['url'] = $url;
  216.                 break;
  217.             case "листовки":
  218.                 $url "/giper-shop?utm_source=main_menu";
  219.                 $data['url'] = $url;
  220.                 break;
  221.             case "гипермаркеты":
  222.                 $url "/giper-shop?utm_source=main_menu";
  223.                 $data['url'] = $url;
  224.                 break;
  225.             case "торговые сети":
  226.                 $url "/giper-shop?utm_source=main_menu";
  227.                 $data['url'] = $url;
  228.                 break;
  229.             case "салоны красоты":
  230.                 $url "/salony-krasoty";
  231.                 $data['url'] = $url;
  232.                 break;
  233.             case "видеогид":
  234.             case "видеогиды":
  235.                 $url "/videogidy";
  236.                 $data['url'] = $url;
  237.                 break;
  238.         }
  239.         if ($data) {
  240.             return $data;
  241.         }
  242.         return false;
  243.     }
  244.     /** @Route("/search/more") */
  245.     public function moreAction(Request $requestCacheService $cacheServiceSearchService $searchServiceSolrIndex $solrIndex) {
  246.         $isMobileDevice CommonUtil::isMobileDevice($request);
  247.         $page $request->query->get('activeOffersPage'0) + 1;
  248.         $sortBy $request->query->get('sortBy''default');
  249.         $distance $request->query->get('distance'0);
  250.         $searchText $request->query->get('text');
  251.         $searchText mb_strtolower(trim($searchText));
  252.         $cityID $request->query->getInt('cityID');
  253.         $searchResult $solrIndex->searchOffers($searchText$cityID);
  254.         $relevantResults = [];
  255.         foreach ($searchResult['allResults'] as $item) {
  256.             $notFound true;
  257.             foreach ($searchResult['descriptionResults'] as $result) {
  258.                 if ($result['id'] == $item['id']) {
  259.                     $notFound false;
  260.                     break;
  261.                 }
  262.             }
  263.             if ($notFound) {
  264.                 $relevantResults[] = $item;
  265.             }
  266.         }
  267.         $searchResult $relevantResults;
  268.         if (count($searchResult) == 0) {
  269.             $searchResult $solrIndex->searchOffers($searchService->transformToCyrillic($searchText), $cityIDfalse$cityID);
  270.             $searchResult $searchResult['allResults'];
  271.         }
  272.         $offers = ['list' => [], 'page' => $page'haveMore' => false];
  273.         foreach ($searchResult as $item) {
  274.             $offers['list'][] = $item['id'];
  275.         }
  276.         $userLocation $request->cookies->get(User::CURRENT_LOCATION_COOKIEGeoLocation::DEFAULT_LOCATION);
  277.         if (!is_array($userLocation)) {
  278.             $userLocation explode(','$userLocation);
  279.         }
  280.         if ($distance 0) {
  281.             $this->filterByDistance($offers['list'], $userLocation$distance);
  282.         }
  283.         if ($sortBy != 'default') {
  284.             $this->sortResults($offers['list'], $sortBy$userLocation);
  285.         }
  286.         $perPage self::OFFERS_PER_PAGE;
  287.         $offset =  $perPage * ($page 1);
  288.         $offers['haveMore'] = count($offers['list']) > $offset $perPage;
  289.         $offers['page'] = $page;
  290.         $offers['list'] = array_slice($offers['list'], $offset$perPage 10);
  291.         $entityManager $this->getDoctrine()->getManager();
  292.         $offerRepository =  $entityManager->getRepository(Offer::class);
  293.         $offerList = [];
  294.         foreach ($offers['list'] as $offerID) {
  295.             $offer $cacheService->getTeaser($offerID$isMobileDevice);
  296.             if (!$offer) {
  297.                 $offer $offerRepository->getAnyWay($offerID);
  298.             }
  299.             if ($offer) {
  300.                 $offerList[] = $offer;
  301.             }
  302.             if (count($offerList) >= $perPage) {
  303.                 break;
  304.             }
  305.         }
  306.         $offers['list'] = $offerList;
  307.         $data['totalColumnAmount'] = $isMobileDevice 4;
  308.         $data['activeOffers'] = $offers;
  309.         $data['searchText'] = $searchText;
  310.         $data['offset'] = $offset $perPage;
  311.         $data['cityID'] = $cityID;
  312.         return $this->render($isMobileDevice 'Slivki/mobile/search/result.html.twig' 'Slivki/search/results.html.twig'$data);
  313.     }
  314.     /**
  315.      * @Route("/search/suggest")
  316.      */
  317.     public function suggestAction(Request $requestSearchService $searchService) {
  318.         $response = new JsonResponse();
  319.         $response->setCharset('UTF-8');
  320.         $response->setEncodingOptions(JSON_UNESCAPED_UNICODE);
  321.         $response->setData($searchService->getSuggest($request->get('term''')));
  322.         return $response;
  323.     }
  324.     public function luceneSearchAction(Request $request) {
  325.         /** @var \Slivki\Util\LuceneIndex  $luceneIndex */
  326.         $luceneIndex $this->get('slivki.lucene_index');
  327.         $activeOfferList = [];
  328.         $pastOfferList = [];
  329.         $saleList = [];
  330.         $searchText trim($request->get('text'));
  331.         if ($searchText != '') {
  332.             $result $luceneIndex->search($searchText);
  333.             foreach ($result as $item) {
  334.                 if ($item['type'] == Category::OFFER_CATEGORY_ID) {
  335.                     /** @var \Slivki\Entity\Offer  $offer */
  336.                     $offer $this->getOfferRepository()->find($item['id']);
  337.                     if ($offer) {
  338.                         if ($offer->getActiveTill() > new DateTime()) {
  339.                             $activeOfferList[] = $offer;
  340.                         } else {
  341.                             $pastOfferList[] = $offer;
  342.                         }
  343.                     }
  344.                 } else {
  345.                     $sale $this->getSaleRepository()->find($item['id']);
  346.                     if ($sale) {
  347.                         $saleList[] = $sale;
  348.                     }
  349.                 }
  350.             }
  351.         }
  352.         $data['expanded'] = false;
  353.         $data['offerList'] = $pastOfferList;
  354.         $activeOffers $this->get('twig')->render('Slivki/offers/teasers.html.twig'$data);
  355.         return new Response($activeOffers);
  356.     }
  357.     private function filterByDistance(&$offerList$location$distance) {
  358.         if (count($offerList) == 0) {
  359.             return;
  360.         }
  361.         $sql "select geo_location_relation.entity_id  from geo_location_relation inner join geo_location on geo_location_relation.location_id = geo_location.id 
  362.           where geo_location.latitude <> '' and geo_location.longitude <> '' and geo_location_relation.entity_id in (" implode(','$offerList) . ") 
  363.           and earth_distance(ll_to_earth($location[0]$location[1]), ll_to_earth(latitude::float8, longitude::float8)) * 1.25 <= $distance * 1000";
  364.         $result $this->getDoctrine()->getConnection()->executeQuery($sql)->fetchAll(\PDO::FETCH_COLUMN);
  365.         $offerListFiltered = [];
  366.         foreach ($offerList as $offerID) {
  367.             if (in_array($offerID$result)) {
  368.                 $offerListFiltered[] = $offerID;
  369.             }
  370.         }
  371.         $offerList $offerListFiltered;
  372.     }
  373.     private function sortResults(&$data$sortBy$location) {
  374.         if ($sortBy == 'popularity') {
  375.             if (isset($data['list'])) {
  376.                 $this->sortOffersByPopularity($data['list']);
  377.             } else {
  378.                 $this->sortSalesByPopularity($data);
  379.             }
  380.         } else {
  381.             if (isset($data['list'])) {
  382.                 $this->sortOffersByDistance($data['list'], $location);
  383.             } else {
  384.                 $this->sortOffersByDistance($data$location);
  385.             }
  386.         }
  387.     }
  388.     private function sortOffersByDistance(&$offerList$location) {
  389.         if (count($offerList) == 0) {
  390.             return;
  391.         }
  392.         $sql "select geo_location_relation.entity_id 
  393.           from geo_location_relation inner join geo_location on geo_location_relation.location_id = geo_location.id where geo_location.latitude <> '' and geo_location.longitude <> '' 
  394.           and geo_location_relation.entity_id in (" implode(','$offerList) . ") order by  earth_distance(ll_to_earth($location[0]$location[1]), ll_to_earth(latitude::float8, longitude::float8))";
  395.         $result $this->getDoctrine()->getConnection()->executeQuery($sql)->fetchAll(\PDO::FETCH_COLUMN);
  396.         $offerList array_unique(array_merge($resultarray_diff($result$offerList)));
  397.     }
  398.     private function sortOffersByPopularity(&$offerList) {
  399.         if (count($offerList) == 0) {
  400.             return;
  401.         }
  402.         $sql 'select entity_id, purchase_count_recent as purchase_count from purchase_count where entity_id in (' implode(','$offerList) . ')';
  403.         $result $this->getDoctrine()->getManager()->getConnection()->executeQuery($sql)->fetchAll(\PDO::FETCH_ASSOC);
  404.         $purchaseCountList = [];
  405.         foreach ($result as $item) {
  406.             $purchaseCountList[$item['entity_id']] = $item['purchase_count'];
  407.         }
  408.         usort($offerList, function($offerID$offerID1) use(&$purchaseCountList) {
  409.             $purchaseCount = isset($purchaseCountList[$offerID]) ? $purchaseCountList[$offerID] : 0;
  410.             $purchaseCount1 = isset($purchaseCountList[$offerID1]) ? $purchaseCountList[$offerID1] : 0;
  411.             return $purchaseCount $purchaseCount1 ? -1;
  412.         });
  413.     }
  414.     private function sortSalesByPopularity(&$saleList) {
  415.         if (count($saleList) == 0) {
  416.             return 0;
  417.         }
  418.         $sql 'select entity_id, visit_count from visit_count_aggregated where entity_id in (' implode(','$saleList) . ') and days_count = 7';
  419.         $result $this->getDoctrine()->getManager()->getConnection()->executeQuery($sql)->fetchAll(\PDO::FETCH_ASSOC);
  420.         $visitCountList = [];
  421.         foreach ($result as $item) {
  422.             $visitCountList[$item['entity_id']] = $item['visit_count'];
  423.         }
  424.         usort($saleList, function($saleID$saleID1) use($visitCountList) {
  425.             $visitCount = isset($visitCountList[$saleID]) ? $visitCountList[$saleID] : 0;
  426.             $visitCount1 = isset($visitCountList[$saleID1]) ? $visitCountList[$saleID1] : 0;
  427.             return $visitCount $visitCount1 ? -1;
  428.         });
  429.     }
  430. }