src/Controller/SearchController.php line 104

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  4. use Symfony\Component\Routing\Annotation\Route;
  5. use FOS\ElasticaBundle\Finder\PaginatedFinderInterface;
  6. use FOS\ElasticaBundle\Index\IndexManager;
  7. use FOS\ElasticaBundle\Transformer\ElasticaToModelTransformerCollection;
  8. use FOS\ElasticaBundle\Manager\RepositoryManagerInterface;
  9. use Symfony\Component\HttpFoundation\JsonResponse;
  10. use Symfony\Component\HttpFoundation\Request;
  11. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  12. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  13. use Doctrine\ORM\EntityManagerInterface;
  14. use Knp\Component\Pager\PaginatorInterface;
  15. use Elastica\Query;
  16. use Elastica\Suggest;
  17. use Elastica\Query\Match;
  18. use Elastica\Query\BoolQuery;
  19. use FOS\ElasticaBundle\Repository;
  20. use App\Entity\Product;
  21. use App\Entity\Company;
  22. use App\Entity\OmeloPost;
  23. use App\Entity\UserSearch;
  24. use App\Service\UserService;
  25. use App\Service\ProductService;
  26. use App\Entity\Region;
  27. use App\Entity\Conservation;
  28. use App\Entity\Category;
  29. use App\SearchRepository\ProductSearch;
  30. class SearchController extends AbstractController
  31. {
  32.     protected $validProductFinder;
  33.     protected $validCompanyFinder;
  34.     protected $indexManager;
  35.     protected $userServ;
  36.     /*
  37.      * @param PaginatedFinderInterface $productFinder
  38.      */
  39.     public function __construct(PaginatedFinderInterface $validProductFinder,
  40.                                 PaginatedFinderInterface $validCompanyFinder,
  41.                                 IndexManager $indexManager,
  42.                                 UserService $userServ,
  43.                                 EntityManagerInterface $em
  44.     ){
  45.         $this->validProductFinder $validProductFinder;
  46.         $this->validCompanyFinder $validCompanyFinder;
  47.         $this->indexManager $indexManager;
  48.         $this->userServ $userServ;
  49.         $this->em $em;
  50.     }
  51.     public function findProducts(string $string){
  52.         $query $this->indexManager->getIndex('product')->getType('valid')
  53.             ->createSearch($string)
  54.             ->getQuery();
  55.         $association $this->userServ->getAssociationUserIsBrowsing();
  56.         if (!$association){
  57.             $query->setPostFilter(new Query\Term(['isDisplayedInAssociationOnly' => false]));
  58.         } else {
  59.             $query->setPostFilter(new Query\Term([
  60.                 'searchAssociations' => $association->getId()
  61.             ]));
  62.         }
  63.         return $query;
  64.     }
  65.     public function findProductsSuggestions(string $string) {
  66.         $products $this->em->getRepository(Product::class)->searchForProductsSuggestions($string);
  67.         return $products;
  68.     }
  69.     public function findCompany(string $string){
  70.         $query $this->indexManager->getIndex('product')->getType('valid')
  71.             ->createSearch($string)
  72.             ->getQuery();
  73.         $association $this->userServ->getAssociationUserIsBrowsing();
  74.         if (!$association){
  75.             //$query->setPostFilter(new Query\Term(['isDisplayedInAssociationOnly' => true]));
  76.         } else {
  77.             $query->setPostFilter(new Query\Term([
  78.                 'searchAssociations' => $association->getId()
  79.             ]));
  80.         }
  81.         return $query;
  82.     }
  83.     /**
  84.      * @Route("/api/search/product/valid",
  85.      *      options = { "expose" = true },
  86.      *      name="searchValidProduct"
  87.      * )
  88.      */
  89.     public function ApiSearch(Request $requestUrlGeneratorInterface $routerProductService $productServEntityManagerInterface $em)
  90.     {
  91.         $term $request->get('term');
  92.         $suggestions = array();
  93.         $productSuggestions $this->findProductsSuggestions($term);
  94.         if (empty($productSuggestions)) {
  95.           $productSuggestions $this->getSuggestions($term'product');
  96.         }
  97.         $columns = array();
  98.         $productId = array();
  99.         //Limit to 10
  100.         $cmtp 0;
  101.         foreach ($productSuggestions as $product) {
  102.             $route false;
  103.             //It remove the duplicates
  104.             if(!in_array($product->getId(), $productId)){
  105.                 $productId[]= $product->getId();
  106.                 $cmtp++;
  107.                 $product $productServ->getProductById($product->getId());
  108.                 //Sometime the search engine doesn'T get updated for products
  109.                 if($product->getCompany()->getShowPublicly()){
  110.                     $route $router->generate('viewProduct',
  111.                         array(
  112.                             'id' => $product->getId(),
  113.                             'producerUrl' => $product->getCompany()->getUrlName(),
  114.                             'productName' => $product->getUrlName()
  115.                         )
  116.                     );
  117.                 }
  118.                 if($route){
  119.                     $suggestions[] = array(
  120.                         'label' => $product->getNameWithDetails().' par '.$product->getCompany()->getName(),
  121.                         'category' => 'Produits',
  122.                         'value' => $route
  123.                     );
  124.                 }
  125.             }
  126.             if($cmtp >= 15)
  127.                 break;
  128.         }
  129.         $companySuggestions $this->getSuggestions($term'company');
  130.         $companyId = array();
  131.         $cmtp 0;
  132.         foreach ($companySuggestions as $company) {
  133.             if(!in_array($company->getId(), $companyId)){
  134.                 $cmtp++;
  135.                 $companyId[]= $company->getId();
  136.                 $company $em->getRepository(Company::class)->findOneBy(
  137.                     [
  138.                         'id' => $company->getId()
  139.                     ]
  140.                 );
  141.                 if($company->getShowPublicly()){
  142.                     $route $router->generate('companyStore',
  143.                         array(
  144.                             'urlname' => $company->getUrlName(),
  145.                             'id' => $company->getId()
  146.                         )
  147.                     );
  148.                     $suggestions[] = array(
  149.                         'label' => $company->getName().' à '.ucfirst(strtolower($company->getMainLocation()->getCity())).', '.$company->getMainLocation()->getProvince(),
  150.                         'category' => 'Boutiques',
  151.                         'value' => $route
  152.                     );
  153.                 }
  154.             }
  155.             if($cmtp >= 5)
  156.                 break;
  157.         }
  158.         $response = new JsonResponse($suggestions 200, array('Cache-Control' => 'no-cache'));
  159.         return $response;
  160.     }
  161.     private function getSuggestions($string$indexName){
  162.             $mngr $this->indexManager;
  163.             $search $mngr->getIndex($indexName)->createSearch();
  164.             $search->addType('valid');
  165.             if($indexName == 'product')
  166.                 return $search->search($this->findProducts($string));
  167.             elseif ($indexName == 'company')
  168.                 return $search->search($this->findCompany($string));
  169.         return $search->search($string);
  170.     }
  171.     /**
  172.      * @Route({
  173.      *          "fr": "/recherche/{type}",
  174.      *          "en": "/search/{type}"
  175.      *      }, name="noSearch")
  176.      */
  177.     public function noSearch(){
  178.         $this->addFlash('success'"Nous avons trouvé aucun produit, voici nos suggestions");
  179.         return $this->redirectToRoute('allCategory');
  180.     }
  181.     /**
  182.      * @Route({
  183.      *          "fr": "/recherche/{type}/{string}",
  184.      *          "en": "/search/{type}/{string}"
  185.      *      },
  186.      *      options = { "expose" = true },
  187.      *      name="search"
  188.      *  )
  189.      * @Template("frontend/category.html.twig")
  190.      */
  191.     public function search(UserService $userServ$type='a'$stringEntityManagerInterface $emProductService $productServRepositoryManagerInterface $managerPaginatorInterface $paginatorRequest $request)
  192.     {
  193.         $twigData = array();
  194.         $twigData['hideSideMenu'] = true;
  195.         $string urldecode($string);
  196.         $twigData['search'] = $string;
  197.         $twigData['products']=false;
  198.         $twigData['companies']=false;
  199.         $order "desc";
  200.         if ($request->get("order")) {
  201.           $order $request->get("order");
  202.         }
  203.         $twigData['order']= $order;
  204.         $sorting "popularity";
  205.         if ($request->get("sorting")) {
  206.           $sorting $request->get("sorting");
  207.         }
  208.         $twigData['sorting']= $sorting;
  209.         $twigData['productsAmount'] = 0;
  210.         $twigData['forcedBanner'] = '/assets/frontend/images/categorie-banner.png';
  211.         /* Template dependant */
  212.         $twigData['category'] = new Category();
  213.         $twigData['category']->settitle('Résultats pour '.$string);
  214.         $twigData['selected'] = array(
  215.             'main' => false,
  216.             'sub1' => false,
  217.             'sub2' => false,
  218.             'sub3' => false
  219.         );
  220.         $twigData['regions'] = $em->getRepository(Region::class)->findBy(['province'=>'Qc']);
  221.         $twigData['conservations'] = $em->getRepository(Conservation::class)->findAll();
  222.         $query $this->findProducts($string);
  223.         switch($type){
  224.         case 'p':
  225.             $paginator $this->validProductFinder->findPaginated($query);
  226.             $twigData['amountSearch'] = $paginator->getNbResults();
  227.             $twigData['products'] = $paginator;
  228.             if($twigData['amountSearch'] == 1){
  229.                 $product current($this->validProductFinder->find($query));
  230.                 return $this->redirectToRoute('viewProduct', array(
  231.                     'producerUrl' => $product->getCompany()->getUrlName(),
  232.                     'productName' => $product->getUrlName(),
  233.                     'id' => $product->getId()
  234.                 ));
  235.             }
  236.             break;
  237.         case 'c':
  238.             $paginator $this->validCompanyFinder->findPaginated($query);
  239.             $twigData['amountSearch'] = $paginator->getNbResults();
  240.             $twigData['companies'] = $paginator;
  241.             if($twigData['amountSearch'] == 1){
  242.                 $company current($this->validCompanyFinder->find($query));
  243.                 return $this->redirectToRoute('companyStore', array(
  244.                     'urlname' => $company->getUrlName(),
  245.                     'id' => $company->getId()
  246.                 ));
  247.             }
  248.             break;
  249.             //All
  250.         case 'a':
  251.             $twigData['products'] = array();
  252.             $mngr $this->indexManager;
  253.             $amount $this->em->getRepository(Product::class)->searchForProducts($stringtrue);
  254.             $query $this->em->getRepository(Product::class)->searchForProducts($stringfalse$sorting$order);
  255.             $twigData['productsAmount'] = $amount;
  256.             $page 1;
  257.             if(!empty($request->get('page')))
  258.                 $page $request->get('page');
  259.             $twigData['products']= $paginator->paginate(
  260.               $query,
  261.               $request->query->getInt('page'$page),
  262.               20
  263.             );
  264.             $twigData['suggestionProductsAmount'] = 0;
  265.             $twigData['suggestionProducts'] = false;
  266.             if ($amount <= 5) {
  267.               $squery $this->findProducts($string);
  268.               $adapter $this->validProductFinder->createPaginatorAdapter($squery);
  269.               $Epaginator $this->validProductFinder->findPaginated($squery);
  270.               $twigData['suggestionProductsAmount'] = $Epaginator->getNbResults();
  271.               $twigData['suggestionProducts'] = $paginator->paginate(
  272.                 $adapter,
  273.                 $request->query->getInt('page'$page),
  274.                 20
  275.               );
  276.               $suggestionProducts = [];
  277.               foreach($twigData['suggestionProducts'] as $sp) {
  278.                 $include true;
  279.                 foreach($twigData['products'] as $p) {
  280.                   if ($sp->getId() == $p->getId()) {
  281.                     $include false;
  282.                     break;
  283.                   }
  284.                 }
  285.                 if ($include) {
  286.                   $suggestionProducts[] = $sp;
  287.                 }
  288.               }
  289.               $twigData["suggestionProducts"] = $suggestionProducts;
  290.             }
  291.             break;
  292.         }
  293.         $userServ->saveSearch($string$twigData['productsAmount'], $type);
  294.         return $twigData;
  295.     }
  296.     function removeAccents($string) {
  297.         if ( !preg_match('/[\x80-\xff]/'$string) )
  298.             return $string;
  299.         $chars = array(
  300.             // Decompositions for Latin-1 Supplement
  301.             chr(195).chr(128) => 'A'chr(195).chr(129) => 'A',
  302.             chr(195).chr(130) => 'A'chr(195).chr(131) => 'A',
  303.             chr(195).chr(132) => 'A'chr(195).chr(133) => 'A',
  304.             chr(195).chr(135) => 'C'chr(195).chr(136) => 'E',
  305.             chr(195).chr(137) => 'E'chr(195).chr(138) => 'E',
  306.             chr(195).chr(139) => 'E'chr(195).chr(140) => 'I',
  307.             chr(195).chr(141) => 'I'chr(195).chr(142) => 'I',
  308.             chr(195).chr(143) => 'I'chr(195).chr(145) => 'N',
  309.             chr(195).chr(146) => 'O'chr(195).chr(147) => 'O',
  310.             chr(195).chr(148) => 'O'chr(195).chr(149) => 'O',
  311.             chr(195).chr(150) => 'O'chr(195).chr(153) => 'U',
  312.             chr(195).chr(154) => 'U'chr(195).chr(155) => 'U',
  313.             chr(195).chr(156) => 'U'chr(195).chr(157) => 'Y',
  314.             chr(195).chr(159) => 's'chr(195).chr(160) => 'a',
  315.             chr(195).chr(161) => 'a'chr(195).chr(162) => 'a',
  316.             chr(195).chr(163) => 'a'chr(195).chr(164) => 'a',
  317.             chr(195).chr(165) => 'a'chr(195).chr(167) => 'c',
  318.             chr(195).chr(168) => 'e'chr(195).chr(169) => 'e',
  319.             chr(195).chr(170) => 'e'chr(195).chr(171) => 'e',
  320.             chr(195).chr(172) => 'i'chr(195).chr(173) => 'i',
  321.             chr(195).chr(174) => 'i'chr(195).chr(175) => 'i',
  322.             chr(195).chr(177) => 'n'chr(195).chr(178) => 'o',
  323.             chr(195).chr(179) => 'o'chr(195).chr(180) => 'o',
  324.             chr(195).chr(181) => 'o'chr(195).chr(182) => 'o',
  325.             chr(195).chr(182) => 'o'chr(195).chr(185) => 'u',
  326.             chr(195).chr(186) => 'u'chr(195).chr(187) => 'u',
  327.             chr(195).chr(188) => 'u'chr(195).chr(189) => 'y',
  328.             chr(195).chr(191) => 'y',
  329.             // Decompositions for Latin Extended-A
  330.             chr(196).chr(128) => 'A'chr(196).chr(129) => 'a',
  331.             chr(196).chr(130) => 'A'chr(196).chr(131) => 'a',
  332.             chr(196).chr(132) => 'A'chr(196).chr(133) => 'a',
  333.             chr(196).chr(134) => 'C'chr(196).chr(135) => 'c',
  334.             chr(196).chr(136) => 'C'chr(196).chr(137) => 'c',
  335.             chr(196).chr(138) => 'C'chr(196).chr(139) => 'c',
  336.             chr(196).chr(140) => 'C'chr(196).chr(141) => 'c',
  337.             chr(196).chr(142) => 'D'chr(196).chr(143) => 'd',
  338.             chr(196).chr(144) => 'D'chr(196).chr(145) => 'd',
  339.             chr(196).chr(146) => 'E'chr(196).chr(147) => 'e',
  340.             chr(196).chr(148) => 'E'chr(196).chr(149) => 'e',
  341.             chr(196).chr(150) => 'E'chr(196).chr(151) => 'e',
  342.             chr(196).chr(152) => 'E'chr(196).chr(153) => 'e',
  343.             chr(196).chr(154) => 'E'chr(196).chr(155) => 'e',
  344.             chr(196).chr(156) => 'G'chr(196).chr(157) => 'g',
  345.             chr(196).chr(158) => 'G'chr(196).chr(159) => 'g',
  346.             chr(196).chr(160) => 'G'chr(196).chr(161) => 'g',
  347.             chr(196).chr(162) => 'G'chr(196).chr(163) => 'g',
  348.             chr(196).chr(164) => 'H'chr(196).chr(165) => 'h',
  349.             chr(196).chr(166) => 'H'chr(196).chr(167) => 'h',
  350.             chr(196).chr(168) => 'I'chr(196).chr(169) => 'i',
  351.             chr(196).chr(170) => 'I'chr(196).chr(171) => 'i',
  352.             chr(196).chr(172) => 'I'chr(196).chr(173) => 'i',
  353.             chr(196).chr(174) => 'I'chr(196).chr(175) => 'i',
  354.             chr(196).chr(176) => 'I'chr(196).chr(177) => 'i',
  355.             chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
  356.             chr(196).chr(180) => 'J'chr(196).chr(181) => 'j',
  357.             chr(196).chr(182) => 'K'chr(196).chr(183) => 'k',
  358.             chr(196).chr(184) => 'k'chr(196).chr(185) => 'L',
  359.             chr(196).chr(186) => 'l'chr(196).chr(187) => 'L',
  360.             chr(196).chr(188) => 'l'chr(196).chr(189) => 'L',
  361.             chr(196).chr(190) => 'l'chr(196).chr(191) => 'L',
  362.             chr(197).chr(128) => 'l'chr(197).chr(129) => 'L',
  363.             chr(197).chr(130) => 'l'chr(197).chr(131) => 'N',
  364.             chr(197).chr(132) => 'n'chr(197).chr(133) => 'N',
  365.             chr(197).chr(134) => 'n'chr(197).chr(135) => 'N',
  366.             chr(197).chr(136) => 'n'chr(197).chr(137) => 'N',
  367.             chr(197).chr(138) => 'n'chr(197).chr(139) => 'N',
  368.             chr(197).chr(140) => 'O'chr(197).chr(141) => 'o',
  369.             chr(197).chr(142) => 'O'chr(197).chr(143) => 'o',
  370.             chr(197).chr(144) => 'O'chr(197).chr(145) => 'o',
  371.             chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
  372.             chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
  373.             chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
  374.             chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
  375.             chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
  376.             chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
  377.             chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
  378.             chr(197).chr(160) => 'S'chr(197).chr(161) => 's',
  379.             chr(197).chr(162) => 'T'chr(197).chr(163) => 't',
  380.             chr(197).chr(164) => 'T'chr(197).chr(165) => 't',
  381.             chr(197).chr(166) => 'T'chr(197).chr(167) => 't',
  382.             chr(197).chr(168) => 'U'chr(197).chr(169) => 'u',
  383.             chr(197).chr(170) => 'U'chr(197).chr(171) => 'u',
  384.             chr(197).chr(172) => 'U'chr(197).chr(173) => 'u',
  385.             chr(197).chr(174) => 'U'chr(197).chr(175) => 'u',
  386.             chr(197).chr(176) => 'U'chr(197).chr(177) => 'u',
  387.             chr(197).chr(178) => 'U'chr(197).chr(179) => 'u',
  388.             chr(197).chr(180) => 'W'chr(197).chr(181) => 'w',
  389.             chr(197).chr(182) => 'Y'chr(197).chr(183) => 'y',
  390.             chr(197).chr(184) => 'Y'chr(197).chr(185) => 'Z',
  391.             chr(197).chr(186) => 'z'chr(197).chr(187) => 'Z',
  392.             chr(197).chr(188) => 'z'chr(197).chr(189) => 'Z',
  393.             chr(197).chr(190) => 'z'chr(197).chr(191) => 's'
  394.         );
  395.         $string strtr($string$chars);
  396.         return $string;
  397.     }
  398. }