src/WebBundle/Service/FiltersService.php line 1132

Open in your IDE?
  1. <?php
  2. namespace WebBundle\Service;
  3. use AdmBundle\Helper\Adm;
  4. use Exception;
  5. use FlexApp\Constant\CatalogConst;
  6. use FlexApp\DTO\BrandResponseDTO;
  7. use FlexApp\DTO\FilterCatalogDTO;
  8. use FlexApp\DTO\FilterGroupCatalogDTO;
  9. use FlexApp\DTO\FilterGroupsCatalogDTO;
  10. use FlexApp\DTO\FilterResponseDTO;
  11. use FlexApp\Service\RedisCachePool;
  12. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  13. use WebBundle\Entity\Article;
  14. use WebBundle\Entity\Collection;
  15. use WebBundle\Helper\App;
  16. use WebBundle\Helper\ArrHelper;
  17. use WebBundle\Helper\ConversionHelper;
  18. use WebBundle\Helper\LocaleHelper;
  19. use WebBundle\Helper\RequestHelper;
  20. use WebBundle\Helper\StrHelper;
  21. use WebBundle\Repository\ArticleRepository;
  22. use WebBundle\Repository\CollectionRepository;
  23. use WebBundle\Repository\FilterRepository;
  24. use WebBundle\Repository\LastUrlRepository;
  25. class FiltersService extends ExtendService
  26. {
  27.     private string $locale;
  28.     private ?int $alsoCollViewedId null;
  29.     private ?bool $isOneFilter null;
  30.     /**
  31.      * Исходные выбранные ID фильтров ДО применения margeFilters().
  32.      * Нужны, чтобы отличать "родитель выбран, потому что выбрали всех детей"
  33.      * от ситуации "в данных пришёл только родитель" (когда нельзя автоматически
  34.      * подставлять/показывать всех детей).
  35.      *
  36.      * @var array<int|string>
  37.      */
  38.     private array $aCurFilterIdsOriginal = [];
  39.     private $urlKeyStr = [];
  40.     /** @var array|FilterResponseDTO[] */
  41.     private array $curFilters = [];
  42.     /** массив id фильтров */
  43.     protected $aCurFilterIds = [];
  44.     /** не найденные ключи из строки запроса*/
  45.     protected array $aBadKeys = [];
  46.     /** разделить параметров УРЛ фильтров  '&'*/
  47.     protected string $separator CatalogConst::SEPARATOR;
  48.     /** Массив для фильтра размеров */
  49.     private array $aDimensions = [];
  50.     /** Массив для фильтра БМов */
  51.     private array $aBMs = [];
  52.     /** @var CollectionRepository */
  53.     protected $collRepo;
  54.     /** @var FilterRepository */
  55.     protected $filterRepo;
  56.     /** @var ArticleRepository */
  57.     protected $articleRepo;
  58.     /**
  59.      * @throws Exception
  60.      */
  61.     public function __construct()
  62.     {
  63.         $this->locale App::getCurLocale();
  64.         $this->collRepo App::getRepository('WebBundle:Collection');
  65.         $this->filterRepo App::getRepository('WebBundle:FilterEntity');
  66.         $this->articleRepo App::getRepository('WebBundle:Article');
  67.         return $this;
  68.     }
  69.     /**
  70.      * Сортировка , что бы вывод был в том положении, как лайт меню
  71.      * @return FilterResponseDTO[]
  72.      */
  73.     private function getSortedFiltersLikeInTheLiteMenu()
  74.     {
  75.         $pattern = [
  76.             'brand',
  77.             'effect',
  78.             'style',
  79.             'price',
  80.             'color',
  81.             'using',
  82.             'samples',
  83.         ];
  84.         $arr = [];
  85.         foreach ($this->curFilters as $filter) {
  86.             $arr[$filter->getGroupAltName()][] = $filter;
  87.         }
  88.         $res = [];
  89.         foreach (array_flip($pattern) as $k => $v) {
  90.             if (isset($arr[$k])) {
  91.                 $res[$k] = $arr[$k];
  92.                 unset($arr[$k]);
  93.             }
  94.         }
  95.         $af = [];
  96.         foreach ($res as $v) {
  97.             $af array_merge($af$v);
  98.         }
  99.         foreach ($arr as $v) {
  100.             $af array_merge($af$v);
  101.         }
  102.         return $af;
  103.     }
  104.     /**
  105.      * @param array $curFilters
  106.      */
  107.     private function setCurFilters(array $curFilters)
  108.     {
  109.         $this->curFilters $curFilters;
  110.     }
  111.     private function margeFilters()
  112.     {
  113.         // Сохраняем исходный набор выбранных фильтров до "сжатия" детей в родителя
  114.         if (!$this->aCurFilterIdsOriginal) {
  115.             $this->aCurFilterIdsOriginal $this->aCurFilterIds;
  116.         }
  117.         $parentMap $this->filterRepo->getFiltersSubRelation(true);
  118.         $result $this->aCurFilterIds;
  119.         foreach ($parentMap as $parentId => $childIds) {
  120.             // Проверяем, все ли дочерние ID присутствуют в выбранных фильтрах
  121.             $allChildrenPresent true;
  122.             foreach ($childIds as $childId) {
  123.                 if (!in_array($childId$result)) {
  124.                     $allChildrenPresent false;
  125.                     break;
  126.                 }
  127.             }
  128.             // Если все дети присутствуют, заменяем их на родителя
  129.             if ($allChildrenPresent) {
  130.                 $result array_diff($result$childIds); // Удаляем детей
  131.                 $result[] = $parentId// Добавляем родителя
  132.             }
  133.         }
  134.         $this->aCurFilterIds array_values($result);
  135.     }
  136.     public function isMargeFilters(int $filterId 0): bool
  137.     {
  138.         $parentMap $this->filterRepo->getFiltersSubRelation(true);
  139.         if (!array_key_exists($filterId$parentMap)) {
  140.             return false;
  141.         }
  142.         // ВАЖНО: проверяем по исходным выбранным ID (до margeFilters),
  143.         // чтобы "показывать всех детей" только когда реально выбрали ВСЕХ детей.
  144.         $original $this->aCurFilterIdsOriginal ?: $this->aCurFilterIds;
  145.         $originalStr array_map('strval'$original);
  146.         foreach ($parentMap[$filterId] as $childId) {
  147.             if (!in_array((string) $childId$originalStrtrue)) {
  148.                 return false;
  149.             }
  150.         }
  151.         return true;
  152.     }
  153.     public function unMargeFilters()
  154.     {
  155.         $parentMap $this->filterRepo->getFiltersSubRelation(true);
  156.         $results $this->aCurFilterIds;
  157.         foreach ($results as $result) {
  158.             // Проверяем, все ли дочерние ID присутствуют в выбранных фильтрах
  159.             $allChildrenPresent true;
  160.             if (array_key_exists($result$parentMap)) {
  161.                 $results array_merge($parentMap[$result], $results);
  162.                 //$results = array_diff($results, [$result]);
  163.             }
  164.         }
  165.         $this->aCurFilterIds array_values($results);
  166.         $filters $this->filterRepo->getSortedByIds($this->aCurFilterIds$this->locale);
  167.         $this->setCurFilters($filters);
  168.     }
  169.     /**
  170.      * Универсальная загрузка данных, написал, но еще не использовал
  171.      * @param null $locale
  172.      * @return $this
  173.      * @throws Exception
  174.      */
  175.     private function loadDataUniversal($locale null)
  176.     {
  177.         $locale = !$locale $this->locale $locale;
  178.         if (!$this->curFilters) {
  179.             if (RequestHelper::isAjax()) {
  180.                 $this->loadBySearchData(RequestHelper::get('data', []));
  181.             } else {
  182.                 $this->loadByUrlKey(App::getRequest()->get('key'), $locale);
  183.             }
  184.         }
  185.         return $this;
  186.     }
  187.     /**
  188.      * Поиск по ID фильтров
  189.      * @param $id
  190.      * @return $this
  191.      */
  192.     public function loadByIds($idstring $lc)
  193.     {
  194.         $id is_array($id) ? $id : [$id];
  195.         $this->aCurFilterIds = [];
  196.         $this->aCurFilterIdsOriginal = [];
  197.         $idsParam = [];
  198.         foreach ($id as $item) {
  199.             // обработка через :: для запросов по размерам, т.к. ID там идет вида 56564::0.5
  200.             // где первое - ID, а второе параметр
  201.             $ids explode('::'$item);
  202.             $this->aCurFilterIds[] = $ids[0];
  203.             if (count($ids) > 1) {
  204.                 $idsParam[$ids[0]] = $ids[1];
  205.             }
  206.         }
  207.         // фиксируем "как пришло" до сжатия
  208.         $this->aCurFilterIdsOriginal $this->aCurFilterIds;
  209.         $this->margeFilters();
  210.         $filters $this->filterRepo->getSortedByIds($this->aCurFilterIds$lc);
  211.         foreach ($filters as $i => $filter) {
  212.             // исключаем не активные фильры, если это не фабрики
  213.             if (!$filter->isEnable() and !$filter->getBrand()) {
  214.                 unset($filters[$i]);
  215.             }
  216.         }
  217.         if (count($idsParam) > 0) {
  218.             foreach ($filters as $filter) {
  219.                 if ($filter->isDimension()) {
  220.                     $this->aDimensions[$filter->getAltName()] = $idsParam[$filter->getId()];
  221.                 }
  222.                 if ($filter->isBM()) {
  223.                     $this->aBMs[$filter->getAltName()] = $idsParam[$filter->getId()];
  224.                 }
  225.             }
  226.         }
  227.         $this->setCurFilters($filters);
  228.         return $this;
  229.     }
  230.     public function loadBySearchData($data)
  231.     {
  232.         // новая загрузка — сбрасываем "исходные" выбранные ID до merge
  233.         $this->aCurFilterIdsOriginal = [];
  234.         if (count($data) > 0) {
  235.             $keys $this->findByBaseInOldCommand($data);
  236.             /**
  237.              * Получаем ID сортировки из запроса
  238.              */
  239.             $sortId RequestHelper::get('sort');
  240.             if (!$sortId) {
  241.                 $sortId ArrHelper::get($this->getSearchFilter(), 'getSort.0');
  242.                 $cookies App::getRequest()->cookies;
  243.                 // если нашли ID сортировки, то пишем его в куки
  244.                 if ($sortId) {
  245.                     $cookies->set('sort_catalog'$sortId);
  246.                 }
  247.                 // получаем итоговую сортировку
  248.                 $sortId $cookies->get('sort_catalog');
  249.                 // если не определна. то ставим поппулярность по умолчанию.
  250.                 if (!$sortId) {
  251.                     $cookies->set('sort_catalog'1);
  252.                 }
  253.             }
  254.             $sStyleDesigner $this->isStyleDesignerAndDesigner($keys);
  255.             // пишем ID фильров в массив, из которого и будем формировать всякие URL и прочее
  256.             foreach ($keys as $filter) {
  257.                 if ($filter->isEnable()) {
  258.                     // выкидываем из фильтров сочетание дизайнера + дизайнерский стиль
  259.                     if ($sStyleDesigner) {
  260.                         if ($filter->isDesignerStyle()) {
  261.                             continue;
  262.                         }
  263.                     }
  264.                     if ($filter->isSort()) {
  265.                         continue;
  266.                     }
  267.                     $this->aCurFilterIds[] = $filter->getId();
  268.                     // проверяем на наличие группы фильтров с размерами, если нашли, то
  269.                     // получаем KEY фильтра в текущей локали и по нему ищем значение с троке
  270.                     // после чего формируем массив вида ["size_x" => "40"]
  271.                     if ($filter->isDimension()) {
  272.                         $alias $filter->getAltName();
  273.                         foreach ($data as $iAlias => $aVal) {
  274.                             if ($iAlias == $alias) {
  275.                                 $this->aDimensions[$alias] = $aVal[0];
  276.                             }
  277.                         }
  278.                     }
  279.                     if ($filter->isBM()) {
  280.                         $alias $filter->getAltName();
  281.                         foreach ($data as $iAlias => $aVal) {
  282.                             if ($iAlias == $alias) {
  283.                                 $this->aBMs[$alias] = $aVal[0];
  284.                             }
  285.                         }
  286.                     }
  287.                 }
  288.             }
  289.             // делаем еще запрос в базу, что бы получить объекты фильтров в нужной сортировке
  290.             $this->margeFilters();
  291.             $this->setCurFilters($this->filterRepo->getSortedByIds($this->aCurFilterIds$this->locale));
  292.         }
  293.         return $this;
  294.     }
  295.     //** ресетируем сервис для генерации правильных урл для sitemap и googleAds */
  296.     public function reset(): void
  297.     {
  298.         $this->curFilters = [];
  299.         $this->urlKeyStr = [];
  300.         $this->aCurFilterIds = [];
  301.         $this->aCurFilterIdsOriginal = [];
  302.         $this->searchFilter = [];
  303.     }
  304.     /**
  305.      * Инициируем сам класс, по разбору строки запроса
  306.      * с поиском данных в базе фильтров
  307.      * @param string|null $key
  308.      * @param null $locale
  309.      * @return $this
  310.      * @throws Exception
  311.      */
  312.     public function loadByUrlKey($key$locale null)
  313.     {
  314.         // новая загрузка — сбрасываем "исходные" выбранные ID до merge
  315.         $this->aCurFilterIdsOriginal = [];
  316.         if ($key) {
  317.             $keys $this->urlToArray($key);
  318.             $cntDesigner 0;
  319.             if (count($keys) > 0) {
  320.                 $filters $this->findByBase($keys$locale);
  321.                 // если фильтр AlsoCollViewed , то остальные убираем, на вариант с совпадением по ID
  322.                 if (!empty($filters[10504])) {
  323.                     $filters = [$filters[10504]];
  324.                     $this->alsoCollViewedId $keys[1];
  325.                 }
  326.                 /**
  327.                  * пишем ID фильров в массив, из которого и будем формировать всякие URL и прочее
  328.                  */
  329.                 foreach ($filters as $filter) {
  330.                     // исключаем не активные фильры, если это не фабрики
  331.                     if (!$filter->isEnable() and !$filter->isBrand()) {
  332.                         continue;
  333.                     }
  334.                     // фабрики проверяем дополнительно
  335.                     if ($oBrand $filter->getBrand()) {
  336.                         if (!$oBrand->isShowPage()) {
  337.                             continue;
  338.                         }
  339.                     }
  340.                     // для дизайнеров ограничиваем вывод - не более одного фильтруется
  341.                     if ($filter->isDesignerUser()) {
  342.                         if ($cntDesigner !== 0) {
  343.                             continue;
  344.                         }
  345.                         $cntDesigner++;
  346.                     }
  347.                     // если в запросе сортировка, то пишем данные в куки, а сам фильтр исключаем
  348.                     if ($filter->isSort()) {
  349.                         $cookies App::getRequest()->cookies;
  350.                         if (RequestHelper::get('sort-tmp')) {
  351.                             // временное изменение сортировки, для ссылки New Arrivals с главной сайта
  352.                             App::getSession()->set('sort_catalog_tmp'$filter->getSphinxId());
  353.                         } else {
  354.                             $cookies->set('sort_catalog'$filter->getSphinxId());
  355.                         }
  356.                         continue;
  357.                     }
  358.                     $this->aCurFilterIds[] = $filter->getId();
  359.                     $this->aCurFilterIds array_unique($this->aCurFilterIds);
  360.                     // проверяем на наличие группы фильтров с размерами, если нашли, то
  361.                     // получаем KEY фильтра в текущей локали и по нему ищем значение с троке
  362.                     // после чего формируем массив вида ["size_x" => "40"]
  363.                     if ($filter->isDimension()) {
  364.                         foreach ($keys as $iKey) {
  365.                             $keyDimensionsAll $filter->getSlugsLc();
  366.                             foreach ($keyDimensionsAll as $keyDim) {
  367.                                 if (strval($keyDim) && strpos($iKeystrval($keyDim)) !== false) {
  368.                                     $size str_replace($keyDim '-'''$iKey);
  369.                                     $this->aDimensions[$filter->getAltName()] = $size;
  370.                                 }
  371.                             }
  372.                         }
  373.                     }
  374.                     if ($filter->isBM()) {
  375.                         foreach ($keys as $iKey) {
  376.                             $keyBMs $filter->getSlug();
  377.                             if (strval($keyBMs) && strpos($iKeystrval($keyBMs)) !== false) {
  378.                                 $this->aBMs[$filter->getAltName()] = str_replace($keyBMs '-'''$iKey);
  379.                             }
  380.                         }
  381.                     }
  382.                 }
  383.                 // делаем еще запрос в базу, что бы получить объекты фильтров в нужной сортировке
  384.                 if ($this->aCurFilterIds) {
  385.                     $this->margeFilters();
  386.                     $filters $this->filterRepo->getSortedByIds($this->aCurFilterIds$locale);
  387.                     $this->setCurFilters($filters);
  388.                 }
  389.                 if (!empty($filters) && $this->getSortFilter() == null) {
  390.                     //если фильтры есть исключаем береберду в запросах и ишют по цене или по звездам, то по умолчанию отдаем по поиску
  391.                     if (array_key_exists('getCostCategory'$this->getSearchFilter())) {
  392.                         App::getSession()->set('sort_catalog_tmp'2);
  393.                     } elseif (array_key_exists('reviews'$this->getSearchFilter())) {
  394.                         App::getSession()->set('sort_catalog_tmp'6);
  395.                     } elseif (array_key_exists('getTopMonth'$this->getSearchFilter())) {
  396.                         App::getSession()
  397.                             ->set('sort_catalog_tmp'5);
  398.                     } elseif (array_key_exists('getTopWeek'$this->getSearchFilter())) {
  399.                         App::getSession()
  400.                             ->set('sort_catalog_tmp'1);
  401.                     }
  402.                 }
  403.             }
  404.         }
  405.         return $this;
  406.     }
  407.     /**
  408.      * @param $altName
  409.      * @param string $locale
  410.      * @return $this
  411.      * @throws Exception
  412.      */
  413.     public function loadByAltName($altNamestring $locale)
  414.     {
  415.         $altName is_array($altName) ? $altName : [$altName];
  416.         $filters $this->filterRepo->getByAltNames($altName);
  417.         $fids = [];
  418.         foreach ($filters as $filter) {
  419.             $fids[] = $filter->getId();
  420.         }
  421.         $this->loadByIds($fids$locale);
  422.         return $this;
  423.     }
  424.     /**
  425.      * @param null $papam
  426.      * @param null $locale
  427.      * @return mixed
  428.      * @throws Exception
  429.      */
  430.     public function getUrl($papam null$locale null)
  431.     {
  432.         $word $this->getWord($papam$locale);
  433.         return $this->getFullUrlKeyStr($word$locale);
  434.     }
  435.     /**
  436.      * Получение KEY для URL строки
  437.      * @param null $papam
  438.      * @param null $locale
  439.      * @return string
  440.      * @throws Exception
  441.      */
  442.     public function getWord($papam null$locale null)
  443.     {
  444.         $locale = !$locale $this->locale $locale;
  445.         if (!$this->curFilters) {
  446.             if (!$papam) {
  447.                 // если ничего нет, то грузим то, что есть сейчас в зависимости от типа запроса
  448.                 $this->loadDataUniversal($locale);
  449.             } else {
  450.                 if (is_array($papam)) {
  451.                     if (!empty($papam[0])) {
  452.                         // массив индексный
  453.                         if (intval($papam[0]) === $papam[0]) {
  454.                             // ищем по ID
  455.                             $this->loadByIds($papam$locale);
  456.                         } else {
  457.                             // ищем по altName
  458.                             $this->loadByAltName($papam$locale);
  459.                         }
  460.                     } else {
  461.                         // массив именованый, значит имеем вид запроса ['getUsings'=>[10,12,58]]
  462.                         $this->loadBySearchData($papam);
  463.                     }
  464.                 } else {
  465.                     // если значение строковое, то обрабатываем отдельно
  466.                     if (strripos($papam$this->separator) !== false) {
  467.                         // ищем по KEY url
  468.                         $this->loadByUrlKey($papam$locale);
  469.                     } else {
  470.                         if (intval($papam) === $papam) {
  471.                             // ищем по ID
  472.                             $this->loadByIds($papam$locale);
  473.                         } else {
  474.                             // ищем по KEY url
  475.                             $this->loadByUrlKey($papam$locale);
  476.                             if (count($this->curFilters) < 1) {
  477.                                 // ищем по altName
  478.                                 $this->loadByAltName($papam$locale);
  479.                             }
  480.                         }
  481.                     }
  482.                 }
  483.             }
  484.         }
  485.         return $this->getUrlKeyStr($locale);
  486.     }
  487.     /**
  488.      * Получаем полную строку вместе с KEY по загруженным ранее данным
  489.      * @param null $key
  490.      * @param null $locale
  491.      * @return mixed
  492.      */
  493.     public function getFullUrlKeyStr($key null$locale null)
  494.     {
  495.         if (!$key) {
  496.             $key $this->getUrlKeyStr($locale);
  497.         }
  498.         // пока убрал, т.к. через него лезут левые запросы, нам не нужные
  499.         //      $subkey = RequestHelper::syRequest()->get('subkey');
  500.         //      if ($subkey) {
  501.         //          $params['subkey'] = $subkey;
  502.         //      }
  503.         $params['key'] = $key;
  504.         if ($locale) {
  505.             // если локаль соответсвует текущей, то проверяем на страну доставки
  506.             if ($locale == $this->locale) {
  507.                 $locale App::getCurLocale(true);
  508.             }
  509.             $params['_locale'] = $locale;
  510.         }
  511.         return str_replace('%26''&'$this->generateUrl('app_catalog'$params));
  512.     }
  513.     /**
  514.      * Получаем строку KEY по загруженным ранее данным
  515.      * Получение происходит по ID фильтров из массива
  516.      * @param null $locale
  517.      * @return string
  518.      */
  519.     public function getUrlKeyStr($locale null)
  520.     {
  521.         $locale = ($locale != null) ? $locale $this->locale;
  522.         if (empty($this->urlKeyStr[$locale])) {
  523.             $str '';
  524.             $isStyleDesignerClear $this->isStyleDesignerAndDesigner();
  525.             foreach ($this->curFilters as $filter) {
  526.                 // фильтр галвной каталога игнорируем при генерации URL
  527.                 if (!$filter->isRootCataloge()) {
  528.                     $slug $filter->getSlug($locale);
  529.                     if ($filter->isDimension()) {
  530.                         $altName $filter->getAltName();
  531.                         $size = (float)$this->aDimensions[$altName];
  532.                         $slug $slug '-' $size;
  533.                     }
  534.                     if ($filter->isBM()) {
  535.                         $altName $filter->getAltName();
  536.                         $slug $slug '-' $this->aBMs[$altName];
  537.                     }
  538.                     // урл сортировки не выводим
  539.                     if ($filter->isSort()) {
  540.                         $slug '';
  541.                     }
  542.                     if ($isStyleDesignerClear and $filter->isDesignerStyle()) {
  543.                         $slug '';
  544.                     }
  545.                     $str .= $slug $this->separator;
  546.                 }
  547.             }
  548.             $this->urlKeyStr[$locale] = trim($str$this->separator);
  549.         }
  550.         return $this->urlKeyStr[$locale];
  551.     }
  552.     //{"searchFilter":{"getFacturas":["5"]},"searchSort":"2","searchPeriod":null,"locale":"en"}
  553.     public function getSearchFilter()
  554.     {
  555.         $aSearchFilter = [];
  556.         foreach ($this->curFilters as $filter) {
  557.             $alias $filter->getSphinxName();
  558.             $id false;
  559.             if ($filter->isDimension()) {
  560.                 // если фильтр размеров, то ставим значение поиска, вместо ID фильтра
  561.                 // для строки &width-from-12000 это будет 1200
  562.                 $val = (float)$this->aDimensions[$alias];
  563.             } elseif ($filter->isBM()) {
  564.                 // если фильтр bm, то ставим значение поиска, вместо ID фильтра
  565.                 // для строки &bm-123123 это будет 123123
  566.                 $val $this->aBMs[$alias];
  567.             } elseif ($filter->isTop()) {
  568.                 // если фильтр top, то ставим значение subkey, вместо ID фильтра
  569.                 $val RequestHelper::get('subkey');
  570.                 //  $val = $filter->getId();
  571.             } elseif ($filter->isDesignerUser()) {
  572.                 // пока для дизайнеров делаем параметром их имя
  573.                 $val $filter->getNameSingle();
  574.                 $id $filter->getId();
  575.             } else {
  576.                 $val $filter->getSphinxId();
  577.             }
  578.             if ($id != false) {
  579.                 $aSearchFilter[$alias][] = "{$id}";
  580.             }
  581.             $aSearchFilter[$alias][] = "{$val}";
  582.         }
  583.         return (count($aSearchFilter) > 0) ? $aSearchFilter null;
  584.     }
  585.     /**
  586.      * @param array $data
  587.      * @return array|FilterResponseDTO[]
  588.      * @throws \Doctrine\DBAL\Driver\Exception
  589.      * @throws \Doctrine\DBAL\Exception
  590.      */
  591.     private function findByBaseInOldCommand(array $data)
  592.     {
  593.         $aKeysNew = [];
  594.         if (count($data) > 0) {
  595.             $filterRepo $this->filterRepo;
  596.             // первый проход поиска, ищем по колному кею
  597.             foreach ($data as $old_command => $ids) {
  598.                 // исключаем запросы с коллекциями
  599.                 if ($old_command == 'collection') {
  600.                     continue;
  601.                 }
  602.                 if ($old_command == 'factory') {
  603.                     if (count($ids) > 1) {
  604.                         unset($ids[1]);
  605.                     }
  606.                 } elseif ($old_command == 'getAlsoCollViewed') {
  607.                     $ids = [0];
  608.                 }
  609.                 if ($old_command == 'collection') {
  610.                     continue;
  611.                 }
  612.                 if ($old_command == 'getDesigner') {
  613.                     $filters $filterRepo->getSortedByIds($ids$this->locale);
  614.                 } else {
  615.                     if (!is_array($ids)) {
  616.                         $ids = [$ids];
  617.                     }
  618.                     $filters $filterRepo->getByOldCommand($ids$old_command$this->locale);
  619.                 }
  620.                 if ($filters) {
  621.                     unset($data[$old_command]);
  622.                     foreach ($filters as $filter) {
  623.                         $aKeysNew[$filter->getId()] = $filter;
  624.                     }
  625.                 } else {
  626.                     $filters $filterRepo->getFilterDTOByAltName($old_command$this->locale);
  627.                     if (count($filters) == 1) {
  628.                         $filter $filters[0];
  629.                         unset($data[$old_command]);
  630.                         $aKeysNew[$filter->getId()] = $filter;
  631.                     }
  632.                 }
  633.             }
  634.         }
  635.         // если в массиве еще остались значения , то пишем значения в массив в бед кеями
  636.         // что с ним потом делать пока не знаю, но что то делать будет надо
  637.         if (count($data) > 0) {
  638.             foreach ($data as $key) {
  639.                 $this->aBadKeys[] = $key;
  640.             }
  641.         }
  642.         return $aKeysNew;
  643.     }
  644.     /**
  645.      * Ищем значения в базе по имени фильтра
  646.      * @param array $aKeys
  647.      * @param string|null $locale
  648.      * @return array|FilterResponseDTO[]
  649.      * @throws \Doctrine\DBAL\Driver\Exception
  650.      * @throws \Doctrine\DBAL\Exception
  651.      */
  652.     private function findByBase(array $aKeys$locale null)
  653.     {
  654.         $aKeysNew = [];
  655.         $repoFilter $this->filterRepo;
  656.         if (count($aKeys) > 0) {
  657.             $isSort false;
  658.             // первый проход поиска, ищем по полному кею
  659.             foreach ($aKeys as $i => $key) {
  660.                 // доп логика для фильтрации БМов
  661.                 if (preg_match("/^bm-(\d*)$/"$key)) {
  662.                     $key 'bm';
  663.                 }
  664.                 $filter $repoFilter->getByKeyUrl($key$locale);
  665.                 // если фильтр не нашли, то проходимся дополнительно разложив кей на части
  666.                 if (!$filter) {
  667.                     $dopKeys $this->buldExplodeKeys($key);
  668.                     foreach ($dopKeys as $dkey) {
  669.                         $filter $repoFilter->getByKeyUrl($dkey$locale);
  670.                         if ($filter) {
  671.                             break;
  672.                         }
  673.                     }
  674.                     if (!$filter) {
  675.                         foreach ($dopKeys as $dkey) {
  676.                             $filter $repoFilter->getByKeyUrlIsLike($dkey$locale);
  677.                             if ($filter) {
  678.                                 break;
  679.                             }
  680.                         }
  681.                     }
  682.                 }
  683.                 if ($filter) {
  684.                     // проверка на включенный фильтр
  685.                     // фильтр может быть отключен, если это фабрика. Фабрику выводим в любом случае
  686.                     if ($filter->isEnable() or $filter->isBrand()) {
  687.                         // проверяем, что бы сортировка была только одна
  688.                         if ($filter->isSort() && !$isSort) {
  689.                             $isSort true;
  690.                         }
  691.                         unset($aKeys[$i]);
  692.                         $aKeysNew[$filter->getId()] = $filter;
  693.                     }
  694.                 }
  695.             }
  696.             // если в массиве еще остались значения , то дополнительно проверяем на наличие редиректов
  697.             if (count($aKeys) > 0) {
  698.                 /** @var $repoLastUrl LastUrlRepository */
  699.                 $repoLastUrl App::getRepository('WebBundle:LastUrlEntity');
  700.                 foreach ($aKeys as $i => $key) {
  701.                     if ($keyTmp $repoLastUrl->getActualSlugFiflter($key$locale)) {
  702.                         if ($filter $this->filterRepo->getByKeyUrl($keyTmp$locale)) {
  703.                             unset($aKeys[$i]);
  704.                             $aKeysNew[$filter->getId()] = $filter;
  705.                         }
  706.                     }
  707.                 }
  708.             }
  709.         }
  710.         // если в массиве еще остались значения , то пишем значения в массив в бед кеями
  711.         // что с ним потом делать пока не знаю, но что то делать будет надо
  712.         if (count($aKeys) > 0) {
  713.             foreach ($aKeys as $key) {
  714.                 $this->aBadKeys[] = $key;
  715.             }
  716.         }
  717.         return $aKeysNew;
  718.     }
  719.     /**
  720.      * @return array|FilterResponseDTO[]
  721.      */
  722.     public function getCurFilters()
  723.     {
  724.         return $this->curFilters;
  725.     }
  726.     /**
  727.      * @return array
  728.      */
  729.     public function getDimensions()
  730.     {
  731.         return $this->aDimensions;
  732.     }
  733.     /**
  734.      * @param mixed $aDimensions
  735.      */
  736.     public function setDimensions($aDimensions)
  737.     {
  738.         $this->aDimensions $aDimensions;
  739.     }
  740.     /**
  741.      * @return array
  742.      */
  743.     public function getBMs()
  744.     {
  745.         return $this->aBMs;
  746.     }
  747.     /**
  748.      * @param mixed $aBMs
  749.      */
  750.     public function setBMs($aBMs)
  751.     {
  752.         $this->aBMs $aBMs;
  753.     }
  754.     /**
  755.      * Формируем многомерный массив из строки запроса с фильтрами
  756.      * @param $key
  757.      * @return array
  758.      */
  759.     private function urlToArray($key)
  760.     {
  761.         $key StrHelper::toLower($key);
  762.         $key trim(urldecode($key));
  763.         $key $key explode($this->separator$key) : [];
  764.         return array_diff($key, [''' 'nullfalse]);
  765.     }
  766.     /**
  767.      * Получаем объект фабрики, если таковая есть в фильтрах
  768.      * @return null|BrandResponseDTO
  769.      */
  770.     public function getCurBrand()
  771.     {
  772.         foreach ($this->getCurFilters() as $curFilter) {
  773.             if ($brand $curFilter->getBrand()) {
  774.                 return $brand;
  775.             }
  776.         }
  777.         return null;
  778.     }
  779.     /**
  780.      * Определяем сколько фильтров примененно, без учета сортировки
  781.      * @return bool
  782.      */
  783.     public function isOneFilter()
  784.     {
  785.         if ($this->isOneFilter === null) {
  786.             $aCurFilters $this->getCurFilters();
  787.             $countFilters count($aCurFilters);
  788.             if ($countFilters 1) {
  789.                 foreach ($aCurFilters as $filter) {
  790.                     if ($filter->isSort()) {
  791.                         $countFilters--;
  792.                     } else {
  793.                         if (!$filter->isEnable()) {
  794.                             $countFilters--;
  795.                         }
  796.                     }
  797.                 }
  798.             }
  799.             $this->isOneFilter = ($countFilters == 1);
  800.         }
  801.         return $this->isOneFilter;
  802.     }
  803.     /**
  804.      * Проверка на тестовую фабрику
  805.      * @return bool
  806.      */
  807.     public function isTestingBrand()
  808.     {
  809.         foreach ($this->curFilters as $filter) {
  810.             if ($filter->getAltName() == 'testing_factory') {
  811.                 return true;
  812.             }
  813.         }
  814.         return false;
  815.     }
  816.     /**
  817.      * Проверка на принадлежность к топу
  818.      * @return bool
  819.      */
  820.     public function isTopFilter()
  821.     {
  822.         foreach ($this->curFilters as $filter) {
  823.             if ($filter->isTop() && !$filter->isAlsoCollViewed()) {
  824.                 return true;
  825.             }
  826.         }
  827.         return false;
  828.     }
  829.     /**
  830.      * Проверка на сочетание двых выбранных фильтров дизайнерский стиль + любой дизайнер
  831.      * @param array $filters
  832.      * @return bool
  833.      */
  834.     public function isStyleDesignerAndDesigner(array $filters = [])
  835.     {
  836.         $filters $filters ?: $this->curFilters;
  837.         if (count($filters) == 2) {
  838.             $isDesigner $this->isExistDesigner($filters);
  839.             if ($isDesigner) {
  840.                 foreach ($filters as $filter) {
  841.                     if ($filter->isDesignerStyle()) {
  842.                         return true;
  843.                     }
  844.                 }
  845.             }
  846.         }
  847.         return false;
  848.     }
  849.     public function isExistDesigner(array $filters = []): bool
  850.     {
  851.         $filters $filters ?: $this->curFilters;
  852.         foreach ($filters as $filter) {
  853.             if ($filter->isDesignerUser()) {
  854.                 return true;
  855.             }
  856.         }
  857.         return false;
  858.     }
  859.     /**
  860.      * Получаем вильтр сортировки, если таковой был в запросе
  861.      * @return null|FilterResponseDTO
  862.      */
  863.     public function getSortFilter()
  864.     {
  865.         foreach ($this->getCurFilters() as $curFilter) {
  866.             if ($curFilter->isSort()) {
  867.                 return $curFilter;
  868.             }
  869.         }
  870.         return null;
  871.     }
  872.     /**
  873.      * @param FilterGroupsCatalogDTO $filterGroups
  874.      * @param bool $isShot
  875.      * @param bool $isLinkToFilter
  876.      * @param bool $isLinkEdit
  877.      * @return string
  878.      */
  879.     public function buldFiltersToStr(
  880.         FilterGroupsCatalogDTO $filterGroups,
  881.         bool $isShot false,
  882.         bool $isLinkToFilter false,
  883.         bool $isLinkEdit true
  884.     ) {
  885.         if ($this->alsoCollViewedId) {
  886.             return $filterGroups->getFirstGroup()->getFirstFilter()->getTitle();
  887.         }
  888.         $and $this->translate('joinder_and'$this->locale);
  889.         $ceramicTilesName $this->translate('catalog_ceramic_tiles'$this->locale);
  890.         $sTtitle2 "$ceramicTilesName ";
  891.         $isShowLinkStyleDesigner $isLinkToFilter;
  892.         if ($this->isOneFilter()) {
  893.             $sTtitle2 '';
  894.             $isLinkToFilter false;
  895.             $isShowLinkStyleDesigner $this->isExistDesigner();
  896.         }
  897.         if ($this->isOneFilter() && $this->getCurBrand()) {
  898.             $isLinkEdit false;
  899.         }
  900.         // type (вид изделия)
  901.         if ($typeGroup $filterGroups->getProductType()) {
  902.             $sTtitle2 $this->modifyFirstFilter($typeGroup);
  903.         } else {
  904.             // material
  905.             if ($materialGroup $filterGroups->getMaterial()) {
  906.                 $sTtitle2 $this->modifyFirstFilter($materialGroup);
  907.             }
  908.         }
  909.         if ($isShot) {
  910.             $sTtitle2 '';
  911.         }
  912.         $groups $filterGroups->getGroups();
  913.         $maxCntFilters 0;
  914.         foreach ($groups as $group) {
  915.             $cnt count($group->getListFilters());
  916.             if ($cnt $maxCntFilters) {
  917.                 $maxCntFilters $cnt;
  918.             }
  919.         }
  920.         if ($maxCntFilters 2) {
  921.             $separatorGroup ';';
  922.             $separatorFilter ',';
  923.         } else {
  924.             $separatorGroup ',';
  925.             $separatorFilter $and;
  926.         }
  927.         $cntGroup count($groups);
  928.         $isDotBefore false;
  929.         foreach ($groups as $i => $group) {
  930.             $groupName $group->getGroupName();
  931.             $altName $group->getGroupAltName();
  932.             if ($i == || $isDotBefore) {
  933.                 $groupName StrHelper::ucFirstOnly($groupName);
  934.             } else {
  935.                 $groupName StrHelper::toLower($groupName);
  936.             }
  937.             if ($altName == 'dimension' || $altName == 'rewards' || $altName == 'samples') {
  938.                 $groupName '';
  939.             } elseif ($altName == 'bm') {
  940.                 $groupName StrHelper::toUpper($groupName) . ': ';
  941.             } elseif ($altName == 'resistance_abrasion') {
  942.                 $groupName '';//StrHelper::toUpper($groupName);
  943.             }
  944.             if ($this->isOneFilter()) {
  945.                 $groupName '';
  946.             }
  947.             $groupName $groupName "{$groupName} " "";
  948.             $name_ '';
  949.             $listFilters $group->getListFilters();
  950.             $nameCnt count($listFilters);
  951.             foreach ($listFilters as $ii => $filter) {
  952.                 $pref '';
  953.                 if ($ii 0) {
  954.                     $pref $separatorFilter "{$separatorFilter} " ' ';
  955.                     // для последнего ставим
  956.                     if ($nameCnt == $ii) {
  957.                         $pref {$and} ";
  958.                     }
  959.                     // для размеров убираем разделители между двумя одинаковами типами
  960.                     if ($altName == 'dimension') {
  961.                         if (!empty($listFilters[$ii 1])) {
  962.                             $keyPrew $listFilters[$ii 1]->getKey();
  963.                             if ($filter->getKey() == $keyPrew '2') {
  964.                                 $pref ' ';
  965.                             }
  966.                         }
  967.                     }
  968.                 }
  969.                 $elFilterName $filter->getTitle() ?? '';
  970.                 if (!$groupName && $altName != 'resistance_abrasion') {
  971.                     if (($i == && $ii == 0) || $isDotBefore) {
  972.                         $elFilterName StrHelper::ucFirstOnly($elFilterName);
  973.                     } else {
  974.                         $elFilterName StrHelper::toLower($elFilterName);
  975.                     }
  976.                 }
  977.                 $isDotBefore preg_match('/\.\s?<?/'strip_tags($elFilterName));
  978.                 if ($isLinkToFilter) {
  979.                     $elFilterName $this->buildElemetFilter($elFilterName$filter->getSlug());
  980.                 } elseif ($isShowLinkStyleDesigner) {
  981.                     $key $this->filterRepo->getKeyDesignerStyle();
  982.                     $link $this->generateUrl('app_catalog', ['key' => $key]);
  983.                     $pref $this->translate('link_on_designer'null, ['%href%' => $link]) . ' ';
  984.                     $elFilterName $filter->getNameMany();
  985.                 }
  986.                 if ($isLinkEdit) {
  987.                     $elFilterName $this->addElemetFilterLinkEdit($filter->getId(), $filter->getKey(), $elFilterName);
  988.                 }
  989.                 if ($this->isMargeFilters($filter->getId())) {
  990.                     $sub $this->filterRepo->getArrListSubForMenu($filter->getId(), $this->locale);
  991.                     $all_sub = [];
  992.                     foreach ($sub as $subItem) {
  993.                         if (!empty($subItem['pageNameMenu']) && !empty($subItem['url'])) {
  994.                             $all_sub[] = $this->buildElemetFilter($subItem['pageNameMenu'], $subItem['url']);
  995.                         }
  996.                     }
  997.                     if ($isLinkToFilter) {
  998.                         $elFilterName .= ' (' implode(', '$all_sub) . ')';
  999.                     } else {
  1000.                         $elFilterName .= ': ' implode(', '$all_sub);
  1001.                     }
  1002.                 }
  1003.                 $name_ .= "{$pref}{$elFilterName}";
  1004.             }
  1005.             // фикс случайных нескольких пробелов на всякий случай
  1006.             $name_ preg_replace(['# {2,}#umi'], ' '$name_);
  1007.             if ($i == $cntGroup 1) {
  1008.                 $sepGroup '';
  1009.             } else {
  1010.                 $sepGroup "{$separatorGroup} ";
  1011.             }
  1012.             // если нашли вконце точку, то разделитель убираем
  1013.             if ($isDotBefore) {
  1014.                 $sepGroup '';
  1015.             }
  1016.             if ($isLinkToFilter) {
  1017.                 $sTtitle2 .= "<span>{$groupName}{$name_}{$sepGroup}</span>";
  1018.             } else {
  1019.                 $sTtitle2 .= "{$groupName}{$name_}{$sepGroup}";
  1020.             }
  1021.         }
  1022.         return $sTtitle2;
  1023.     }
  1024.     /**
  1025.      * @param FilterGroupsCatalogDTO $filterGroups
  1026.      * @return string
  1027.      */
  1028.     public function buldFiltersToStrMetaTitle(
  1029.         FilterGroupsCatalogDTO $filterGroups
  1030.     ) {
  1031.         if ($this->alsoCollViewedId) {
  1032.             return $filterGroups->getFirstGroup()->getFirstFilter()->getTitle();
  1033.         }
  1034.         $and $this->translate('joinder_and'$this->locale);
  1035.         $ceramicTilesName $this->translate('catalog_ceramic_tiles'$this->locale);
  1036.         $sTtitle2 "";
  1037.         // type (вид изделия)
  1038.         if ($typeGroup $filterGroups->getProductType()) {
  1039.             $sTtitle2 $this->modifyFirstFilter($typeGroup);
  1040.         } else {
  1041.             // material
  1042.             if ($materialGroup $filterGroups->getMaterial()) {
  1043.                 $sTtitle2 $this->modifyFirstFilter($materialGroup);
  1044.             }
  1045.         }
  1046.         $groups $filterGroups->getGroups();
  1047.         $maxCntFilters 0;
  1048.         foreach ($groups as $group) {
  1049.             $cnt count($group->getListFilters());
  1050.             if ($cnt $maxCntFilters) {
  1051.                 $maxCntFilters $cnt;
  1052.             }
  1053.         }
  1054.         if ($maxCntFilters 2) {
  1055.             $separatorGroup ';';
  1056.             $separatorFilter ',';
  1057.         } else {
  1058.             $separatorGroup ',';
  1059.             $separatorFilter $and;
  1060.         }
  1061.         $cntGroup count($groups);
  1062.         $isDotBefore false;
  1063.         $filters $this->getCurFilters();
  1064.         $firstFilterGroups $filters[0];
  1065.         foreach ($groups as $i => $group) {
  1066.             $groupName $group->getGroupName();
  1067.             $altName $group->getGroupAltName();
  1068.             if ($i == || $isDotBefore) {
  1069.                 $groupName StrHelper::ucFirstOnly($groupName);
  1070.             } else {
  1071.                 $groupName StrHelper::toLower($groupName);
  1072.             }
  1073.             if ($altName == 'dimension' || $altName == 'rewards' || $altName == 'samples') {
  1074.                 $groupName '';
  1075.             } elseif ($altName == 'bm') {
  1076.                 $groupName StrHelper::toUpper($groupName) . ': ';
  1077.             } elseif ($altName == 'resistance_abrasion') {
  1078.                 $groupName StrHelper::toUpper($groupName);
  1079.             }
  1080.             $groupName = !empty($groupName) && $i "{$groupName} " "";
  1081.             if ($this->isOneFilter()) {
  1082.                 $groupName '';
  1083.             }
  1084.             $name_ '';
  1085.             $listFilters $group->getListFilters();
  1086.             $nameCnt count($listFilters);
  1087.             $prefGroup false;
  1088.             foreach ($listFilters as $ii => $filter) {
  1089.                 $pref '';
  1090.                 if ($ii 0) {
  1091.                     $pref $separatorFilter "{$separatorFilter} " ' ';
  1092.                     // для последнего ставим
  1093.                     if ($nameCnt == $ii) {
  1094.                         $pref {$and} ";
  1095.                     }
  1096.                     // для размеров убираем разделители между двумя одинаковами типами
  1097.                     if ($altName == 'dimension') {
  1098.                         if (!empty($listFilters[$ii 1])) {
  1099.                             $keyPrew $listFilters[$ii 1]->getKey();
  1100.                             if ($filter->getKey() == $keyPrew '2') {
  1101.                                 $pref ' ';
  1102.                             }
  1103.                         }
  1104.                     }
  1105.                 }
  1106.                 if ($i == 0) {
  1107.                     $elFilterName StrHelper::toLower($filter->getNameSingle() ?? '');
  1108.                 } else {
  1109.                     $elFilterName $filter->getTitle() ?? '';
  1110.                 }
  1111.                 if (!$groupName) {
  1112.                     if (($i == && $ii == 0) || $isDotBefore) {
  1113.                         $elFilterName StrHelper::ucFirstOnly($elFilterName);
  1114.                     } else {
  1115.                         $elFilterName StrHelper::toLower($elFilterName);
  1116.                     }
  1117.                 }
  1118.                 $isDotBefore preg_match('/\.\s?<?/'strip_tags($elFilterName));
  1119.                 $elFilterName $this->buildElemetFilter($elFilterName$filter->getSlug());
  1120.                 $name_ .= "{$pref}{$elFilterName}";
  1121.             }
  1122.             // фикс случайных нескольких пробелов на всякий случай
  1123.             $name_ preg_replace(['# {2,}#umi'], ' '$name_);
  1124.             if ($i == $cntGroup 1) {
  1125.                 $sepGroup '';
  1126.             } else {
  1127.                 $sepGroup "{$separatorGroup} ";
  1128.             }
  1129.             // если нашли вконце точку, то разделитель убираем
  1130.             if ($isDotBefore) {
  1131.                 $sepGroup '';
  1132.             }
  1133.             if ($prefGroup) {
  1134.                 $sTtitle2_pref "{$name_}. ";
  1135.             } else {
  1136.                 $sTtitle2 .= "{$groupName}{$name_}{$sepGroup}";
  1137.             }
  1138.         }
  1139.         $sTtitle2 = (!empty($sTtitle2_pref) ? $sTtitle2_pref '') . $sTtitle2;
  1140.         return $sTtitle2;
  1141.     }
  1142.     /**
  1143.      * @param string $name
  1144.      * @param string $slug
  1145.      * @return string
  1146.      */
  1147.     private function buildElemetFilter(string $namestring $slug): string
  1148.     {
  1149.         $link $this->generateUrl('app_catalog', ['key' => $slug]);
  1150.         return "<a class=\"el-filter\" href=\"{$link}\">{$name}</a>";
  1151.     }
  1152.     /**
  1153.      * @param int $id
  1154.      * @param string $key
  1155.      * @param string $nameFilterStr
  1156.      * @return string
  1157.      */
  1158.     private function addElemetFilterLinkEdit(int $idstring $keystring $nameFilterStr): string
  1159.     {
  1160.         $linkEdit $key == 'factory' Adm::linkEdit('adm.brand.edit'$id) : Adm::linkEdit('adm.filter.edit'$id);
  1161.         $linkEdit $linkEdit "<sup> <a class=\"link-edit\" href=\"$linkEdit\" target=\"_blank\">edit</a></sup>" null;
  1162.         return $linkEdit "{$nameFilterStr}{$linkEdit}$nameFilterStr;
  1163.     }
  1164.     /**
  1165.      * @return FilterGroupsCatalogDTO
  1166.      * @throws Exception
  1167.      */
  1168.     public function buildFilterGroupsDTO(): FilterGroupsCatalogDTO
  1169.     {
  1170.         $aCurFilters $this->getSortedFiltersLikeInTheLiteMenu();
  1171.         $isOneFilter $this->isOneFilter();
  1172.         //$isDesignerUser = $this->filterService()->isDesignerUser();
  1173.         $filterGroups = new FilterGroupsCatalogDTO();
  1174.         // если фильтр размеров есть, то создаем массив с количеством значений по группам, для будущего формирования
  1175.         $aDimensionsCnt = [];
  1176.         if ($aDimensions $this->getDimensions()) {
  1177.             foreach ($aDimensions as $key => $val) {
  1178.                 $key str_replace('2'''$key);
  1179.                 if (!empty($aDimensionsCnt[$key])) {
  1180.                     $aDimensionsCnt[$key] += 1;
  1181.                 } else {
  1182.                     $aDimensionsCnt[$key] = 1;
  1183.                 }
  1184.             }
  1185.         }
  1186.         foreach ($aCurFilters as $filter) {
  1187.             $groupAltName $filter->getGroupAltName();
  1188.             if (!$filterGroup $filterGroups->getGroup($groupAltName)) {
  1189.                 $filterGroup = new FilterGroupCatalogDTO($filter->getGroupId(), $filter->getGroupName(), $groupAltName);
  1190.                 $filterGroups->addGroup($filterGroup);
  1191.             }
  1192.             $nameSingle $filter->getNameSingle();
  1193.             $nameMany $filter->getNameMany();
  1194.             $dopValue null;
  1195.             $slug $filter->getSlug();
  1196.             if ($filter->isDimension()) {
  1197.                 $dopValue $this->aDimensions[$filter->getSphinxName()];
  1198.                 $slug "{$slug}-{$dopValue}";
  1199.             } elseif ($groupAltName == 'bm') {
  1200.                 $dopValue $this->aBMs['bm'];
  1201.                 $slug "{$slug}-{$dopValue}";
  1202.             } elseif ($filter->isAlsoCollViewed()) {
  1203.                 $dopValue $this->alsoCollViewedId;
  1204.             }
  1205.             $filterGroup->addListFilters(
  1206.                 new FilterCatalogDTO(
  1207.                     $filter->getId(),
  1208.                     $filter->getSphinxName(),
  1209.                     $filter->getSphinxId(),
  1210.                     $filter->getCode(),
  1211.                     $filter->getAltName(),
  1212.                     $slug,
  1213.                     $nameSingle,
  1214.                     $nameMany,
  1215.                     $dopValue,
  1216.                 )
  1217.             );
  1218.         }
  1219.         foreach ($filterGroups->getGroups() as $groupDto) {
  1220.             $groupAltName $groupDto->getGroupAltName();
  1221.             foreach ($groupDto->getListFilters() as $filterDto) {
  1222.                 $title $isOneFilter $filterDto->getNameSingle() : $filterDto->getNameMany();
  1223.                 $filterDto->setTitle($title);
  1224.                 switch ($groupAltName) {
  1225.                     case 'antislip_coff':
  1226.                         $groupName $this->translate('antislip_full_name'$this->locale, ['%d%' => '']);
  1227.                         $groupDto->setGroupName($groupName);
  1228.                         break;
  1229.                     case 'resistance_abrasion':
  1230.                         // $title = trim(str_replace('PEI', '', $title));
  1231.                         $filterDto->setTitle($title);
  1232.                         break;
  1233.                     case 'price':
  1234.                         $title LocaleHelper::getNamePriceFilter($title$this->locale);
  1235.                         $title LocaleHelper::getNamePriceFilterWithCurrency($title);
  1236.                         $filterDto->setTitle($title);
  1237.                         break;
  1238.                     case 'bm':
  1239.                         $repoUser App::getRepository('WebBundle:User');
  1240.                         $title $repoUser->getUserEasyNameById($filterDto->getDopValue());
  1241.                         $filterDto->setTitle($title);
  1242.                         break;
  1243.                     case 'top':
  1244.                         if ($filterDto->getKey() == 'getAlsoCollViewed') {
  1245.                             if ($collAlsoId $filterDto->getDopValue()) {
  1246.                                 /** @var Collection $coll */
  1247.                                 $coll $this->collRepo->getCollForAlsoById($collAlsoId);
  1248.                                 if (null === $coll) {
  1249.                                     throw new NotFoundHttpException();
  1250.                                 }
  1251.                                 $factory $coll->getFactory();
  1252.                                 $collName $coll->getName();
  1253.                                 $brandName $factory->getName();
  1254.                                 if ($coll->getStatus() == || $factory->getStatus() == 1) {
  1255.                                     $collUrl $this->generateUrl(
  1256.                                         'app_collection',
  1257.                                         ['factoryUrl' => $factory->getUrl(), 'collectionUrl' => $coll->getUrl()]
  1258.                                     );
  1259.                                     $collName "<a href=\"$collUrl\" title=\"{$coll->getName()}\">{$coll->getName()}</a>";
  1260.                                     $brandUrl $this->generateUrl('app_catalog', ['key' => $factory->getUrl()]);
  1261.                                     $brandName "<a href=\"$brandUrl\" title=\"$brandName\">$brandName</a>";
  1262.                                 }
  1263.                             } else {
  1264.                                 $collName $this->translate('collection');
  1265.                                 $brandName $this->translate('brand');
  1266.                             }
  1267.                             $title str_replace('%collection%'$collName$title);
  1268.                             if (stripos($title'%brand%') !== false) {
  1269.                                 $title str_replace('%brand%'$brandName$title);
  1270.                             }
  1271.                             $filterDto->setTitle($title);
  1272.                         }
  1273.                         break;
  1274.                     case 'dimension':
  1275.                         $sizeVal $aDimensions[$filterDto->getKey()];
  1276.                         $sizeEd $this->translate("left_menu_{$filterDto->getCode()}"$this->locale);
  1277.                         $dimKey str_replace('2'''$filterDto->getKey());
  1278.                         // если группа размеров содержит более одного элемента, формируем дополнительный массив
  1279.                         if ($aDimensionsCnt[$dimKey] > 1) {
  1280.                             $aSizeType explode(' '$title);
  1281.                             $firstTitle array_shift($aSizeType);
  1282.                             $pattern $this->translate('settings_size_from_to'$this->locale);
  1283.                             if ($pattern and $pattern != 'settings_size_from_to') {
  1284.                                 if (preg_match('/(.*%size%)\s(.*%size2%)/'$pattern$out)) {
  1285.                                     if (preg_match('/.*2$/'$filterDto->getKey())) {
  1286.                                         $title str_replace('%size2%'$sizeVal$out[2]);
  1287.                                         $title "{$title} {$sizeEd}";
  1288.                                     } else {
  1289.                                         $title str_replace('%size%'$sizeVal"{$out[1]} ");
  1290.                                         $title "{$firstTitle} {$title}";
  1291.                                     }
  1292.                                 }
  1293.                             }
  1294.                         } else {
  1295.                             $title "{$title} {$sizeVal} {$sizeEd}";
  1296.                         }
  1297.                         $filterDto->setTitle($title);
  1298.                         break;
  1299.                 }
  1300.             }
  1301.         }
  1302.         return $filterGroups;
  1303.     }
  1304.     /**
  1305.      * разбиваем строку кея на полстроки для дополнительного поиска. например для размеров или БМа
  1306.      * @param string $key
  1307.      * @return array
  1308.      */
  1309.     private function buldExplodeKeys(string $key)
  1310.     {
  1311.         $res = [];
  1312.         $aKey explode('-'$key);
  1313.         if (count($aKey) > 2) {
  1314.             // создаем копию массива и удаляем последний элемент
  1315.             $aKeyTmp $aKey;
  1316.             array_pop($aKeyTmp);
  1317.             $res[] = implode('-'$aKeyTmp);
  1318.             // создаем копию массива и удаляем последний элемент
  1319.             $aKeyTmp $aKey;
  1320.             array_shift($aKeyTmp);
  1321.             $res[] = implode('-'$aKeyTmp);
  1322.         }
  1323.         foreach ($aKey as $k) {
  1324.             if (!is_numeric($k) && mb_strlen($k'utf-8') > 2) {
  1325.                 $res[] = $k;
  1326.             }
  1327.         }
  1328.         // в конец добавим полный кей, для LIKE поиска
  1329.         $res[] = $key;
  1330.         return array_unique($res);
  1331.     }
  1332.     /**
  1333.      * Правим фильтр, который должен быть первым и определяющим для страницы
  1334.      * @param FilterGroupCatalogDTO $filterGroup
  1335.      * @return string
  1336.      */
  1337.     private function modifyFirstFilter(FilterGroupCatalogDTO $filterGroup): string
  1338.     {
  1339.         $tilesName $this->translate('footer_tile'$this->locale);
  1340.         if (count($filterGroup->getListFilters()) > 1) {
  1341.             return "{$tilesName}. ";
  1342.         }
  1343.         // ставим отдельным предложением в начало
  1344.         $afterDot $this->isOneFilter() ? '' '. ';
  1345.         $firstFilter $filterGroup->getFirstFilter();
  1346.         $firstFilter->setTitle("{$firstFilter->getNameSingle()}{$afterDot}");
  1347.         $filterGroup->setGroupName('');
  1348.         return '';
  1349.     }
  1350.     private function getSizeInCalc(array $input): array
  1351.     {
  1352.         $items array_keys($input);
  1353.         sort($items);
  1354.         $items array_map(function ($num) {
  1355.             $num = (int)$num;
  1356.             $num $num 100;
  1357.             $n round($num2PHP_ROUND_HALF_DOWN);
  1358.             return ($n == 0.0) ? null $n;
  1359.         }, $items);
  1360.         // Удаляем null'ы
  1361.         $items array_filter($items, function ($val) {
  1362.             return $val !== null;
  1363.         });
  1364.         return array_unique($items);
  1365.     }
  1366.     /**
  1367.      * Перенести из контроллера в сервис поиска, а лучше в сервис фильтров
  1368.      *
  1369.      * @return array|string
  1370.      * @throws Exception
  1371.      */
  1372.     public function getFiltersList()
  1373.     {
  1374.         $lc App::getCurLocale();
  1375.         $cc App::getCurCountry();
  1376.         $lcFull $lc == $cc $lc "{$lc}_$cc";
  1377.         $cur LocaleHelper::getCurrency();
  1378.         $msr LocaleHelper::getUserMeasure();
  1379.         $memcache App::getMemcache();
  1380.         $redisCachePool App::getContainer()->get(RedisCachePool::class)->getPool();
  1381.         //        $memcacheKey = "collection_filter_factory_search_page_list_$lcFull.$cur.$msr";
  1382.         //        $filters = $memcache->get($memcacheKey);
  1383.         //
  1384.         //        if ($filters) {
  1385.         //                  return $filters; //todo тест без кеша
  1386.         //        }
  1387.         $filters = [];
  1388.         $filtersTmp $this->filterRepo->getArrListForFilterMenuNew($lc);
  1389.         if ($lc == 'zh') {
  1390.             $filtersTmpEn $this->filterRepo->getArrListForFilterMenuNew('en');
  1391.             // Рекурсивно заполняем пустые поля китайского массива значениями из английского
  1392.             $filtersTmp $this->filterRepo->fillEmptyFields($filtersTmp$filtersTmpEn);
  1393.         }
  1394.         //приписываем новые значения Просьба:Подвисает отбор по отзывам на рабочем сайте
  1395.         $memKeyCalc 'all_calculate_' $cc '_' $msr;
  1396.         $allCalculateItem $redisCachePool->getItem($memKeyCalc);
  1397.         if ($allCalculateItem->isHit()) {
  1398.             $allCalculate $allCalculateItem->get();
  1399.             $sizesX $this->getSizeInCalc($allCalculate['size_x']);
  1400.             $sizesY $this->getSizeInCalc($allCalculate['size_y']);
  1401.             $thicks $this->getSizeInCalc($allCalculate['tolsch']);
  1402.             $filtersTmp $this->setNewCount($filtersTmp$allCalculateItem->get());
  1403.         } else {
  1404.             $allCalculate false;
  1405.             $thicks $this->articleRepo->getSizeValues('thick');
  1406.             $sizesY $this->articleRepo->getSizeValues('sizeY');
  1407.             $sizesX $this->articleRepo->getSizeValues('sizeX');
  1408.         }
  1409.         // проверяем наличие вложенных фильтров
  1410.         $sub = [];
  1411.         $pids array_filter($filtersTmp, function ($r) {
  1412.             return $r['pid'] != null;
  1413.         });
  1414.         if ($pids) {
  1415.             foreach ($pids as $id => $r) {
  1416.                 unset($filtersTmp[$id]);
  1417.                 $sub[$r['pid']][$id] = $r;
  1418.             }
  1419.         }
  1420.         foreach ($filtersTmp as $filter) {
  1421.             $fid $filter['id'];
  1422.             $groupAltName $filter['group']['altName'];
  1423.             // вставляем вложенные фильтры, если есть такие
  1424.             if (!empty($sub[$fid])) {
  1425.                 $filter['sub'] = $sub[$fid];
  1426.             }
  1427.             $filters[$groupAltName][$fid] = $filter;
  1428.             // формируем фильтры для БМов
  1429.             if ($groupAltName == 'bm') {
  1430.                 $filters['bm'] = [];
  1431.                 $aUsers $this->collRepo->getListActiveBM();
  1432.                 foreach ($aUsers as $id => $name) {
  1433.                     $filters['bm'][$id] = [
  1434.                         'fid' => $fid,
  1435.                         'id' => $id,
  1436.                         'name' => $name,
  1437.                         'altName' => $id,
  1438.                         'selected' => [],
  1439.                         'group' => $filter['group'],
  1440.                         'count' => 0,
  1441.                     ];
  1442.                 }
  1443.             }
  1444.             // формируем фильтры для размеров
  1445.             if ($groupAltName == 'dimension') {
  1446.                 // проверяем на Дюймы и если что конвертируем
  1447.                 if (LocaleHelper::measureGb()) {
  1448.                     $measure '″';
  1449.                     if (StrHelper::isInStr($filter['altName'], 'tolsch')) {
  1450.                         $koff ConversionHelper::convertInch(
  1451.                             0.1,
  1452.                             ConversionHelper::MM,
  1453.                             5
  1454.                         ); //mm так там выходит 0.00394
  1455.                     } else {
  1456.                         $koff ConversionHelper::convertInch(1.0ConversionHelper::CM); //cm
  1457.                     }
  1458.                 } else {
  1459.                     if (StrHelper::isInStr($filter['altName'], 'tolsch')) {
  1460.                         $measure 'left_menu_mm';
  1461.                     } else {
  1462.                         $measure 'left_menu_cm';
  1463.                     }
  1464.                     $measure $this->translate($measure);
  1465.                     $koff 1;
  1466.                 }
  1467.                 if (!StrHelper::isInStr($filter['altName'], '2')) {
  1468.                     $filters[$groupAltName][$fid]['subGroup'] = [
  1469.                         'name' => $this->translate('dimensions_from'),
  1470.                         'altName' => 'from',
  1471.                         'suff' => '',
  1472.                         'measure' => '',
  1473.                     ];
  1474.                 } else {
  1475.                     $filters[$groupAltName][$fid]['subGroup'] = [
  1476.                         'name' => $this->translate('dimensions_to'),
  1477.                         'altName' => 'to',
  1478.                         'suff' => '2',
  1479.                         'measure' => $measure,
  1480.                     ];
  1481.                 }
  1482.                 /** @var $item Article */
  1483.                 if (StrHelper::isInStr($filter['altName'], 'tolsch')) {
  1484.                     $subGroupName $this->translate('left_menu_thickness');
  1485.                     $filters[$groupAltName][$fid]['name'] = $subGroupName;
  1486.                     $sizes = [];
  1487.                     foreach ($thicks as $s) {
  1488.                         $sizes[] = [
  1489.                             'name' => $s $koff,
  1490.                             'val' => $s,
  1491.                         ];
  1492.                     }
  1493.                     if (!StrHelper::isInStr($filter['altName'], '2')) {
  1494.                         array_pop($sizes);
  1495.                     }
  1496.                     $filters[$groupAltName][$fid]['sizes'] = $sizes;
  1497.                     $filters[$groupAltName][$subGroupName][$fid] = $filters[$groupAltName][$fid];
  1498.                 }
  1499.                 if (StrHelper::isInStr($filter['altName'], 'size_y')) {
  1500.                     $subGroupName $this->translate('left_menu_height');
  1501.                     $filters[$groupAltName][$fid]['name'] = $subGroupName;
  1502.                     foreach ($sizesY as $s) {
  1503.                         $filters[$groupAltName][$fid]['sizes'][] = [
  1504.                             'name' => $s $koff,
  1505.                             'val' => $s,
  1506.                         ];
  1507.                     }
  1508.                     $filters[$groupAltName][$subGroupName][$fid] = $filters[$groupAltName][$fid];
  1509.                 }
  1510.                 if (StrHelper::isInStr($filter['altName'], 'size_x')) {
  1511.                     $subGroupName $this->translate('left_menu_width');
  1512.                     $filters[$groupAltName][$fid]['name'] = $subGroupName;
  1513.                     foreach ($sizesX as $s) {
  1514.                         $filters[$groupAltName][$fid]['sizes'][] = [
  1515.                             'name' => $s $koff,
  1516.                             'val' => $s,
  1517.                         ];
  1518.                     }
  1519.                     $filters[$groupAltName][$subGroupName][$fid] = $filters[$groupAltName][$fid];
  1520.                 }
  1521.                 unset($filters[$groupAltName][$fid]);
  1522.             }
  1523.         }
  1524.         // переносим пачку противоскольжения в groupList фильтра Противоскользящая
  1525.         //todo не нужно если перенести противоскользыщие фильтры в подгруппу 10146 в группу 401
  1526.         // UPDATE `filters` SET `parent_id` = '10146', `group_id` = 401 WHERE group_id=422
  1527.         // логика обработки в sphinx
  1528. //        if (!empty($filters['surface']) && !empty($filters['surface']['10146'])) {
  1529. //            if (!empty($filters['antislip_coff'])) {
  1530. //                $filters['surface']['10146']['groupList'] = $filters['antislip_coff'];
  1531. //                unset($filters['antislip_coff']);
  1532. //            }
  1533. //        }
  1534.         $paramGetCollections = [
  1535.             'order' => 'c.name, c.publishDate DESC, c.id',
  1536.             'onlyCF' => true,
  1537.             'leftCollectionCount' => true,
  1538.             'locale' => App::getCurLocale(),
  1539.         ];
  1540.         $aColls $this->collRepo->getCollections($paramGetCollections);
  1541.         //получаем фабрики, которые скрытые в стране
  1542.         $issetCollectionFactory $allCalculate array_keys($allCalculate['factory']) : [];
  1543.         $issetCollection $allCalculate array_keys($allCalculate['c_id']) : [];
  1544.         //$all_coll=[];
  1545.         //        foreach ($aColls as $coll){
  1546.         //            $all_coll[]=$coll['id'];
  1547.         //        }
  1548.         //        $result = array_diff($all_coll, $issetCollection);
  1549.         //
  1550.         //        App::debugExit($paramGetCollections,$result,count($issetCollection),count($all_coll), $issetCollection,$all_coll);
  1551.         foreach ($aColls as $coll) {
  1552.             if (empty($coll['brandUrl']) || empty($coll['url'])) {
  1553.                 continue;
  1554.             }
  1555.             if (!empty($issetCollectionFactory) && !in_array($coll['id'], $issetCollection)) {
  1556.                 //App::debugExit($coll, $issetCollection);
  1557.                 continue;
  1558.             }
  1559.             $filters['collection'][$coll['id']] = [
  1560.                 'id' => $coll['id'],
  1561.                 'url' => $coll['url'],
  1562.                 'name' => $coll['nameFull'],
  1563.                 'altName' => $coll['alternateName'],
  1564.                 'selected' => [],
  1565.                 'brand' => [
  1566.                     'id' => $coll['brandId'],
  1567.                     'url' => $coll['brandUrl'],
  1568.                 ],
  1569.                 'dataLink' => $this->generateUrl(
  1570.                     'app_collection',
  1571.                     ['factoryUrl' => $coll['brandUrl'], 'collectionUrl' => $coll['url']]
  1572.                 ),
  1573.                 'group' => [
  1574.                     'name' => App::getTranslator()->trans('left_menu_collections'),
  1575.                     'altName' => 'collections',
  1576.                 ],
  1577.             ];
  1578.             if (!empty($filters['brand'][$coll['brandId']])) {
  1579.                 if (!in_array($coll['id'], $filters['brand'][$coll['brandId']]['collection'])) {
  1580.                     $filters['brand'][$coll['brandId']]['collection'][] = $coll['id'];
  1581.                 }
  1582.             }
  1583.         }
  1584.         //удаляем бренды которые скрыты
  1585.         if (!empty($issetCollectionFactory)) {
  1586.             //Удаляем фабрики если есть скрытые бренды
  1587.             $old count($filters['brand']);
  1588.             foreach ($filters['brand'] as $brKey => $brV) {
  1589.                 if (!in_array($brV['id'], $issetCollectionFactory)) {
  1590.                     unset($filters['brand'][$brKey]);
  1591.                 }
  1592.             }
  1593.         }
  1594.         // сортируем фабрики по имени
  1595.         if (!empty($filters['brand'])) {
  1596.             $brandSort array_column($filters['brand'], 'name');
  1597.             array_multisort($brandSortSORT_ASC$filters['brand']);
  1598.         }
  1599.         // сортируем выставки по ID
  1600.         if (!empty($filters['exhibition'])) {
  1601.             $exhSort array_column($filters['exhibition'], 'id');
  1602.             array_multisort($exhSortSORT_DESC$filters['exhibition']);
  1603.         }
  1604.         // кешируем на продакшене
  1605.         //        if (App::isGeneral()) {
  1606.         //            $memcache->add($memcacheKey, $filters, MEMCACHE_COMPRESSED, (int)(TimeConstant::HOUR * 12));
  1607.         //        }
  1608.         return $filters;
  1609.     }
  1610.     public function setNewCount(array $filters, array $allCalculate): array
  1611.     {
  1612.         //меняем логику перебираем фильтры и ищем новое значения иначе 0
  1613.         foreach ($filters as $filter) {
  1614.             if (!empty($allCalculate[$filter['oldCommand']][$filter['id']])) {
  1615.                 $filters[$filter['id']]['count'] = $allCalculate[$filter['oldCommand']][$filter['id']];
  1616.             }
  1617. //            else {
  1618. //               // unset($filters[$filter['id']]);//=0; todo не все
  1619. //            }
  1620.         }
  1621. //        foreach ($allCalculate as $group) {
  1622. //            foreach ($group as $id => $count) {
  1623. //                if (!empty($filters[$id])) {
  1624. //                    $filters[$id]['count'] = $count;
  1625. //                }
  1626. //            }
  1627. //        }
  1628.         return $filters;
  1629.     }
  1630. }