src/WebBundle/Controller/CatalogController.php line 234

Open in your IDE?
  1. <?php
  2. namespace WebBundle\Controller;
  3. use Exception;
  4. use FlexApp\DTO\RequestCatalogDTO;
  5. use FlexApp\Service\RedisCachePool;
  6. use Symfony\Component\HttpFoundation\JsonResponse;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Symfony\Component\HttpFoundation\Response;
  9. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  10. use WebBundle\Enum\CollectionAndFactoryStateEnum;
  11. use WebBundle\Filler\MessageFiller;
  12. use WebBundle\Helper\App;
  13. use WebBundle\Helper\FilterHelper;
  14. use WebBundle\Helper\HideFactoryCountriesHelper;
  15. use WebBundle\Helper\LocaleHelper;
  16. use WebBundle\Helper\RequestHelper;
  17. use WebBundle\Helper\SearchLogHelper;
  18. use WebBundle\Helper\StatsHelper;
  19. use WebBundle\Repository\CollectionRepository;
  20. use WebBundle\Repository\FactoryRepository;
  21. use WebBundle\Repository\FilterRepository;
  22. use WebBundle\Repository\PublicationRepository;
  23. use WebBundle\Service\ReviewsService;
  24. use WebBundle\Service\SearchService;
  25. use WebBundle\Service\SphinxSearcherService;
  26. use WebBundle\Service\VisitedService;
  27. class CatalogController extends ExtendedController
  28. {
  29.     /** @required */
  30.     public PublicationRepository $publicationRepository;
  31.     /** @required */
  32.     public FilterRepository $filterRepository;
  33.     /** @required */
  34.     public CollectionRepository $collectionRepository;
  35.     /** @required */
  36.     public FactoryRepository $factoryRepository;
  37.     /** @required */
  38.     public VisitedService $visitedService;
  39.     /** @required */
  40.     public SphinxSearcherService $sphinxSearcherService;
  41.     /** @required */
  42.     public ReviewsService $reviewsService;
  43.     /** @required */
  44.     public SearchService $searchService;
  45.     /** @required */
  46.     public MessageFiller $messageFiller;
  47.     public function indexAction(Request $request, ?string $key null$subkey null): Response
  48.     {
  49.         ini_set('memory_limit''2048M');
  50.         $reqCatDTO = new RequestCatalogDTO($request$key$subkey);
  51.         $oSSearch $this->searchService->setFilter($reqCatDTO);
  52.         $oSSearch->setNoWithArticles(true);
  53.         //  перенаправляем на верную страницу каталога
  54.         if ($oSSearch->isRedirect()) {
  55.             return $oSSearch->getRedirect();
  56.         }
  57.         if ($oSSearch->filterService()->isTestingBrand()) {
  58.             if (!App::isRole('ROLE_TEST')) {
  59.                 throw new NotFoundHttpException('factory not found');
  60.             }
  61.         }
  62.         $dataFilterSearch $oSSearch->getSearchKey() ? $oSSearch->getReplaceParentWithChildren() : [];
  63.         $subkey $oSSearch->getSearchSubKey();
  64.         // $oSSearch->setGCount(true); //Тогда будет считать
  65.         $result $oSSearch->getResult();
  66.         $calculate $oSSearch->getCalculate();
  67.         $limit $oSSearch->getLimit();
  68.         $pageCount intval(ceil($result['count'] / ($limit ?: 1)));
  69.         $linkSamples null;
  70.         if ($oSSearch->isPageExpressSample()) {
  71.             $linkSamples $this->publicationRepository->getUrlBlogExpressSamples();
  72.         }
  73.         $factory null;
  74.         if ($oSSearch->filterService() && $oSSearch->filterService()->getCurBrand()) {
  75.             $factoryId $oSSearch->filterService()->getCurBrand()->getId();
  76.             $factory $this->factoryRepository->find($factoryId);
  77.         }
  78.         $factoryReviewsUrl $factory $this->generateUrl('factory_reviews', ['id' => $factory->getId()]) : "";
  79.         list($avgReviewsStar$reviewsTotalCount) = $this->computeAvgStarAndTotalCount($factory$result);
  80.         $titleHtml $oSSearch->getTitleHtml();
  81.         $title $titleHtml !== null trim(strip_tags($titleHtml)) : '';
  82.         //  App::debugExit($oSSearch->getMetaManager()->getTitle(), $oSSearch->getMetaManager()->getDescription());
  83.         $output = [
  84.             'content' => [
  85.                 'h1' => $titleHtml,
  86.                 'html' => $oSSearch->getHtml(),
  87.                 'amount' => $oSSearch->getAmount(),
  88.                 'key' => $key,
  89.                 'subkey' => $subkey,
  90.                 'fullKey' => $key $subkey "/$subkey'',
  91.                 'brand' => $oSSearch->filterService()->getCurBrand(),
  92.                 'isDesigner' => $oSSearch->isDesignerStyle(),
  93.             ],
  94.             'meta' => [
  95.                 'title' => $oSSearch->getMetaManager()->getTitle(),
  96.                 'description' => $oSSearch->getMetaManager()->getDescription(),
  97.                 'keywords' => $oSSearch->getMetaManager()->getKeywords(),
  98.             ],
  99.             'result' => $result,
  100.             'activeFilters' => $oSSearch->getFiltersGTM(),
  101.             'page' => $oSSearch->getPage(),
  102.             'pageCount' => $pageCount,
  103.             'limit' => $limit,
  104.             'sortId' => $oSSearch->getSearchSortId(),
  105.             'sortList' => $oSSearch->getSortList(),
  106.             'discount' => $oSSearch->getDiscount(),
  107.             'top20' => $oSSearch->getTop20(),
  108.             'dataFilterSearch' => json_encode($dataFilterSearch),
  109.             'gclid' => $request->query->get('gclid'null),
  110.             'noindex' => $oSSearch->isNoindex(),
  111.             'isPageReleaseYear' => $oSSearch->isPageReleaseYear(),
  112.             'isPageExhibition' => $oSSearch->isPageExhibition(),
  113.             'linkSamples' => $linkSamples,
  114.             'factoryReviewsUrl' => $factoryReviewsUrl,
  115.         ];
  116.         $output['calculate'] = $calculate ?? []; //попытка передать в твиг
  117.         $output['result']['reviewsTotalCount'] = $reviewsTotalCount;
  118.         $output['result']['avgReviewsStar'] = $avgReviewsStar;
  119.         $output['result']['catalogName'] = $title;
  120.         $output['result']['collectionReviewsUrl'] = $this->getCollectionReviewsUrl($result);
  121.         StatsHelper::addHits($oSSearch->filterService());
  122.         SearchLogHelper::save([
  123.             'url' => App::getRequest()->getUri(),
  124.             'title' => $oSSearch->getMetaManager()->getTitle()
  125.         ]);
  126.         $output['noFloor'] = true;
  127.         unset($output['result']['fReview']);
  128.         // http://te.loc/ru/catalogue/novogres?debug=1
  129.         // переадресация на каталог с сообщением если сняли фабрику
  130.         // https://te.remote.team/#/discus/98061423-1D64-57EB-547F-90E7AD5E8305/
  131.         // убрали переaдресацию, теперь просто показываем сообщение и скрываем результаты показа
  132.         if (
  133.             $oSSearch->isBrands()
  134.             && $oSSearch->isOneFilter()
  135.             && (
  136.                 $oSSearch->filterService()->getCurBrand()->getStatus() == CollectionAndFactoryStateEnum::STATE_DISCONTINUED
  137.                 || in_array($oSSearch->filterService()->getCurBrand()->getId(), HideFactoryCountriesHelper::codes())
  138.             )
  139.         ) {
  140.             $output['msg'] = $this->messageFiller->getMessageForDiscontinuedFactory(
  141.                 $oSSearch->filterService()->getCurBrand()->getName(),
  142.                 $this->generateUrl('app_catalog'),
  143.                 $oSSearch->filterService()->getCurBrand()->getStatus()
  144.             );
  145.         } elseif (
  146.             $oSSearch->isOneFilter()
  147.             && $oSSearch->isDesigner()
  148.             && $oSSearch->getResult()['count'] == 0
  149.         ) {
  150.             // принято решение страницу дизайнера, который не имеет активных коллекций переадресовывать на список дизайнеров
  151.             $keyUrl FilterHelper::checkPageUrl('designer');
  152.             $output['msg'] = $this->messageFiller->getMessageForDiscontinuedDesigner(
  153.                 trim(str_replace('edit'''html_entity_decode($title))),
  154.                 $this->generateUrl('app_catalog', ['key' => $keyUrl])
  155.             );
  156.         }
  157.         $this->visitedService->addHistory($oSSearch);
  158.         if (RequestHelper::isAjax()) {
  159.             if ($oSSearch->getPage() == and !$reqCatDTO->isOnlyPage()) {
  160.                 $response = new JsonResponse(
  161.                     [
  162.                         'content' => $this->render('@Web/Catalog/search-content.html.twig'$output)->getContent(),
  163.                         'key' => $oSSearch->getSearchKey(),
  164.                         'url' => urldecode(
  165.                             $this->generateUrl(
  166.                                 'app_catalog',
  167.                                 ['key' => $oSSearch->getSearchKey(), 'subkey' => $subkey]
  168.                             )
  169.                         ),
  170.                         'dataFilterSearch' => $dataFilterSearch,
  171.                         'title' => $oSSearch->getMetaManager()->getTitle(),
  172.                         'isDesigner' => $oSSearch->isDesignerStyle(),
  173.                         'isPageReleaseYear' => $oSSearch->isPageReleaseYear(),
  174.                         'isPageExhibition' => $oSSearch->isPageExhibition(),
  175.                         'page' => $oSSearch->getPage(),
  176.                         'pageCount' => $pageCount,
  177.                         'limit' => $limit,
  178.                         'count' => $result['count'],
  179.                         'calculate' => $calculate,
  180.                         'history' => [
  181.                             'all' => $this->visitedService->getCountHistory(),
  182.                             'list' => $this->render(
  183.                                 '@Web/Visit/last.html.twig',
  184.                                 ['visited' => $this->visitedService->getLastHistory()]
  185.                             )->getContent(),
  186.                         ],
  187.                         'factoryReviewsUrl' => $factoryReviewsUrl,
  188.                         'avgReviewsStar' => $avgReviewsStar,
  189.                     ]
  190.                 );
  191.                 $key $key ?: $oSSearch->getSearchKey();
  192.                 if (!$oSSearch->getSearchKey()) {
  193.                     $oSSearch->setSearchKey($key);
  194.                 }
  195.             } else {
  196.                 $response = new JsonResponse(
  197.                     [
  198.                         'content' => $this->render('@Web/Catalog/search-result.html.twig'$output)->getContent(),
  199.                         'page' => $oSSearch->getPage(),
  200.                         'pageCount' => $pageCount,
  201.                         'limit' => $limit,
  202.                         'count' => $result['count'],
  203.                     ]
  204.                 );
  205.             }
  206.         } else {
  207.             $response $this->render('@Web/Catalog/index.html.twig'$output); // 179 ms
  208.         }
  209.         // чистим временную сортировку каталога
  210.         App::getSession()->remove('sort_catalog_tmp');
  211.         return $response;
  212.     }
  213.     /**
  214.      * @param string $key
  215.      * @param        $filterKey
  216.      * @return Response
  217.      * @throws Exception
  218.      */
  219.     public function filtersAction(string $key$filterKey)
  220.     {
  221.         $_locale App::getRequest()->get('_locale');
  222.         $_locale $_locale ?: App::getCurLocale();
  223.         //////////////////////////////////////
  224.         // заплатка для локагей вида en_us
  225.         // разбираем локаль и формируем на основании первой части
  226.         // на выдачу меняем локаль сформированную на исходную
  227.         $a_locale explode('-'$_locale);
  228.         $_locale_replace null;
  229.         if (count($a_locale) > 1) {
  230.             $_locale_replace $_locale;
  231.             $_locale $a_locale[0];
  232.         }
  233.         //////////////////////////////////////
  234.         // запрос фильтрации НЕ из каталога через лефт меню
  235.         if ($key == 'add') {
  236.             $word FilterHelper::getWord(null$_locale);
  237.             $url FilterHelper::getUrl(null$_locale$_locale_replace);
  238.             return $this->ok([
  239.                 'post' => RequestHelper::get(),
  240.                 'url' => $url,
  241.                 'word' => $word,
  242.             ]);
  243.         } elseif ($key == 'get-uri') {
  244.             $word FilterHelper::getWord($filterKey$_locale);
  245.             $url FilterHelper::getUrl($filterKey$_locale$_locale_replace);
  246.             return $this->ok([
  247.                 'url' => $url,
  248.                 'word' => $word,
  249.                 '$key' => $key,
  250.                 '_locale' => $_locale,
  251.                 '$filterKey' => $filterKey,
  252.             ]);
  253.         } elseif ($key == 'list-designer') {
  254.             $isReact $filterKey == 'react';
  255.             $aids = [];
  256.             // адский костыль, но пока иначе никак
  257.             // получаем выдачу коллекций и по ним формируем список дизайнеров
  258.             $referer = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
  259.             if ($referer) {
  260.                 $keyNorm explode('/'$referer);
  261.                 $keyNorm array_pop($keyNorm);
  262.                 $keyNorm explode('?'$keyNorm);
  263.                 $keyNorm $keyNorm[0];
  264.                 $keyNorm explode('&'$keyNorm);
  265.                 $searchFilter $this->filterRepository->getFiltersForSearchSphinx($keyNorm$_locale);
  266.                 $data = [
  267.                     "searchFilter" => $searchFilter,
  268.                     "searchSort" => "3",
  269.                     "searchPeriod" => null,
  270.                     "locale" => $_locale,
  271.                 ];
  272.                 $sphRes $this->sphinxSearcherService->searchSphinx($data3falsetruetrue);
  273.                 $allCalculate $sphRes['res']['calculate'] ?? $sphRes['calculate'];
  274.                 $sphRes $sphRes['res']['collections'] ?? $sphRes['collections'];
  275.                 $cids array_column($sphRes'c_id');
  276.                 if ($cids) {
  277.                     $aids $this->collectionRepository->getCollAuthorIds($cids);
  278.                 }
  279.             } else {
  280.                 $redisCachePool App::getContainer()->get(RedisCachePool::class)->getPool();
  281.                 $cc App::getCurCountry();
  282.                 $msr LocaleHelper::getUserMeasure();
  283.                 $memKeyCalc 'all_calculate_' $cc '_' $msr//
  284.                 $allCalculateItem $redisCachePool->getItem($memKeyCalc);
  285.                 if ($allCalculateItem->isHit()) {
  286.                     $allCalculate $allCalculateItem->get();
  287.                 } else {
  288.                     $allCalculate false;
  289.                 }
  290.             }
  291.             // получение и формирования списка дизайнеров в каталоге /.../catalogue/designer
  292.             $listDesigner $this->filterRepository->getListDesignersForCataloge($aids);
  293.             $listDesignersCnt count($listDesigner);
  294.             $aLlistDesigner = [];
  295.             $keyDesignerStyle $this->filterRepository->getKeyDesignerStyle($_locale);
  296.             $keysNew = !empty($keyNorm) ? array_diff($keyNorm, [$keyDesignerStyle]) : [];
  297.             foreach ($listDesigner as $des) {
  298.                 $firstLetter $des['name'][0];
  299.                 $des['slug'] .= !empty($keysNew) ? '&' implode('&'$keysNew) : '';
  300.                 $des['url'] = urldecode($this->generateUrl('app_catalog', ['key' => $des['slug']]));
  301.                 $des['active'] = $filterKey == $des['oldId'];
  302.                 $des['cnt'] = $allCalculate['getDesigner'][$des['id']] ?? 0;
  303.                 if ($des['cnt']) {
  304.                     $aLlistDesigner[$firstLetter][] = $des;
  305.                 }
  306.             }
  307.             if ($isReact) {
  308.                 $content $aLlistDesigner;
  309.             } else {
  310.                 $output $this->render('@Web/Catalog/menu_designers.html.twig', ['listDesigners' => $aLlistDesigner]);
  311.                 $content $output->getContent();
  312.             }
  313.             return $this->ok([
  314.                 'allCount' => $listDesignersCnt,
  315.                 'content' => $content,
  316.             ]);
  317.         } else {
  318.             return $this->error("fail filtersAction not $key");
  319.         }
  320.     }
  321.     private function computeAvgStarAndTotalCount($factory, array $result): array
  322.     {
  323.         $sum 0;
  324.         $count 0;
  325.         $reviewsTotalCount 0;
  326.         if ($factory) {
  327.             $collections $this->reviewsService->getReviewsByFactory($factory);
  328.             foreach ($collections as $collection) {
  329.                 $reviewsTotalCount += count($collection['reviews']);
  330.                 foreach ($collection['reviews'] as $review) {
  331.                     $sum += $review['star'];
  332.                     $count++;
  333.                 }
  334.             }
  335.         } elseif (isset($result['list'])) {
  336.             foreach ($result['list'] as $collection) {
  337.                 $sum += $collection['prc_vote'] ?? 0;
  338.                 $reviewsTotalCount $count += $collection['prc_count'] ?? 0;
  339.             }
  340.         }
  341.         $avgReviewsStar $reviewsTotalCount round($sum $count2) : 0;
  342.         return [$avgReviewsStar$reviewsTotalCount];
  343.     }
  344.     private function getCollectionReviewsUrl(array $result): string
  345.     {
  346.         $collections $this->getCollectionsWithReviews($result);
  347.         if ($collections === '') {
  348.             return '';
  349.         }
  350.         return $this->generateUrl('multiple_collection_reviews', ['collections' => $collections]);
  351.     }
  352.     private function getCollectionsWithReviews(array $result): string
  353.     {
  354.         $collectionsWithReviews = [];
  355.         foreach ($result['list'] as $collection) {
  356.             if (isset($collection['prc_count']) && $collection['prc_count'] > 0) {
  357.                 $collectionsWithReviews[] = $collection['c_id'];
  358.             }
  359.         }
  360.         return implode(','$collectionsWithReviews);
  361.     }
  362. }