src/WebBundle/Controller/TileController.php line 93

Open in your IDE?
  1. <?php
  2. namespace WebBundle\Controller;
  3. use AdmBundle\Helper\Adm;
  4. use AdmBundle\Helper\StrAdm;
  5. use DateTime;
  6. use Doctrine\ORM\NonUniqueResultException;
  7. use Doctrine\ORM\NoResultException;
  8. use Exception;
  9. use FlexApp\Classes\CommentableEntityTypes;
  10. use FlexApp\DTO\RequestCatalogDTO;
  11. use FlexApp\Helper\MetaHelper;
  12. use Import1CBundle\Helper\v3\ArticleHelper;
  13. use Import1CBundle\Helper\v3\BiConst;
  14. use Import1CBundle\Helper\v3\InteriorHelper;
  15. use Memcache;
  16. use Symfony\Component\HttpFoundation\JsonResponse;
  17. use Symfony\Component\HttpFoundation\RedirectResponse;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  20. use WebBundle\Entity\Visit;
  21. use WebBundle\Helper\App;
  22. use WebBundle\Helper\FilterHelper;
  23. use WebBundle\Helper\ItemHelper;
  24. use WebBundle\Helper\LocaleHelper;
  25. use WebBundle\Helper\PathHelper;
  26. use WebBundle\Helper\RedirectHelper;
  27. use WebBundle\Helper\SearchLogHelper;
  28. use WebBundle\Helper\StatsHelper;
  29. use WebBundle\Helper\StrHelper;
  30. use WebBundle\Helper\UrlHelper;
  31. use WebBundle\Helper\UserHelper;
  32. use WebBundle\Repository\ArticleRepository;
  33. use WebBundle\Repository\BuyOrderRepository;
  34. use WebBundle\Repository\FilterRepository;
  35. use WebBundle\Repository\IdeaRepository;
  36. use WebBundle\Repository\InteriorRepository;
  37. use WebBundle\Repository\PublicationRepository;
  38. use WebBundle\Repository\VisitRepository;
  39. use WebBundle\Service\CollectionService;
  40. use WebBundle\Service\CollectionSettingsService;
  41. use WebBundle\Service\GoogleTranslateService;
  42. use WebBundle\Service\ReviewsService;
  43. use WebBundle\Service\SearchService;
  44. class TileController extends ExtendedController
  45. {
  46.     /** @required */
  47.     public ArticleRepository $articleRepository;
  48.     /** @required */
  49.     public BuyOrderRepository $buyOrderRepository;
  50.     /** @required */
  51.     public FilterRepository $filterRepository;
  52.     /** @required */
  53.     public IdeaRepository $ideaRepository;
  54.     /** @required */
  55.     public InteriorRepository $interiorRepository;
  56.     /** @required */
  57.     public PublicationRepository $publicationRepository;
  58.     /** @required */
  59.     public VisitRepository $visitRepository;
  60.     /** @required */
  61.     public CollectionService $collectionService;
  62.     /** @required */
  63.     public CollectionSettingsService $collectionSettingsService;
  64.     /** @required */
  65.     public ReviewsService $reviewsService;
  66.     /** @required */
  67.     public SearchService $searchService;
  68.     /** @required */
  69.     public GoogleTranslateService $googleTranslateService;
  70.     private int $itemsLimit 20;
  71.     private int $interiorsLimit 20;
  72.     /**
  73.      * @param Request $request
  74.      * @param string $factoryUrl
  75.      * @param string $collectionUrl
  76.      * @param string|null $type
  77.      * @param string|null $elementId
  78.      * @return mixed
  79.      * @throws NoResultException
  80.      * @throws NonUniqueResultException
  81.      * @throws \Doctrine\DBAL\Driver\Exception
  82.      * @throws \Doctrine\DBAL\Exception
  83.      * @throws Exception
  84.      */
  85.     public function indexAction(
  86.         Request $request,
  87.         string $factoryUrl,
  88.         string $collectionUrl,
  89.         ?string $type null,
  90.         ?string $elementId null
  91.     ) {
  92.         // проверка переноса фабрики
  93.         if ($iNeedRedirect RedirectHelper::checkRedirect($factoryUrl$collectionUrl$type$elementId)) {
  94.             return $this->redirect(
  95.                 $this->generateUrl(
  96.                     'app_collection',
  97.                     $iNeedRedirect->getArrayForRedirect()
  98.                 )
  99.             );
  100.         }
  101.         $collection $this->collectionService->findCollectionInDb($factoryUrl$collectionUrl);
  102.         if ($collection['return'] ?? null) {
  103.             return $collection['return'];
  104.         }
  105.         $collection $collection['collection'];
  106.         // нет коллекции
  107.         if (!$collection) {
  108.             throw $this->createNotFoundException('Collection not found');
  109.         }
  110.         // для совместимости
  111.         $key StrAdm::toLower($elementId);
  112.         if ($key == $collection['factory']['url']) {
  113.             return new RedirectResponse(
  114.                 $this->generateUrl('app_collection', [
  115.                     'factoryUrl' => $collection['factory']['url'],
  116.                     'collectionUrl' => $collection['url'],
  117.                 ]),
  118.                 301
  119.             );
  120.         }
  121.         $factoryUrl StrAdm::toLower($factoryUrl);
  122.         $collectionUrl StrAdm::toLower($collectionUrl);
  123.         $collection['interiors'] = $this->interiorRepository->getInteriorsForCollection($collection['id']);
  124.         //todo временно
  125.         if (!empty($collection['process'])) {
  126.             foreach ($collection['interiors'] as $k => $r) {
  127.                 $collection['interiors'][$k]['file'] = preg_replace('#\.jpg#i''.webp'$r['file']);
  128.                 $collection['interiors'][$k]['a_version'] = true;
  129.             }
  130.         }
  131.         $collection['a_version'] = !empty($collection['process']);
  132.         $mainImage PathHelper::pathGenerate('main'$collection);
  133.         // нормализуем данные страны, потом надо будет все это в нормализацию перенести
  134.         $country $collection['factory']['country'];
  135.         $keyCountry $this->filterRepository->getKeyByLeftMenu($country['alias']);
  136.         $collection['factory']['country'] = [
  137.             'id' => $country['id'],
  138.             'code' => StrHelper::toLower($country['code']),
  139.             'alias' => App::trans($country['alias']),
  140.             'url' => $collection['collection']['factory']['country']['url'] = App::generateUrl(
  141.                 'app_catalog',
  142.                 ['key' => StrAdm::toLower($keyCountry)],
  143.                 0
  144.             ),
  145.         ];
  146.         // логика по релизам коллекции
  147.         $releaseYear = !empty($collection['releaseYear']) ? $collection['releaseYear'] : null;
  148.         if ($releaseYear) {
  149.             $curYear date("Y");
  150.             $keyYear $curYear == $releaseYear 'release_year_cur' 'release_year_' $releaseYear;
  151.             if ($releaseYear >= '2017') {
  152.                 $releaseYear = [
  153.                     'year' => $collection['releaseYear'],
  154.                     'text' => App::getTranslator()->trans('collection.releaseYear', ['%d%' => $releaseYear]),
  155.                     'link' => FilterHelper::getUrl([$keyYear]),
  156.                 ];
  157.             } else {
  158.                 $releaseYear null;
  159.             }
  160.         }
  161.         if (!empty($collection['awards'])) {
  162.             $aAwards $this->filterRepository->getAwards($collection['awards']);
  163.             if ($aAwards) {
  164.                 $collection['awards'] = array_values($aAwards);
  165.             }
  166.         }
  167.         // статус использования фильтрации
  168.         $interiorsIds false;
  169.         $itemsIds false;
  170.         $filters $type && $type == 'f' && $key;
  171.         if ($filters) {
  172.             //специальная проверка для псевдофильтра по артикулу
  173.             if (preg_match('#item-(.+)$#'$key$matches)) {
  174.                 $item $this->articleRepository->getItemUrlById($matches[1]);
  175.                 if (!empty($item['url'])) {
  176.                     return new RedirectResponse(
  177.                         $this->generateUrl('app_collection_slideshow', [
  178.                             'factoryUrl' => $collection['factory']['url'],
  179.                             'collectionUrl' => $collection['url'],
  180.                             'type' => 'a',
  181.                             'elementId' => $item['url'],
  182.                         ])
  183.                     );
  184.                 }
  185.             } else {
  186.                 $keyArr explode('&'$key);
  187.                 if (count($keyArr) > 0) {
  188.                     $keyNew implode('&'$keyArr);
  189.                     if ($keyNew != $key) {
  190.                         $url $this->generateUrl(
  191.                             'app_collection',
  192.                             [
  193.                                 '_locale' => App::getCurLocale(true),
  194.                                 'factoryUrl' => $factoryUrl,
  195.                                 'collectionUrl' => $collectionUrl,
  196.                                 'type' => $type,
  197.                                 'key' => $keyNew,
  198.                             ]
  199.                         );
  200.                         return new RedirectResponse($url301);
  201.                     }
  202.                 } else {
  203.                     $url $this->generateUrl(/*'app_tile'*/
  204.                         'app_collection',
  205.                         [
  206.                             '_locale' => App::getCurLocale(true),
  207.                             'factoryUrl' => $factoryUrl,
  208.                             'collectionUrl' => $collectionUrl,
  209.                         ]
  210.                     );
  211.                     return new RedirectResponse($url301);
  212.                 }
  213.                 $searchFilter = [
  214.                     'c_id' => [$collection['id']],
  215.                     'inside' => true,
  216.                 ];
  217.                 $reqCatDTO = new RequestCatalogDTO($request$keynull);
  218.                 $oSearchService $this->searchService->setFilter($reqCatDTO$searchFilter);
  219.                 $titleHtml strip_tags($oSearchService->getTitleHtml());
  220.                 $titleHtml preg_replace('/ edit/ui'''$titleHtml);
  221.                 //  перенаправляем на верную страницу каталога
  222.                 if ($oSearchService->isRedirect()) {
  223.                     return $oSearchService->getRedirect();
  224.                 }
  225.                 $data $oSearchService->getSearchData();
  226.                 $keyString serialize($data);
  227.                 $memcache_key 'sphinx' md5($keyString);
  228.                 $searchTrue_cache App::getMemcache()->get($memcache_key);
  229.                 if ($searchTrue_cache !== false) {
  230.                     $searchTrue $searchTrue_cache;
  231.                 } else {
  232.                     $searchTrue App::searchSphinx($data0true);
  233.                     App::getMemcache()->set($memcache_key$searchTrue);
  234.                 }
  235.                 // собираем id подходящих артикулов и интерьеров
  236.                 if (!empty($searchTrue) && $searchTrue != false) {
  237.                     $interiorsIds = !empty($searchTrue[0]['interiors'])
  238.                         ? array_values(array_unique(array_column($searchTrue[0]['interiors'], 'i_id')))
  239.                         : false;
  240.                     $itemsIds = !empty($searchTrue[0]['articles'])
  241.                         ? array_values(array_unique(array_column($searchTrue[0]['articles'], 'a_id')))
  242.                         : false;
  243.                 }
  244.                 $filters = [
  245.                     'list' => $this->collectionService->getSettingsFiltersCollection($oSearchService),
  246.                     'linkToCataloge' => $this->generateUrl('app_catalog', ['key' => $key]),
  247.                 ];
  248.                 $isInteriorsSuitable false;
  249.                 $sortInteriorsIds=[];
  250.                 foreach ($collection['interiors'] as $i => $interior) {
  251.                     if ($interiorsIds && in_array($interior['id'], $interiorsIds)) {
  252. //                        App::debug(array_search($interior['id'], $interiorsIds));
  253.                         $collection['interiorsSuitable'][array_search($interior['id'], $interiorsIds)] = $interior;
  254.                         $sortInteriorsIds[array_search($interior['id'], $interiorsIds)] = $interior['id'];
  255.                         unset($collection['interiors'][$i]);
  256.                         $isInteriorsSuitable true;
  257.                     }
  258.                 }
  259.                 if ($isInteriorsSuitable) {
  260.                     ksort($collection['interiorsSuitable']);
  261.                   $collection['interiorsSuitable']= array_values($collection['interiorsSuitable']);
  262.                     $collection['interiors'] = array_values($collection['interiors']);
  263.                     $interiorsIds $sortInteriorsIds;
  264.                 }
  265. //                App::debugExit($collection['interiorsSuitable']);
  266.             }
  267.         } else {
  268.             $this->oSession()->set('searchData', []);
  269.             $collection['interiorsSuitable'] = [];
  270.         }
  271.         $imagePreload null;
  272.         $imagePreload2 null;
  273.         if (!empty($collection['interiorsSuitable'])){
  274.             foreach ($collection['interiorsSuitable'] as $i => $interior) {
  275.                 $itemInterior InteriorHelper::getInteriorDetails($interior$collection$i$key);
  276.                 $collection['interiorsSuitable'][$i] = $itemInterior;
  277.                 if (!$imagePreload && !empty($itemInterior['pathImg'])) {
  278.                     $imagePreload $itemInterior['pathImg'];
  279.                 }
  280.                 if ($imagePreload && !$imagePreload2 && !empty($itemInterior['pathImg'])) {
  281.                     $imagePreload2 $itemInterior['pathImg'];
  282.                 }
  283.             }
  284.         }
  285.         foreach ($collection['interiors'] as $i => $interior) {
  286.             $itemInterior InteriorHelper::getInteriorDetails($interior$collection$i$key);
  287.             $collection['interiors'][$i] = $itemInterior;
  288.             if (!$imagePreload && !empty($itemInterior['pathImg'])) {
  289.                 $imagePreload $itemInterior['pathImg'];
  290.             }
  291.             if ($imagePreload && !$imagePreload2 && !empty($itemInterior['pathImg'])) {
  292.                 $imagePreload2 $itemInterior['pathImg'];
  293.             }
  294.         }
  295.         $reviews $this->reviewsService->getReviewsByCollectionId((int) $collection['id']);
  296. //App::debugExit($collection['interiors'],$collection['interiorsSuitable']);
  297.         $preData $reviews;
  298.         unset($preData['percent']);
  299.         unset($preData['list']);
  300.         unset($preData['stars']);
  301.         // получаем все количество интерьеров и артикулов коллекции
  302.         $interiorsCount $this->interiorRepository->countInteriorsColl($collection['id']);
  303.         $interiorsSuitableCount $interiorsIds $this->interiorRepository->countInteriorsColl(
  304.             $collection['id'],
  305.             $interiorsIds
  306.         ) : 0;
  307.         $favorites $this->ideaRepository->getInteriorsIdeasByToken(UserHelper::getInstance()->getToken());
  308.         $isFreezed in_array($collection['status'], [BiConst::STATE_DISCONTINUEDBiConst::STATE_PROCESSING])
  309.             || in_array($collection['factory']['status'], [BiConst::STATE_DISCONTINUEDBiConst::STATE_PROCESSING]);
  310.         //         вызывало такую ошибку https://te.remote.team/#/discus/C3E213E9-F69E-543B-6D32-4F5724BC1FA5/
  311.         //        if ($itemsIds) {
  312.         //            $itemsCount = count($itemsIds);
  313.         ////            $itemsIdArray = $itemsIds;
  314.         //        } else {
  315.         //            $itemsIdArray = $repoArticle->getArticlesIdColl($collection['id']);
  316.         //            $itemsCount = $repoArticle->countArticlesColl($collection['id'], false, $isFreezed);
  317.         //        }
  318.         $itemsIdArray $this->articleRepository->getArticlesIdColl($collection['id']);
  319.         $itemsCount $this->articleRepository->countArticlesColl($collection['id'], false$isFreezed);
  320.         // отключили артикулы без изображений https://te.remote.team/#/discus/89045B58-C74C-0E9E-762B-13C59633635A/
  321.         //$itemsNoImgCount = $repoArticle->countArticlesColl($collection['id'], false, $isFreezed, true);
  322.         $userCurrency LocaleHelper::getCur();
  323.         $currency LocaleHelper::getCurrency();
  324.         // получение минимальной цены арта
  325.         $minPrice $this->articleRepository->getArticleMinPriceByCollectionId($collection['id']);
  326.         $settings '';
  327.         $settingsReact = [];
  328.         if (!empty($collection['fids'])) {
  329.             $settings $this->collectionSettingsService->getFiltersHtml($collection['fids']);
  330.             $settingsReact $this->collectionSettingsService->getFilters($collection['fids'], true);
  331.         }
  332.         $publishDate $collection['publishDate'];
  333.         if ($publishDate instanceof DateTime) {
  334.             $publishDate $publishDate->format('d.m.Y');
  335.         }
  336.         $msg $this->collectionService->getAlertMessageIfCollectionInDiscontinuedState($collection);
  337.         $collection array_merge($collection, [
  338.             'ratingHelp' => App::trans(
  339.                 $collection['rating'] == 1
  340.                     'collection_ideas_summ'
  341.                     'collection_ideas_summ_many',
  342.                 null,
  343.                 ['%count%' => $collection['rating']]
  344.             ),
  345.             'targetItem' => false,
  346.             'settings' => $settings,
  347.             'settingsReact' => $settingsReact,
  348.             'reviews' => $reviews,
  349.             'preData' => $preData,
  350.             'starsOf' => App::trans('product_review_by'null, ['%d%' => $reviews['percent']['d']]),
  351.             'releaseYear' => $releaseYear,
  352.             'publishDate' => $publishDate,
  353.             'linkEdit' => Adm::linkEdit('adm.collection.edit'$collection['id']),
  354.             'linkEditBi' => Adm::linkEdit('bi_collection_show_check'$collection['id']),
  355.             'isFreezed' => $isFreezed,
  356.             'closed' => ($collection['status'] == BiConst::STATE_DISCONTINUED
  357.                 App::trans('catalog_out_of_production')
  358.                 : ($collection['status'] == BiConst::STATE_PROCESSING
  359.                     App::trans('collection_unavailable')
  360.                     : ''
  361.                 )),
  362.             'closedHelp' => $collection['status'] == BiConst::STATE_PROCESSING
  363.                 App::trans('collection_unavailable_manufacture_desc')
  364.                 : '',
  365.             'filters' => $filters,
  366.             'addIdeaUrl' => App::generateUrl('app_ideas_list', ['id' => '']),
  367.             'interiorsUrl' => App::generateUrl('app_tile_interiors', ['id' => $collection['id']]),
  368.             'itemSettingsUrl' => App::generateUrl('app_article_settings', ['id' => 0]),
  369.             'preDataCollectionReviewsUrl' => App::generateUrl('pre_data_collection_reviews', ['id' => $collection['id']]),
  370.             'collectionReviewsUrl' => App::generateUrl('collection_reviews', ['id' => $collection['id']]),
  371.             'interiorsCount' => $interiorsCount,
  372.             'interiorsIds' => $interiorsIds,
  373.             'interiorsSuitableCount' => $interiorsSuitableCount,
  374.             'interiorsMore' => false,
  375.             'interiorsSuitableMore' => false,
  376.             'favorites' => $favorites,
  377.             'itemsUrl' => App::generateUrl('app_tile_items', ['id' => $collection['id']]),
  378.             'itemsCount' => $itemsCount/* + $itemsNoImgCount*/,
  379.             'itemsIdArray' => $itemsIdArray,
  380.             'itemsSuitableCount' => $itemsIds count($itemsIds) : 0,
  381.             'itemsMore' => true,
  382.             'itemsSuitableMore' => true,
  383.             'itemsNoImgMore' => false,//$repoArticle->countArticlesColl($collection['id'], false) > 0,
  384.             'items' => [],
  385.             'itemsSuitable' => [],
  386.             'itemsNoImg' => [],
  387.             'itemsNoImgCount' => 0,//(int)$itemsNoImgCount,
  388.             'itemsIds' => $itemsIds,
  389.             'alsoViewed' => null,
  390.             'alsoViewedUrl' => App::generateUrl('app_article_info', ['collectionId' => $collection['id']]),
  391.             'commentsCounts' => $this->collectionService->getCommentsCountData($collection['unid'] ?? ''),
  392.             'commentsBlockUrl' => App::generateUrl(
  393.                 'app_comment_block',
  394.                 [
  395.                     'entity' => $collection['id'],
  396.                     'type' => CommentableEntityTypes::COLLECTION,
  397.                     'unid' => $collection['unid'] ?? null,
  398.                 ]
  399.             ),
  400.             'collection_reviews' => '',
  401.             'userCountry' => App::getCurCountry(),
  402.             'userLocale' => App::getCurLocale(),
  403.             'userCurrency' => $userCurrency,
  404.             'currency' => $currency,
  405.             'isWithoutVATPrice' => LocaleHelper::isWithoutVATPrice(10) !== false,
  406.             'vatPercent' => LocaleHelper::includeVATAlways(),
  407.             'measureGb' => LocaleHelper::measureGb(),
  408.             'minPrice' => $minPrice,
  409.             'priceSort' => LocaleHelper::getPrMin($collection),
  410.             'priceSortCur' => LocaleHelper::getCur(),
  411.             'priceSortMea' => LocaleHelper::getUserMeasure(),
  412.             'notRegular' => App::trans(
  413.                 'collection.notRegular',
  414.                 null,
  415.                 [
  416.                     '%suspended_brand%' => $collection['factory']['name'],
  417.                 ]
  418.             ),
  419.             'trans' => $this->trans(),
  420.             'msg' => $msg,
  421.         ]);
  422. //App::debugExit($collection);
  423.         // получаем мета по данной странице
  424.         $metaManager MetaHelper::getManager($collection);
  425.         $title $metaManager->getTitle();
  426.         if (!empty($titleHtml)) {
  427.             $titleHtml trim(preg_replace('/(^.+\.)/'''$titleHtml), "\n");
  428.             $title preg_replace('/\. .+/'''$title) . '. ' $titleHtml;
  429.         }
  430.         // нормализуем заголовок
  431.         $collHeader $this->get('translator')->trans(
  432.             $collection['header'],
  433.             [
  434.                 '%collection%' => preg_replace('#\\(.*\\)#isUu'''$collection['ActualName']),
  435.                 '%factory%' => $collection['factory']['ActualName'],
  436.                 '%factoryUrl%' => App::generateUrl(
  437.                     'app_catalog',
  438.                     [
  439.                         'key' => $factoryUrl,
  440.                     ],
  441.                     UrlGeneratorInterface::ABSOLUTE_URL
  442.                 ),
  443.             ]
  444.         );
  445.         // защита от "дурака" когда в переводе добавляют в начало ссылки /;
  446.         $collection['header'] = str_replace('href="/''href="'$collHeader);
  447.         // логика под вывод ссылки на затирки и смеси
  448.         if ($glueUrl $collection['glueUrl']) {
  449.             $glue['url'] = $this->generateUrl('app_collection', [
  450.                 'factoryUrl' => $factoryUrl,
  451.                 'collectionUrl' => $glueUrl,
  452.             ]);
  453.             $glue['text'] = App::getTranslator()->trans('adhesives_grouts_glass_link');
  454.             $collection['glue'] = $glue;
  455.         }
  456.         // сохраняем запись в историю обязательно после нормализации заголовка
  457.         $this->addHistory($collection);
  458.         StatsHelper::addHitsColl($collection['id']);
  459.         SearchLogHelper::save(['url' => App::getRequest()->getUri(), 'title' => $title]);
  460.         /* Временно отключена отправка событий */
  461.         // // отправка события в амазон
  462.         // $token = UserHelper::getInstance()->getToken();
  463.         // /** @var UserRepository $userRepo */
  464.         // $userRepo = App::getRepository(User::class);
  465.         // /** @var User $user */
  466.         // $user = $userRepo->getUserByToken($token);
  467.         // $userId = $user ? $user->getId() : 0;
  468.         // $amazonPersonalizeService = $this->getAmazonPersonalizeService();
  469.         // /*$eventSent = нигде не используется*/
  470.         // $amazonPersonalizeService->putEvent($userId, (int)$collection['id'], 'click', App::getSession()->getId());
  471.         // Специальная ссылка на блог
  472.         $blog $this->publicationRepository->find(2232);
  473.         $collection['fastDeliverySamplesUrl'] = UrlHelper::genUrlBlogSingle($blog);
  474. //App::debugExit([
  475. //    'imagePreload' => $imagePreload,
  476. //    'imagePreload2' => $imagePreload2,
  477. //    'mainImage' => $mainImage,
  478. //    'type' => $type,
  479. //    'meta' => [
  480. //        'title' => $title,
  481. //        'description' => $metaManager->getDescription(),
  482. //        'keywords' => $metaManager->getKeywords(),
  483. //        'specs' => $settingsReact ? FilterHelper::filterText($settingsReact) : null,
  484. //    ],
  485. //    'initialState' => ['collection' => $collection],
  486. //    'ldJson' => $collection['status'] == BiConst::STATE_PUBLISHED && LocaleHelper::getPrMin($collection) > 0,
  487. //]);
  488.         return $this->renderReact('@Web/Tile/index.html.twig', [
  489.             'imagePreload' => $imagePreload,
  490.             'imagePreload2' => $imagePreload2,
  491.             'mainImage' => $mainImage,
  492.             'type' => $type,
  493.             'meta' => [
  494.                 'title' => $title,
  495.                 'description' => $metaManager->getDescription(),
  496.                 'keywords' => $metaManager->getKeywords(),
  497.                 'specs' => $settingsReact FilterHelper::filterText($settingsReact) : null,
  498.             ],
  499.             'initialState' => ['collection' => $collection],
  500.             'ldJson' => $collection['status'] == BiConst::STATE_PUBLISHED && LocaleHelper::getPrMin($collection) > 0,
  501.         ]);
  502.         /**
  503.          * для реакта добавлены переменные
  504.          *
  505.          * interior.pathImg
  506.          * [pathImg] => https://img.tile.expert/img_lb/bisazza/campana/per_sito/ambienti/z_bisazza_campana_2_1.jpg
  507.          * interior.x
  508.          * [x] => 314
  509.          * interior.y
  510.          * [y] => 400
  511.          * interior.imgAlt
  512.          * [imgAlt] => Bisazza-campana-1, handmade,designer Style, Bisazza-campana-2, handmade,designer,handmade,designer Style
  513.          * interior.slideShowInteriorLink
  514.          * [slideShowInteriorLink] => /en/slideshow-images/3246088/i/174155/link
  515.          */
  516.     }
  517.     /**
  518.      * Возвращает порцию артикулов коллекции
  519.      * @param int $id
  520.      * @param ?int $page
  521.      * @return JsonResponse
  522.      * @throws Exception
  523.      * @throws \Doctrine\DBAL\Driver\Exception
  524.      */
  525.     public function itemsAction(int $id, ?int $page 1): JsonResponse
  526.     {
  527.         $limit $this->itemsLimit;
  528.         $repoArticle $this->articleRepository;
  529.         $ordersItems $this->buyOrderRepository->getInfoBuyOrderArticle(UserHelper::getInstance()->getToken(), false$id);
  530.         //загрузка до страницы
  531.         if (App::getRequest()->get('loadAll')) {
  532.             $limit $limit $page;
  533.             $page 1;
  534.         }
  535.         $params = [
  536.             'collection' => $id,
  537.             'offset' => $limit $page $limit,
  538.             'limit' => $limit,
  539.         ];
  540.         // показывать так же снятые артикулы
  541.         if (App::getRequest()->get('isFreezed'false) == 'true') {
  542.             $params['isFreezed'] = 1;
  543.         }
  544.         $suitable App::getRequest()->get('suitable'false) == 'true';
  545.         $keyName 'items' . ($suitable 'Suitable' '');
  546.         if (App::getRequest()->get('itemsIds'false) != 'false') {
  547.             $params[$suitable 'items' 'notItems'] = explode(','App::getRequest()->get('itemsIds'));
  548.         }
  549.         $items $repoArticle->getArticleNativeOpt($paramstrue);
  550.         // нужно проставить индексы, чтобы react воспринял как массив
  551.         $res = [];
  552.         $i $params['offset'];
  553.         foreach ($items as $item) {
  554.             if ($texture $item['details']['variantImage']['texture'] ?? null) {
  555.                 $item['variantImage']['texture'] = ItemHelper::addMainPic(
  556.                     $texture,
  557.                     StrHelper::toLower($item['details']['file'])
  558.                 );
  559.             }
  560.             if ($picture $item['details']['variantImage']['picture'] ?? null) {
  561.                 $item['variantImage']['picture'] = ItemHelper::addMainPic(
  562.                     $picture,
  563.                     StrHelper::toLower($item['details']['file'])
  564.                 );
  565.             }
  566.             $item['shape'] = empty($item['shape']) ? ['id' => null'alias' => null] : $item['shape'];
  567.             $item['mea'] = App::trans(LocaleHelper::getMeasure($item));
  568.             $item['amount'] = LocaleHelper::getAmount($item);
  569.             $item['orders'] = !empty($ordersItems[$item['id']]) ? $ordersItems[$item['id']] : false;
  570.             $item['suitable'] = $suitable;
  571.             $options ArticleHelper::getTileArticleAddOptions($item);
  572.             $res[$i] = $options;
  573.             $i++;
  574.         }
  575.         if (count($items) == $limit) {
  576.             $params['limit'] = 1;
  577.             $items $repoArticle->getArticleNativeOpt($paramstrue);
  578.             $more count($items) > 0;
  579.         } else {
  580.             $more false;
  581.         }
  582.         return new JsonResponse(['items' => $res'more' => $more'keyName' => $keyName'nextPage' => $page 1]);
  583.     }
  584.     /**
  585.      * Возвращает порцию интерьеров коллекции
  586.      * @param int $id
  587.      * @param ?int $page
  588.      * @return JsonResponse
  589.      * @throws Exception
  590.      * @internal param string $sort
  591.      */
  592.     public function interiorsAction(int $id, ?int $page 1): JsonResponse
  593.     {
  594.         $limit $this->interiorsLimit;
  595.         $offset $limit $page $limit;
  596.         $suitable App::getRequest()->get('suitable'false) == 'true';
  597.         $keyName 'interiors' . ($suitable 'Suitable' '');
  598.         if (App::getRequest()->get('interiorsIds') && App::getRequest()->get('interiorsIds') != 'false') {
  599.             $params[$suitable 'ids' 'notIds'] = explode(','App::getRequest()->get('interiorsIds'));
  600.         } else {
  601.             $params = [];
  602.         }
  603.         $interiors $this->interiorRepository->getInteriors($id$params);
  604.         $favorites $this->ideaRepository->getInteriorsIdeasByToken(UserHelper::getInstance()->getToken());
  605.         // нужно проставить индексы чтобы react воспринял как массив
  606.         $res = [];
  607.         $i $offset;
  608.         foreach ($interiors as $interior) {
  609.             $alt[] = $interior['name'];
  610.             foreach ($interior['styles'] as $k => $style) {
  611.                 $interiors[$i]['styles'][$k]['alias'] = $alt[] = App::trans($style['alias']);
  612.             }
  613.             foreach ($interior['textures'] as $k => $texture) {
  614.                 $interiors[$i]['textures'][$k]['alias'] = $alt[] = App::trans($texture['alias']);
  615.             }
  616.             $interiors[$i]['alt'] = join(', '$alt);
  617.             $interior['favorite'] = !empty($favorites[$interior['id']]);
  618.             $interior['suitable'] = $suitable;
  619.             $res[$i] = $interior;
  620.             $i++;
  621.         }
  622.         return new JsonResponse(['interiors' => $res'more' => false'keyName' => $keyName]);
  623.     }
  624.     /**
  625.      * Добавляет запись в историю просмотров
  626.      *
  627.      * @param $collection
  628.      * @throws NoResultException
  629.      * @throws NonUniqueResultException
  630.      * @throws Exception
  631.      */
  632.     private function addHistory($collection)
  633.     {
  634.         $headerVisited implode(' ', [
  635.             $collection['ActualName'],
  636.             $this->get('translator')->trans('collection_by'),
  637.             $collection['factory']['ActualName'],
  638.         ]);
  639.         $icon $collection['path'] . 'main.jpg';
  640.         $factoryUrl StrAdm::toLower($collection['factory']['url']);
  641.         $collectionUrl StrAdm::toLower($collection['url']);
  642.         // специально чтобы ссылки с выбранными фильтрами рассматривались как стандартная ссылка на коллекцию
  643.         $url $this->generateUrl(
  644.             'app_collection',
  645.             [
  646.                 '_locale' => App::getCurLocale(true),
  647.                 'factoryUrl' => $factoryUrl,
  648.                 'collectionUrl' => $collectionUrl,
  649.             ],
  650.             0
  651.         );
  652.         $this->visitRepository->setVisit(
  653.             $headerVisited,
  654.             $icon,
  655.             $url,
  656.             null,
  657.             Visit::TYPE_VISIT['COLLECTION'],
  658.             $collection['id']
  659.         );
  660.     }
  661.     /**
  662.      * Переводы для страницы коллекции
  663.      * @return array
  664.      * @throws \Doctrine\DBAL\Driver\Exception
  665.      * @throws \Doctrine\DBAL\Exception
  666.      * @throws Exception
  667.      */
  668.     private function trans(): array
  669.     {
  670.         $translator App::getTranslator();
  671.         return [
  672.             'loc' => App::getCurLocale(true),
  673.             'lang' => App::getCurLocale(),
  674.             'settings' => $translator->trans('collection_marks'),
  675.             'added' => $translator->trans('collection_added'),
  676.             'star' => $translator->trans('reviews.stars.one'),
  677.             'stars' => $translator->trans('reviews.stars.many'),
  678.             'reviewShowAll' => $translator->trans('product_review_show_all'),
  679.             'catalogMoreDown' => $translator->trans('catalog_more_down'),
  680.             'catalogMoreUp' => $translator->trans('catalog_more_up'),
  681.             'descCollectionHeader' => $translator->trans('descCollectionHeader'),
  682.             'commentAddQuestion' => $translator->trans('comment_add_question'),
  683.             'collectionVideos' => $translator->trans('collection.videos'),
  684.             'collectionBack' => $translator->trans('collection_back'),
  685.             'productReview' => [
  686.                 $translator->trans('product_review'),
  687.                 $translator->trans('product_review_'),
  688.                 $translator->trans('product_reviews'),
  689.             ],
  690.             'comments' => $translator->trans('blog_comments'),
  691.             'of' => $translator->trans('of'),
  692.             'more' => $translator->trans('show_more'),
  693.             'effect' => $translator->trans('left_menu_effect'),
  694.             'style' => $translator->trans('left_menu_style'),
  695.             'reviews' => [
  696.                 'heading' => $translator->trans('collection_customer_reviews'),
  697.                 'validUser' => $translator->trans('product_validUser'),
  698.                 'reply' => $translator->trans('reply_comment'),
  699.                 'edit' => $translator->trans('edit'),
  700.                 'save' => $translator->trans('save'),
  701.                 'cancel' => $translator->trans('cancel'),
  702.             ],
  703.             'item' => [
  704.                 'collection' => $translator->trans('collection_name'),
  705.                 'factory' => $translator->trans('catalog_factory'),
  706.                 'characteristics' => $translator->trans('article_characteristics'),
  707.                 'tile' => $translator->trans('footer_tile'),
  708.                 'item' => $translator->trans('collection_article'),
  709.                 'header' => $translator->trans('collection_articles_d'),
  710.                 'formats' => $translator->trans('article_item_formats'),
  711.                 'cm' => $translator->trans('left_menu_cm'),
  712.                 'inch' => '″',
  713.                 'diameter' => $translator->trans('article_item_diameter'),
  714.                 'pcs' => $translator->trans('measure_unit'),
  715.                 'pcsPlural' => $translator->trans('measure_units'),
  716.                 'set' => $translator->trans('measure_set'),
  717.                 'sets' => $translator->trans('measure_sets'),
  718.                 'price' => $translator->trans('catalog_price'),
  719.                 'vat' => [
  720.                     'label' => $translator->trans('vat.label'),
  721.                     'included' => $translator->trans('vat.included'),
  722.                     'excluded' => $translator->trans('vat.excluded'),
  723.                 ],
  724.                 'info' => $translator->trans('article_item_more_info'),
  725.                 'infoLess' => $translator->trans('article_item_less_info'),
  726.                 'order' => [
  727.                     'help' => $translator->trans('buyOrder.help'),
  728.                     'ceilToPallet' => $translator->trans('collection_ceil_to_pallet'),
  729.                     'atentionPallet' => $translator->trans('collection_atention_pallet'),
  730.                     'popupAutoChangeCountArts' => $translator->trans('popup_auto_change_count_arts'),
  731.                 ],
  732.                 'up' => $translator->trans('article.price.up'),
  733.                 'down' => $translator->trans('article.price.down'),
  734.                 'readMore' => $translator->trans('read_more'),
  735.                 'titleAddedArticle' => $translator->trans('buyOrder.titleAddedArticle'),
  736.                 'addIntoOrder' => $translator->trans('buy_order.add_into_order'),
  737.                 'headerOrderAdd' => $translator->trans('header_order_add'),
  738.                 'draft' => $translator->trans('order.status.draft'),
  739.                 'typeMain' => $translator->trans('article.type.main'),
  740.                 'typeSample' => $translator->trans('article.type.sample'),
  741.                 'sampleText' => $translator->trans('article.type.sampleText'),
  742.                 'typeCompare' => $translator->trans('article.type.compare'),
  743.                 'compareText' => $translator->trans('article.type.compareText'),
  744.                 'type3d' => $translator->trans('article.type.3d'),
  745.                 'text3d' => $translator->trans('article.type.3dText'),
  746.                 'articleOrderOver' => $translator->trans('article.order.over'),
  747.                 'articleOrderMultiplies' => $translator->trans('article.order.multiplies'),
  748.                 'articlePricePerPallet' => $translator->trans('article.price.perPallet'),
  749.                 'articlePriceNoLessPallet' => $translator->trans('article.price.noLessPallet'),
  750.                 'articlePricePalleteFrom' => $translator->trans('article.pricePallete.from'),
  751.                 'articlePriceFrom' => $translator->trans('article.price.from'),
  752.                 'articlePricePalleteUnder' => $translator->trans('article.pricePallete.under'),
  753.                 'articlePriceFromTo' => $translator->trans('article.price.from_to'),
  754.                 'articlePriceFromLine' => $translator->trans('catalog_price_from'),
  755.                 'articlePriceToLine' => $translator->trans('dimensions_to'),
  756.                 'boxArticleSingle' => $translator->trans('box_article_single'),
  757.                 'boxArticlePlural' => $translator->trans('box_article_plural'),
  758.                 'articleNoImgTitle' => $translator->trans('article.no_img'),
  759.                 'collectionAddOrder' => $translator->trans('collection_add_order'),
  760.                 'discountinued' => $translator->trans('article.discountinued'),
  761.                 'tempNoUKShippingMsg' => $translator->trans('msg.uk'),
  762.                 'tempUnavailable' => $translator->trans('article.temp_unavailable'),
  763.             ],
  764.             'sample' => [
  765.                 'folder' => $translator->trans('sample.folder.text'),
  766.                 'original' => $translator->trans('sample.original.text'),
  767.                 'piece' => $translator->trans('sample.piece.text'),
  768.                 'title' => $translator->trans('samplePopup.title'),
  769.                 'noMoreShow' => $translator->trans('samplePopup.noMoreShow'),
  770.                 'withDecl' => $translator->trans('article.type.sampleWithDecl'),
  771.                 'alreadyAdded' => $translator->trans('sample_already_added.header'),
  772.             ],
  773.             'interior' => [
  774.                 'header' => $translator->trans('collection_interiors_d'),
  775.                 'msg' => $translator->trans('collection.interior.msg'),
  776.                 'ideaHelp' => [
  777.                     'added' => $translator->trans('idea_msg_added'),
  778.                     'normal' => $translator->trans('idea_msg_normal'),
  779.                     'normalMany' => $translator->trans('idea_msg_normal_many'),
  780.                     'normalZero' => $translator->trans('idea_msg_normal_zero'),
  781.                     'collectionIdeasShort' => $translator->trans('collection_ideas_short'),
  782.                 ],
  783.             ],
  784.             'sampleBlog' => $this->publicationRepository->getUrlBlogExpressSamples(),
  785.             'unavailableFreezedDescArticle' => $translator->trans('collection_unavailable_freezed_desc_article'),
  786.             'collectionTempUnavailable' => $translator->trans('collection.temp_unavailable'),
  787.             'notAvailableInRuCountry' => $translator->trans('product_not_available_in_ru'),
  788.             'searchResult' => $translator->trans('search_result'),
  789.             'suitableElements' => $translator->trans('collection_suitable_elements'),
  790.             'otherElements' => $translator->trans('collection_other_elements'),
  791.             'anonymously' => $translator->trans('anonymously'),
  792.         ];
  793.     }
  794.     public function translateArticleAction(int $elementIdstring $lang): JsonResponse
  795.     {
  796.         return new JsonResponse([
  797.             'result' => $this->googleTranslateService->translateCommentForArticle($elementId$lang),
  798.         ]);
  799.     }
  800. }