src/Repository/SaleRepository.php line 129

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by PhpStorm.
  4.  * User: adv
  5.  * Date: 06.12.15
  6.  * Time: 20:00
  7.  */
  8. namespace Slivki\Repository;
  9. use Doctrine\ORM\Query;
  10. use Doctrine\ORM\EntityRepository;
  11. use Slivki\Entity\Category;
  12. use Slivki\Entity\City;
  13. use Slivki\Entity\Comment;
  14. use Slivki\Entity\Media;
  15. use Slivki\Entity\OfferPayedCategory;
  16. use Slivki\Entity\Sale;
  17. use Slivki\Entity\Seo;
  18. use Slivki\Entity\TopSale;
  19. use Slivki\Entity\VisitCounter;
  20. use Slivki\Util\SoftCache;
  21. use Slivki\Entity\Visit;
  22. use Slivki\Util\TarantoolCache;
  23. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  24. class SaleRepository extends EntityRepository {
  25.     const CACHE_NAME "Sale-0";
  26.     const CACHE_NAME_SIDEBAR 'sidebar-2-';
  27.     const CACHE_NAME_PRODUCTS 'sale-products-01-';
  28.     const GALLERY_CACHE_KEY "sales-in-gallery-2-";
  29.     const ACTIVE_SALES_BY_CATEGORY "activeByCategory";
  30.     const CACHE_NAME_TEASERS_FLIER 'food-teaser-flier';
  31.     const CACHE_NAME_GEO_LOCATION_DATA 'sale-geolocation-data';
  32.     const VISIT_COUNT_CACHE_KEY 'visit-count';
  33.     const FLIER_VISIT_COUNT_CACHE_KEY 'flier-visit-count';
  34.     const VISITED_SALE_COUNT_CACHE_KEY 'visited-sales-count';
  35.     const VISITED_FLIER_COUNT_CACHE_KEY 'visited-flier-count';
  36.     const CITIES_CACHE_KEY 'flier-cities-';
  37.     const CACHE_KEY_BY_BRAND '-brand-';
  38.     const CACHE_KEY_BY_CITY '-city-';
  39.     const CACHE_KEY_BY_CATEGORY '-category-';
  40.     const PRODUCT_TAGS_CACHE_KEY '-tags-';
  41.     const SOS_CATEGORY_ID 53;
  42.     const NEW_CATEGORY_ID 59;
  43.     const POPULAR_SALE_CATEGORY_ID 1978;
  44.     const FAKE_CATEGORY_ID PHP_INT_MAX;
  45.     const RESIZED_IMAGE_PREFIX '_resized_';
  46.     const HASWM_IMAGE_PREFIX '_haswm_';
  47.     const WITHWM_IMAGE_PREFIX '_65de6_';
  48.     const HOT_SALES_DURABILITY_DAYS 7;
  49.     const API_HOST 'http://supercheck.by';
  50.     const API_ROOT_URL '/api/v2/';
  51.     public static $salePositionList = [];
  52.     /**
  53.      * @throws NotFoundHttpException
  54.      */
  55.     public function getActiveSalesByCategoryID($categoryID) {
  56.         $softCache = new SoftCache(self::CACHE_NAME);
  57.         $saleListByCategory $softCache->get(self::ACTIVE_SALES_BY_CATEGORY);
  58.         if (!$saleListByCategory) {
  59.             throw new NotFoundHttpException();
  60.         }
  61.         $saleList = [];
  62.         if (isset($saleListByCategory[$categoryID])) {
  63.             $saleList $softCache->getMulti($saleListByCategory[$categoryID]);
  64.         }
  65.         if (!$saleList) {
  66.             return [];
  67.         }
  68.         $result = [];
  69.         foreach ($saleList as $sale) {
  70.             if ($sale != null) {
  71.                 $result[] = $sale;
  72.             }
  73.         }
  74.         $saleList $result;
  75.         $category $this->getEntityManager()->getRepository(Category::class)->findCached($categoryID);
  76.         if (in_array($categoryID, [self::POPULAR_SALE_CATEGORY_IDCategory::FLIER_SALE_CATEGORY_ID]) ||
  77.             (isset($category['category']) && $category['category']->isChildOf(Category::FLIER_SALE_CATEGORY_ID))) {
  78.             $dql "select salePosition from Slivki:OfferPayedCategory salePosition index by salePosition.entityID where salePosition.categoryID = :categoryID order by salePosition.position";
  79.             self::$salePositionList $this->getEntityManager()->createQuery($dql)->setParameter('categoryID'$categoryID)->execute();
  80.             usort($saleList, ['\Slivki\Repository\SaleRepository''compareSalesByPosition']);
  81.         } else {
  82.             usort($saleList, ['\Slivki\Repository\SaleRepository''compareSalesBySince']);
  83.         }
  84.         return $saleList;
  85.     }
  86.     public function getAllSalesByCategoryID($categoryID) {
  87.         $dql "select sale, offerPayedCategory.position, category from Slivki:Sale sale
  88.             join sale.categories category
  89.             left join Slivki:OfferPayedCategory offerPayedCategory
  90.               with offerPayedCategory.entityID = sale.ID and offerPayedCategory.categoryID = :categoryID
  91.             where category.ID = :categoryID
  92.             order by offerPayedCategory.position, sale.active desc, sale.since desc, sale.ID desc";
  93.         $saleList $this->getEntityManager()->createQuery($dql)->setParameter("categoryID"$categoryID)->getResult();
  94.         return $saleList;
  95.     }
  96.     public function getSortedActiveSalesByCategoryID($categoryID) {
  97.         $dql "select sale, offerPayedCategory.position from Slivki:Sale sale
  98.             join sale.categories category
  99.             left join Slivki:OfferPayedCategory offerPayedCategory
  100.               with offerPayedCategory.entityID = sale.ID and offerPayedCategory.categoryID = :categoryID
  101.             where category.ID = :categoryID and sale.active = true and sale.since < CURRENT_TIMESTAMP() and sale.till > CURRENT_TIMESTAMP() 
  102.             order by offerPayedCategory.position, sale.since desc, sale.ID desc";
  103.         $saleList $this->getEntityManager()->createQuery($dql)->setParameter("categoryID"$categoryID)->getResult();
  104.         return $saleList;
  105.     }
  106.     public function getAllActiveSales(){
  107.         $dql "select sale from Slivki:Sale sale 
  108.                 where sale.active = true
  109.                 and sale.since < CURRENT_TIMESTAMP() 
  110.                 and sale.till > CURRENT_TIMESTAMP() 
  111.                 order by sale.active desc";
  112.         $sales $this->getEntityManager()->createQuery($dql)->getResult();
  113.         return $sales;
  114.     }
  115.     public function getActiveSaleByID($saleID) {
  116.         $softCache = new SoftCache(self::CACHE_NAME);
  117.         $sale $softCache->get($saleID);
  118.         if ($sale && $sale->getCategories()->count() == || true) {//TODO: delete after bugfix
  119.             $sale $this->reloadCacheForSale($saleID);
  120.         }
  121.         return $sale;
  122.     }
  123.     public function reloadCache() {
  124.         $dql "select sale, category, saleVersions, geoLocations from Slivki:Sale sale index by sale.ID 
  125.           left join sale.versions saleVersions
  126.           left join sale.geoLocations geoLocations 
  127.           inner join sale.categories category where category.active = true and sale.active = true 
  128.           and sale.since < CURRENT_TIMESTAMP() and sale.till > CURRENT_TIMESTAMP() order by sale.since desc";
  129.         $saleList $this->getEntityManager()->createQuery($dql)->getResult();
  130.         $saleListByCategory = [];
  131.         $mediaRepository $this->getEntityManager()->getRepository(Media::class);
  132.         $commentRepository $this->getEntityManager()->getRepository(Comment::class);
  133.         $cityList = [];
  134.         $salesByCity = [];
  135.         /** * @var \Slivki\Entity\Sale  $sale  */
  136.         foreach ($saleList as $saleID => $sale) {
  137.             $sale->getDirectors()->toArray();
  138.             $saleList[$saleID]->setIcon($mediaRepository->getSaleIconMedia($saleID));
  139.             $saleList[$saleID]->setHotFeedIconMedia($mediaRepository->getOfferHotFeedIconMedia($saleID));
  140.             $saleList[$saleID]->setAlternativeIcon($mediaRepository->getSaleAlternativeIconMedia($saleID));
  141.             $saleList[$saleID]->setFlierMedia($mediaRepository->getFlierImageMedia($saleID));
  142.             foreach ($sale->getDescriptions() as $saleDescription) {
  143.                 $saleDescription->setDescription(str_replace(self::HASWM_IMAGE_PREFIXself::WITHWM_IMAGE_PREFIX$saleDescription->getDescription()));
  144.                 $saleDescription->getEntityDescriptionSliderImages()->toArray();
  145.             }
  146.             $saleList[$saleID]->setRating($commentRepository->getEntityRating(Category::SALE_CATEGORY_ID$saleID));
  147.             foreach ($sale->getCategories() as $category) {
  148.                 $saleListByCategory[$category->getID()][] = $sale->getID();
  149.             }
  150.         }
  151.         $saleCategoryList = [];
  152.         $categoryList $this->getEntityManager()->getRepository(Category::class)->getActiveCategoriesNotCached(Category::SALE_CATEGORY_ID);
  153.         foreach ($categoryList as $category) {
  154.             if (!isset($saleListByCategory[$category->getID()])) {
  155.                 continue;
  156.             }
  157.             $category->setEntityCount(count($saleListByCategory[$category->getID()]));
  158.             $category->getParentCategories()->toArray();
  159.             $category->setHotFeedIconMedia($mediaRepository->getСategoryHotFeedIconMedia($category->getID()));
  160.             $saleCategoryList[$category->getID()] = ['category' => $category'entityList' => $saleListByCategory[$category->getID()]];
  161.         }
  162.         $softCache = new SoftCache(self::CACHE_NAME);
  163.         $softCache->setMulti($saleList0);
  164.         $softCache->set(self::ACTIVE_SALES_BY_CATEGORY$saleListByCategory0);
  165.         $softCache = new SoftCache(CategoryRepository::CACHE_NAME);
  166.         $categoryListCached $softCache->get(CategoryRepository::ALL_CATEGORIES_CACHE_KEY);
  167.         foreach ($saleCategoryList as $categoryID => $categoryData) {
  168.             $categoryListCached[$categoryID] = $categoryData;
  169.         }
  170.         $softCache->set(CategoryRepository::ALL_CATEGORIES_CACHE_KEY$categoryListCached0);
  171.         $softCache->setMulti($saleCategoryList0);
  172.         $this->getEntityManager()->clear();
  173.         $this->reloadFliersCache($saleList);
  174.     }
  175.     /** @deprecated  */
  176.     public function reloadCacheForSale($saleID) {
  177.         /** @var Sale $sale */
  178.         $sale $this->find($saleID);
  179.         if (!$sale) {
  180.             return;
  181.         }
  182.         if (!$sale->isActive() || !$sale->isVisible()) {
  183.             $this->removeSaleFromCache($sale->getID());
  184.             return;
  185.         }
  186.         $mediaRepository $this->getEntityManager()->getRepository(Media::class);
  187.         $sale->setIcon($mediaRepository->getSaleIconMedia($sale->getID()));
  188.         $sale->setHotFeedIconMedia($mediaRepository->getOfferHotFeedIconMedia($sale->getID()));
  189.         $sale->setAlternativeIcon($mediaRepository->getSaleAlternativeIconMedia($sale->getID()));
  190.         $sale->setFlierMedia($mediaRepository->getFlierImageMedia($saleID));
  191.         $sale->getDirectors()->toArray();
  192.         $sale->getGeoLocations()->toArray();
  193.         foreach ($sale->getDescriptions() as $saleDescription) {
  194.             $saleDescription->setDescription(str_replace(self::HASWM_IMAGE_PREFIXself::WITHWM_IMAGE_PREFIX$saleDescription->getDescription()));
  195.         }
  196.         $sale->setRating($this->getEntityManager()->getRepository(Comment::class)->getEntityRating(Category::SALE_CATEGORY_ID$saleID));
  197.         foreach ($sale->getVersions()->toArray() as $version) {
  198.             foreach ($version->getDescriptions() as $description) {
  199.                 $description->getEntityDescriptionSliderImages()->toArray();
  200.             }
  201.         }
  202.         $softCache = new SoftCache(self::CACHE_NAME);
  203.         $softCache->set($saleID$sale0);
  204.         $salesByCategory $softCache->get(self::ACTIVE_SALES_BY_CATEGORY);
  205.         foreach ($salesByCategory as $categoryID => $category) {
  206.             if (in_array($saleID$category)) {
  207.                 $categoryFound false;
  208.                 foreach ($sale->getCategories() as $saleCategory) {
  209.                     if ($saleCategory->getID() == $categoryID) {
  210.                         $categoryFound true;
  211.                         break;
  212.                     }
  213.                 }
  214.                 if (!$categoryFound) {
  215.                     $salesByCategory[$categoryID] = array_diff($salesByCategory[$categoryID], [$saleID]);
  216.                 }
  217.             }
  218.         }
  219.         foreach ($sale->getCategories() as $category) {
  220.             if (!isset($salesByCategory[$category->getID()])) {
  221.                 if ($category->isActive() || !$category->isPast()) {
  222.                     $category->getBanners()->toArray();
  223.                     $category->setEntityCount(1);
  224.                     $categoryForCache['category'] = $category;
  225.                     $categoryForCache['entityList'][] = $saleID;
  226.                     $salesByCategory[$category->getID()][] = $saleID;
  227.                     $this->getEntityManager()->getRepository(Category::class)->putCategoryToCache($categoryForCache);
  228.                 }
  229.             } else {
  230.                 if (!in_array($sale->getID(), $salesByCategory[$category->getID()])) {
  231.                     $salesByCategory[$category->getID()][] = $sale->getID();
  232.                 }
  233.             }
  234.         }
  235.         $softCache->set(self::ACTIVE_SALES_BY_CATEGORY$salesByCategory0);
  236.         $this->getEntityManager()->getRepository(Seo::class)->reloadCacheForEntity(SeoRepository::RESOURCE_URL_SALE_DETAILS$saleID);
  237.         return $sale;
  238.     }
  239.     public function reloadFliersCache($flierList null) {
  240.         if (!$flierList) {
  241.             $flierList $this->getActiveSalesByCategoryID(Category::FLIER_SALE_CATEGORY_ID);
  242.         }
  243.         $cityList = [];
  244.         foreach ($flierList as $flier) {
  245.             if ($flier->isInCategory(Category::FLIER_SALE_CATEGORY_ID)) {
  246.                 foreach ($flier->getGeoLocations() as $geoLocation) {
  247.                     $cityList[trim($geoLocation->getCity())][] = $flier->getID();
  248.                 }
  249.             }
  250.         }
  251.         ksort($cityList);
  252.         $cityListSorted = [];
  253.         foreach ($cityList  as $cityName => $fliers) {
  254.             $cityListSorted[mb_substr($cityName01)][] = ['cityName' => $cityName'entityList' => $fliers];
  255.         }
  256.         $softCache = new SoftCache(self::CACHE_NAME);
  257.         $softCache->set(self::CITIES_CACHE_KEY$cityListSorted0);
  258.     }
  259.     public function removeSaleFromCache($saleID) {
  260.         $softCache = new SoftCache(self::CACHE_NAME);
  261.         $sale $softCache->get($saleID);
  262.         if (!$sale) {
  263.             return;
  264.         }
  265.         $softCache->delete($saleID);
  266.         $salesByCategory $softCache->get(self::ACTIVE_SALES_BY_CATEGORY);
  267.         foreach ($salesByCategory as $key => $category) {
  268.             $salesByCategory[$key] = array_diff($category, [$saleID]);
  269.         }
  270.         $softCache->set(self::ACTIVE_SALES_BY_CATEGORY$salesByCategory0);
  271.     }
  272.     private static function compareSalesBySince(Sale $saleSale $sale1) {
  273.         return $sale->getSince() > $sale1->getSince() ? -1;
  274.     }
  275.     private static function compareSalesByPosition(Sale $saleSale $sale1) {
  276.         $saleID $sale->getID();
  277.         $sale1ID $sale1->getID();
  278.         $salePosition = isset(self::$salePositionList[$saleID]) ? self::$salePositionList[$saleID]->getPosition() : INF;
  279.         $sale1Position = isset(self::$salePositionList[$sale1ID]) ? self::$salePositionList[$sale1ID]->getPosition() : INF;
  280.         if ($salePosition == $sale1Position) {
  281.             if ($sale->getSince() == $sale1->getSince()) {
  282.                 return $sale->getID() > $sale1->getID() ? -1;
  283.             }
  284.             return $sale->getSince() > $sale1->getSince() ? -1;
  285.         }
  286.         return $salePosition $sale1Position : -1;
  287.     }
  288.     
  289.     public function getCategoryBoxData($categoryID) {
  290.         $categoryRepository $this->getEntityManager()->getRepository(Category::class);
  291.         $categoryList $categoryRepository->getActiveCategories(0, array(Category::DEFAULT_CATEGORY_TYPE), Category::SALE_CATEGORY_ID);
  292.         foreach ($categoryList as $category) {
  293.             $saleList null;
  294.             if ($category->getID() == $categoryID) {
  295.                 $saleList $this->getSalesSorted($categoryID);
  296.             }
  297.             $data['categoryList'][$category->getID()] = [
  298.                 "category" => $category,
  299.                 "saleList" => $saleList
  300.             ];
  301.         }
  302.         return $data;
  303.     }
  304.     public function getCategoryBoxDataCached($categoryID$reload false) {
  305.         $softCache = new SoftCache(self::CACHE_NAME);
  306.         $cacheKey 'categoryBox-17-' $categoryID;
  307.         $categoryBoxData $softCache->get($cacheKey);
  308.         if ($categoryBoxData && !$reload) {
  309.             return $categoryBoxData;
  310.         }
  311.         $categoryBoxData $this->getCategoryBoxData($categoryID);
  312.         $softCache->set($cacheKey$categoryBoxData0);
  313.         return $categoryBoxData;
  314.     }
  315.     
  316.     public function getSalesSorted($categoryID) {
  317.         $saleList $this->getActiveSalesByCategoryID($categoryID);
  318.         $payedPositions $this->getEntityManager()->getRepository(OfferPayedCategory::class)->findBy(
  319.             ['categoryID' => $categoryID], ['position' => 'asc']);
  320.         if ($payedPositions) {
  321.             foreach ($payedPositions as $position) {
  322.                 foreach ($saleList as $key => $sale) {
  323.                     if ($sale->getID() == $position->getEntityID()) {
  324.                         unset($saleList[$key]);
  325.                         array_splice($saleList$position->getPosition() - 10, [$sale]);
  326.                         break;
  327.                     }
  328.                 }
  329.             }
  330.         }
  331.         return $saleList;
  332.     }
  333.     public function getActiveSalesCount() {
  334.         $sql "select count(*) from sale where active and now() between since and till";
  335.         return $this->getEntityManager()->getConnection()->executeQuery($sql)->fetchColumn(0);
  336.     }
  337.     public function getActiveSalesCountCached() {
  338.         $softCache = new SoftCache(self::CACHE_NAME);
  339.         $cacheKey 'activeCount';
  340.         $salesCount $softCache->get($cacheKey);
  341.         if (!$salesCount) {
  342.             $salesCount $this->getActiveSalesCount();
  343.             $softCache->set($cacheKey$salesCount30 60);
  344.         }
  345.         return $salesCount;
  346.     }
  347.     public function getTopMainSalesJson() {
  348.         $salesList $this->getEntityManager()->getRepository(Sale::class)->findBy(['showOnMainPage' => true]);
  349.         $salesListJson = [];
  350.         foreach ($salesList as $sale) {
  351.             $tempSale = [];
  352.             $tempSale['id'] = $sale->getId();
  353.             $tempSale['topPosition'] = $sale->getTopPosition();
  354.             $salesListJson[] = $tempSale;
  355.         }
  356.         return $salesListJson;
  357.     }
  358.     public function getTopMainSales() {
  359.         $salesListJson $this->getEntityManager()->getRepository(Sale::class)->findBy(['showOnMainPage' => true], ['topPosition' => 'asc']);
  360.         return $salesListJson;
  361.     }
  362.     public function getMainSales($cityID$isMobileDevice false$offset 0) {
  363.         $topSaleList $this->getEntityManager()->getRepository(TopSale::class)->findBy(
  364.             ['city' => $cityID],
  365.             ['sortOrder' => 'ASC'],
  366.             3,
  367.             $offset
  368.         );
  369.         if (count($topSaleList) == && $cityID != City::DEFAULT_CITY_ID) {
  370.             $topSaleList $this->getEntityManager()->getRepository(TopSale::class)->findBy(
  371.                 ['city' => City::DEFAULT_CITY_ID],
  372.                 ['sortOrder' => 'ASC'],
  373.                 3,
  374.                 $offset
  375.             );
  376.         }
  377.         $result = [];
  378.         $seoRepository $this->getEntityManager()->getRepository(Seo::class);
  379.         foreach ($topSaleList as $topSale) {
  380.             $sale $topSale->getSale();
  381.             $data = [];
  382.             $data['media'] = $this->getEntityManager()->getRepository(Media::class)->getSaleMainIconMedia($sale->getID());
  383.             $data['sale'] = $sale;
  384.             if ($sale->getAlternativeURL()) {
  385.                 $data['url'] = $sale->getAlternativeURL();
  386.             } else {
  387.                 $seo $seoRepository->getByEntity(SeoRepository::RESOURCE_URL_SALE_DETAILS$sale->getID());
  388.                 $data['url'] = $seo $seo->getMainAlias() : '';
  389.             }
  390.             $result[] = $data;
  391.         }
  392.         return $result;
  393.     }
  394.     /**
  395.      * @return Sale
  396.      */
  397.     public function findCached($saleID) {
  398.         $softCache = new SoftCache(self::CACHE_NAME);
  399.         return $softCache->get($saleID);
  400.     }
  401.     public function getVisitCount($sale) {
  402.         $dql "select count(visit.ID) from Slivki:Visit visit 
  403.             where visit.entityID = :saleID and visit.entityTypeID = :entityTypeID and visit.createdOn > :dateFrom and visit.createdOn > :saleSince";
  404.         return $this->getEntityManager()->createQuery($dql)
  405.             ->setParameter('dateFrom', new \DateTime('-30 days'))
  406.             ->setParameter('saleID'$sale->getID())
  407.             ->setParameter('saleSince'$sale->getSince())
  408.             ->setParameter('entityTypeID'Category::SALE_CATEGORY_ID)
  409.             ->getSingleScalarResult();
  410.     }
  411.     public function getRecentVisitCount($saleID) {
  412.         $sql "select * from offer_category_sale where sale_id = $saleID limit 1";
  413.         $result $this->getEntityManager()->getConnection()->executeQuery($sql)->fetchAll();
  414.         return $result[0]['recent_visit_count'];
  415.     }
  416.     public function getSaleRating($saleID) {
  417.         $dql "select avg(comment.rating) rating from Slivki:Comment comment 
  418.           where comment.entityID = :entityID and comment.typeID = :typeID and comment.rating > 0 and comment.checked = true and comment.confirmedPhone = true and comment.hidden != true";
  419.         $rating $this->getEntityManager()->createQuery($dql)
  420.             ->setParameter('entityID'$saleID)->setParameter('typeID'Comment::TYPE_SALE_COMMENT)->getResult(Query::HYDRATE_SCALAR);
  421.         return round($rating[0]['rating'], 1);
  422.     }
  423.     public function sortSaleListByRecentPopularity($saleList) {
  424.         if (count($saleList) == 0) {
  425.             return [];
  426.         }
  427.         $idList = [];
  428.         foreach ($saleList as $sale) {
  429.             $idList[] = $sale->getID();
  430.         }
  431.         $sql 'select entity_id from visit_counter where type = ' VisitCounter::TYPE_SALE ' and entity_id in (' implode(', '$idList) . ') order by visit_count_recent desc';
  432.         $idList $this->getEntityManager()->getConnection()->executeQuery($sql)->fetchAll();
  433.         $saleListSorted = [];
  434.         foreach ($idList as $item) {
  435.             $saleListSorted[] = $saleList[$item['entity_id']];
  436.         }
  437.         $notInsertedSales array_udiff($saleListSorted$saleList,
  438.             function ($sale$sale1) {
  439.                 return $sale->getID() - $sale1->getID();
  440.             }
  441.         );
  442.         if (count($notInsertedSales) > 0) {
  443.             $saleListSorted array_merge($saleListSorted$notInsertedSales);
  444.         }
  445.         return $saleListSorted;
  446.     }
  447.     /**
  448.      * @return Sale
  449.      */
  450.     public function getInactiveSaleByUrl($url) {
  451.         $sql "select sale.id from sale inner join seo on sale.id = seo.entity_id where seo.resource_url = 'Slivki:Sale:details' and seo.main_alias = '$url' and sale.till < now() limit 1";
  452.         $saleID $this->getEntityManager()->getConnection()->executeQuery($sql)->fetchColumn();
  453.         if (!$saleID) {
  454.             return null;
  455.         }
  456.         return $this->find($saleID);
  457.     }
  458.     public function getHotSales($limit null$offset 0) {
  459.         $sql "select sale.id from sale inner join category2entity on sale.id = category2entity.entity_id
  460.           where category_id = " Category::NEW_SALE_CATEGORY_ID .  " and sale.active and sale.since > now() - interval '" self::HOT_SALES_DURABILITY_DAYS "' day order by sale.since desc, sale.id desc offset " $offset;
  461.         if ($limit) {
  462.             $sql .= ' limit ' $limit;
  463.         }
  464.         $salIDList $this->getEntityManager()->getConnection()->executeQuery($sql)->fetchAll(\PDO::FETCH_COLUMN);
  465.         $softCache = new SoftCache(self::CACHE_NAME);
  466.         $saleList $softCache->getMulti($salIDList);
  467.         if (!$saleList) {
  468.             $saleList = [];
  469.         }
  470.         $saleListFiltered = [];
  471.         foreach ($saleList as $sale) {
  472.             if ($sale) {
  473.                 $saleListFiltered[] = $sale;
  474.             }
  475.         }
  476.         return $saleListFiltered;
  477.     }
  478.     public function getAllActiveSalesCached() {
  479.         $categoryList $this->getEntityManager()->getRepository(Category::class)->getActiveCategories(0,[Category::DEFAULT_CATEGORY_TYPE], Category::SALE_CATEGORY_ID);
  480.         $saleList = [];
  481.         foreach ($categoryList as $category) {
  482.             foreach ($this->getActiveSalesByCategoryID($category->getID()) as $sale) {
  483.                 if (!isset($saleList[$sale->getID()])) {
  484.                     $saleList[$sale->getID()] = $sale;
  485.                 }
  486.             }
  487.         }
  488.         return $saleList;
  489.     }
  490.     public function getSaleIDSorted($sortBy$categoryID null$offset null$limit null, array $coordinates null) {
  491.         $sql 'select sale.id from sale';
  492.         $categoryCondition '';
  493.         if ($categoryID) {
  494.             $sql .= ' inner join category2entity on sale.id = category2entity.entity_id';
  495.             $categoryCondition ' and category2entity.category_id = ' . (int)$categoryID;
  496.         }
  497.         $orderBy ' order by ';
  498.         switch ($sortBy) {
  499.             case 'new':
  500.                 $orderBy .= 'sale.since desc';
  501.                 break;
  502.             case 'views':
  503.                 $sql .= ' inner join (select entity_id, sum(visit_count) as visit_count from stat_visit_count_aggregated where entity_type_id = ' Visit::TYPE_SALE .
  504.                     " and visit_date > now() + '-45 days' group by 1) as visit_count on sale.id = visit_count.entity_id";
  505.                 $orderBy .= 'visit_count.visit_count desc';
  506.                 break;
  507.             case 'location':
  508.                 if ($coordinates) {
  509.                     $sql .= ' inner join geo_location_relation on sale.id = geo_location_relation.entity_id inner join geo_location on geo_location_relation.location_id = geo_location.id';
  510.                     $orderBy .= "min(earth_distance(ll_to_earth($coordinates[0]$coordinates[1]), ll_to_earth(coalesce(nullif(latitude, ''), '0')::float8, coalesce(nullif(longitude, ''), '0')::float8)))";
  511.                 }
  512.                 break;
  513.             default:
  514.                 $orderBy .= 'sale.since desc';
  515.                 break;
  516.         }
  517.         $sql .= ' where sale.active and now() between sale.since and sale.till' $categoryCondition;
  518.         if ($coordinates) {
  519.             $sql .= ' group by 1 ';
  520.         }
  521.         $sql .= $orderBy;
  522.         if ($offset !== null && $limit) {
  523.             $sql .= ' offset ' . (int)$offset ' limit ' . (int)$limit;
  524.         }
  525.         return $this->getEntityManager()->getConnection()->executeQuery($sql)->fetchAll(\PDO::FETCH_COLUMN);
  526.     }
  527.     public function getSalesWithProduct() {
  528.         $saleList $this->getActiveSalesByCategoryID(Category::FLIER_SALE_CATEGORY_ID);
  529.         $result = [];
  530.         foreach ($saleList as $sale) {
  531.             if ($sale->getSaleProducts()->count() > 0) {
  532.                 $result[] = $sale;
  533.             }
  534.         }
  535.         return $result;
  536.     }
  537.     public function getProducts() {
  538.         $dql 'select product from Slivki:Product product join product.saleProducts saleProduct join saleProduct.sale sale where sale.active = true and sale.till > now() order by product.name asc';
  539.         return $this->getEntityManager()->createQuery($dql)->getResult();
  540.     }
  541.     public function getSaleProducts($offset$limit null) {
  542.         $dql 'select product, saleProduct, saleVersion, sale, product, teaserMedia from Slivki:Product product join product.saleProducts saleProduct join saleProduct.saleVersion saleVersion join saleVersion.sale sale index by saleProduct.ID
  543.            join saleProduct.teaserMedia teaserMedia  
  544.            where sale.active = true and sale.till > current_timestamp() and current_timestamp() between saleVersion.since and saleVersion.till + \'1 day\' order by sale.till desc, saleProduct.ID asc';
  545.         $query $this->getEntityManager()->createQuery($dql);
  546.         $query->setFirstResult($offset);
  547.         if ($limit) {
  548.             $query->setMaxResults($limit);
  549.         }
  550.         return $query->getResult();
  551.     }
  552.     public function getSaleProductCategories() {
  553.         $dql 'select category from Slivki:ProductCategory category join category.products product join product.saleProducts saleProduct join saleProduct.saleVersion saleVersion
  554.           join saleVersion.sale sale where sale.active = true order by category.name';
  555.         return $this->getEntityManager()->createQuery($dql)->getResult();
  556.     }
  557.     public function getSaleProductTopLevelCategories() {
  558.         $dql 'select category from Slivki:ProductCategory category where category.parents is empty order by category.name';
  559.         return $this->getEntityManager()->createQuery($dql)->getResult();
  560.     }
  561.     public function reloadProductCache() {
  562.         ini_set('memory_limit''1g');
  563.         $dbConnection $this->getEntityManager()->getConnection();
  564.         $productList $this->getSaleProducts(0);
  565.         $byTradingNetwork = [];
  566.         $byCategory = [];
  567.         $byCity = [];
  568.         $saleProductList = [];
  569.         $tagList = [];
  570.         foreach ($productList as $product) {
  571.             foreach ($product->getSaleProducts() as $saleProduct) {
  572.                 if (!$saleProduct->getProduct()->getCategories()) {
  573.                     continue;
  574.                 }
  575.                 $saleProductList[$saleProduct->getID()] = $saleProduct;
  576.             }
  577.         }
  578.         $sql 'select product.id, product.name from product inner join sale_product on product.id = sale_product.product_id 
  579.           inner join sale_version on sale_product.sale_version_id = sale_version.id';
  580.         $allProductList $this->getEntityManager()->getConnection()->executeQuery($sql)->fetchAll(\PDO::FETCH_ASSOC);
  581.         foreach ($allProductList as $item) {
  582.             $position mb_stripos($item['name'], '"');
  583.             if ($position 0) {
  584.                 $tag trim(mb_strtolower(mb_substr($item['name'], 0$position)));
  585.                 $tagList[$tag][] = $item['id'];
  586.             }
  587.         }
  588.         foreach ($saleProductList as $key => $saleProduct) {
  589.             $sale $saleProduct->getSaleVersion()->getSale();
  590.             $sale->getGeoLocations()->toArray();
  591.             $saleProduct->getProduct();
  592.             $sale->getDirectors()->first();
  593.             $saleProductList[$key] = $saleProduct;
  594.             foreach ($saleProduct->getProduct()->getCategories() as $category) {
  595.                 $category->getProducts()->toArray();
  596.             }
  597.             $byTradingNetwork[$sale->getID()][] = $saleProduct->getID();
  598.             $sql 'select parent_id from category2entity inner join category_child_relation on category2entity.category_id = category_child_relation.child_id where entity_id = ' $saleProduct->getProduct()->getID();
  599.             foreach ($dbConnection->executeQuery($sql)->fetchAll(\PDO::FETCH_COLUMN) as $categoryID) {
  600.                 $byCategory[$categoryID][] = $saleProduct->getID();
  601.             }
  602.             foreach ($sale->getGeoLocations() as $location) {
  603.                 $byCity[mb_strtolower($location->getCity())][] = $saleProduct->getID();
  604.             }
  605.         }
  606.         $softCache = new SoftCache(self::CACHE_NAME_PRODUCTS);
  607.         $softCache->setMulti($saleProductList0);
  608.         $softCache->set(SoftCache::CACHE_KEY_ALL$saleProductList0);
  609.         $softCache->set(self::CACHE_KEY_BY_BRAND$byTradingNetwork0);
  610.         $softCache->set(self::CACHE_KEY_BY_CATEGORY$byCategory0);
  611.         $softCache->set(self::CACHE_KEY_BY_CITY$byCity0);
  612.         $softCache->set(self::PRODUCT_TAGS_CACHE_KEY$tagList0);
  613.         dump('done');
  614.     }
  615.     public function getSaleProductsCached() {
  616.         return (new SoftCache(self::CACHE_NAME_PRODUCTS))->get(SoftCache::CACHE_KEY_ALL);
  617.     }
  618.     public function getSaleProductCached($saleProductID) {
  619.         return (new SoftCache(self::CACHE_NAME_PRODUCTS))->get($saleProductID);
  620.     }
  621.     public function getVideoguideAutorCategory(Sale $sale) {
  622.         /** @var Category $category */
  623.         foreach ($sale->getCategories() as $category) {
  624.             if ($category->isChildOf(Category::SALE_VIDEO_GUIDE_AUTORS_CATEGORY_ID)) {
  625.                 return $category;
  626.             };
  627.         }
  628.         return null;
  629.     }
  630.     public function getSaleProductsIDByCategoryID($categoryID) {
  631.         $sql 'select DISTINCT sale_product.id from sale_product
  632.                 inner join sale_version on sale_product.sale_version_id = sale_version.id
  633.                 inner join category2entity on sale_version.sale_id = category2entity.entity_id
  634.                 inner join sale on category2entity.entity_id = sale.id
  635.                 inner join media on media.entity_id = sale_product.id
  636.                 where category2entity.category_id = ' $categoryID ' and sale.active and media.type = 1
  637.                 and now() between sale_version.since and sale_version.till order by 1;';
  638.         return $this->getEntityManager()->getConnection()->executeQuery($sql)->fetchAll(\PDO::FETCH_COLUMN);
  639.     }
  640.     public function getSaleProductsByCategoryID($categoryID) {
  641.         $dql 'select saleProduct, saleVersion from Slivki:SaleProduct saleProduct join saleProduct.saleVersion saleVersion join saleProduct.product product join product.categories category 
  642.             where category.ID = :categoryID and current_date() between saleVersion.since and saleVersion.till';
  643.         $query $this->getEntityManager()->createQuery($dql)->setParameter('categoryID',$categoryID);
  644.         return $query->getResult();
  645.     }
  646.     public function getSupercheckShops() {
  647.         $shopList $this->sendSupercheckApiRequest('city/0/shops'falsefalsenull);
  648.         if (!$shopList) {
  649.             return [];
  650.         }
  651.         return $shopList;
  652.     }
  653.     private function sendSupercheckApiRequest($request$body false$userToken false$httpHeader 'json') {
  654.         $request self::API_HOST  self::API_ROOT_URL $request;
  655.         $curl curl_init($request);
  656.         curl_setopt($curlCURLOPT_RETURNTRANSFERtrue);
  657.         $result curl_exec($curl);
  658.         $statusCode curl_getinfo($curlCURLINFO_HTTP_CODE);
  659.         $result json_decode($result);
  660.         if ($statusCode != 200) {
  661.             return false;
  662.         }
  663.         return $result->result;
  664.     }
  665. }