src/WebBundle/Controller/TileController.php line 316

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