<?php
namespace Slivki\Services;
use Doctrine\ORM\EntityManagerInterface;
use Slivki\Entity\Banner\AbstractMobileAppBanner;
use Slivki\Entity\Banner\CategoryMobileAppBanner;
use Slivki\Entity\Banner\ExternalMobileAppBanner;
use Slivki\Entity\Banner\OfferMobileAppBanner;
use Slivki\Entity\City;
use Slivki\Entity\Banner;
use Slivki\Entity\Category;
use Slivki\Entity\SidebarBanner;
use Slivki\Repository\Banner\CommentsBannerRepositoryInterface;
use Slivki\Repository\Banner\MobileAppBannerRepositoryInterface;
use Slivki\Util\SoftCache;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\KernelInterface;
final class BannerService
{
const CACHE_NAME = 'banner-1-';
const MOBILE_CACHE_NAME_PREFIX = 'mobile-1-';
const CACHE_INDEX_KEY = 'index-for-comments-3-';
const SIDEBAR_BANNER_CACHE_KEY = 'sidebar-banner-12-1-';
const MAIN_MENU_BANNER_CACHE_KEY = 'main-menu-banner-1-';
const CACHE_VERSION_CACHE_KEY = '-version-1-';
const MOBILE_APP_MAIN_PAGE_BANNER_CACHE_KEY = 'mobile-app-1-';
// offerId => bannerId
private const BANNER_BAN_LIST = [
143636 => 9322
];
private $bannerRepository;
private $entityManager;
private $container;
private $kernel;
private MobileAppBannerRepositoryInterface $mobileAppBannerRepository;
private CommentsBannerRepositoryInterface $commentsBannerRepository;
public function __construct(
EntityManagerInterface $entityManager,
ContainerInterface $container,
KernelInterface $kernel,
MobileAppBannerRepositoryInterface $mobileAppBannerRepository,
CommentsBannerRepositoryInterface $commentsBannerRepository
) {
$this->bannerRepository = $entityManager->getRepository(Banner::class);
$this->entityManager = $entityManager;
$this->container = $container;
$this->kernel = $kernel;
$this->mobileAppBannerRepository = $mobileAppBannerRepository;
$this->commentsBannerRepository = $commentsBannerRepository;
}
public function getHeadBannerCached($cityID, $categoryIDs, $mobile, $mobileCache = false) {
$cacheName = $mobileCache ? Banner::MOBILE_HEAD_BANNER_CACHE_NAME : Banner::HEAD_BANNER_CACHE_NAME;
$cacheName .= $this->getCacheVersion() . '-' . $cityID;
$softCache = new SoftCache($cacheName);
$bannersAmount = $softCache->get('amount');
if (!$bannersAmount) {
$this->reloadHeadBannerCache($cityID, $mobileCache);
$bannersAmount = $softCache->get('amount');
}
if ($bannersAmount <= 0 || $bannersAmount == SoftCache::LOCKED_KEY) {
return '';
}
$cacheKey = $mobile ? '-mobile' : '';
$bannerHtml = '';
$banners = [];
for ($i = 1; $i <= $bannersAmount; $i++) {
$banner = $softCache->get($i . $cacheKey);
$banners[$i] = $banner;
}
$session = new Session();
$bannerIndexSessionKey = $mobile ? '2-bannerIndex-mobile' : '2-bannerIndex';
$bannerIndex = $session->get($bannerIndexSessionKey);
if (!$bannerIndex || $bannerIndex > $bannersAmount) {
$bannerIndex = 1;
$session->set($bannerIndexSessionKey, $bannerIndex);
}
$categoryBannerIDs = [];
$isPassThroughOnly = true;
foreach ($categoryIDs as $categoryID) {
$currentCategory = $this->entityManager->getRepository(Category::class)->findCached((int)$categoryID);
if (isset($currentCategory['category'])) {
foreach ($banners as $key => $banner) {
if (in_array($key, $categoryBannerIDs) || (!$banner['categoryID'] && !$banner['passThrough'])) {
continue;
}
if ($banner['passThrough']) {
$categoryBannerIDs[] = $key;
} elseif ($banner['categoryID'] == $categoryID || $currentCategory['category']->isChildOfRecursive($banner['categoryID']) || $banner['passThrough']) {
$categoryBannerIDs[] = $key;
if (!$banner['passThrough']) {
$isPassThroughOnly = false;
}
}
}
}
}
if (empty($categoryBannerIDs) || $isPassThroughOnly) {
foreach ($banners as $key => $banner) {
if ($banner['categoryID'] && !$banner['passThrough']) {
unset($banners[$key]);
}
}
if (count($banners) == 0) {
return '';
}
$banners = array_combine(range(1, count($banners)), array_values($banners));
$bannersAmount = count($banners);
if ($bannerIndex > $bannersAmount) {
$bannerIndex = 1;
$session->set($bannerIndexSessionKey, $bannerIndex);
}
if (isset($banners[$bannerIndex]['html']) && (!$banners[$bannerIndex]['categoryID'] || $banners[$bannerIndex]['passThrough'])) {
$bannerHtml = $banners[$bannerIndex]['html'];
$session->set($bannerIndexSessionKey, $bannerIndex + 1);
} else {
$nextBannerIndex = $bannerIndex + 1;
$nextBannerIndex = $nextBannerIndex > $bannersAmount ? 1 : $nextBannerIndex;
while ($nextBannerIndex != $bannerIndex) {
if (isset($banners[$nextBannerIndex]['html'])) {
$bannerHtml = $banners[$nextBannerIndex]['html'];
$session->set($bannerIndexSessionKey, $nextBannerIndex);
break;
}
$nextBannerIndex++;
$nextBannerIndex = $nextBannerIndex > $bannersAmount ? 1 : $nextBannerIndex;
}
}
} else {
if (isset($banners[$bannerIndex]['html']) && in_array($bannerIndex, $categoryBannerIDs)) {
$bannerHtml = $banners[$bannerIndex]['html'];
$session->set($bannerIndexSessionKey, $bannerIndex + 1);
} else {
$nextBannerIndex = $bannerIndex + 1;
$nextBannerIndex = $nextBannerIndex > $bannersAmount ? 1 : $nextBannerIndex;
while ($nextBannerIndex != $bannerIndex) {
if (isset($banners[$nextBannerIndex]['html']) && in_array($nextBannerIndex, $categoryBannerIDs)) {
$bannerHtml = $banners[$nextBannerIndex]['html'];
$session->set($bannerIndexSessionKey, $nextBannerIndex + 1);
break;
}
$nextBannerIndex++;
$nextBannerIndex = $nextBannerIndex > $bannersAmount ? 1 : $nextBannerIndex;
}
}
}
return $bannerHtml ? $bannerHtml : '';
}
public function resetHeadBannerCache() {
$softCache = new SoftCache(self::CACHE_NAME);
$version = $softCache->get(self::CACHE_VERSION_CACHE_KEY, 0);
$version++;
$softCache->set(self::CACHE_VERSION_CACHE_KEY, $version,30 * 60);
}
public function reloadHeadBannerCache($cityID, $mobileCache = false) {
$cacheName = $mobileCache ? Banner::MOBILE_HEAD_BANNER_CACHE_NAME : Banner::HEAD_BANNER_CACHE_NAME;
$cacheName .= $this->getCacheVersion() . '-' . $cityID;
$softCache = new SoftCache($cacheName);
$previousBannersAmount = $softCache->get('amount');
if ($previousBannersAmount == SoftCache::LOCKED_KEY) {
return;
}
$softCache->set('amount', SoftCache::LOCKED_KEY, 30);
if (!$previousBannersAmount) {
$previousBannersAmount = 0;
}
$bannerList = $this->entityManager->getRepository(Banner\HeaderBanner::class)->findBy(['active' => true], ['ID' => 'DESC']);
$currentBannerAmount = 0;
$bannerListByCity = [];
foreach ($bannerList as $key => $banner) {
if (in_array($cityID, $banner->getCityIds(), true)) {
$bannerListByCity[$key] = $banner;
}
}
if (!empty($bannerListByCity)) {
$bannerList = $bannerListByCity;
}
/** @var Banner\HeaderBanner $banner */
foreach ($bannerList as $key => $banner) {
if (!$mobileCache && $banner->getCodeFilePath()) {
continue;
}
if ($banner->getCityIds() && !in_array($cityID, $banner->getCityIds(), true)) {
continue;
}
$currentBannerAmount++;
if ($banner->isJavaScript()) {
$bannerHTML = $banner->getCode();
if ($banner->getCodeFilePath()) {
$bannerHTML = @file_get_contents(realpath($this->kernel->getProjectDir() . '/public') . $banner->getCodeFilePath());
$softCache->set($currentBannerAmount . '-mobile', ['categoryID' => $banner->getCategoryID(), 'passThrough' => $banner->isPassThrough(), 'html' => $bannerHTML], 0);
}
} else {
if (stripos($banner->getFilePath(), '.swf') !== false) {
$data = [
'banner' => $banner,
'width' => '100%',
'height' => 90
];
$bannerHTML = $this->container->get('twig')->render('Slivki/banners/swf_banner.html.twig', $data);
} else {
$view = 'Slivki/banners/head_banner.html.twig';
if ($mobileCache) {
$view = 'Slivki/mobile/banner/header_banner.html.twig';
}
$bannerHTML = $this->container->get('twig')->render($view, ['topSiteBanner' => $banner]);
}
}
$softCache->set($currentBannerAmount, ['categoryID' => $banner->getCategoryID(), 'passThrough' => $banner->isPassThrough(), 'html' => $bannerHTML], 0);
if ($banner->getFilePathMobile() != '') {
if (!$banner->getCodeFilePath()) {
$view = 'Slivki/banners/head_banner.html.twig';
if ($mobileCache) {
$view = 'Slivki/mobile/banner/header_banner.html.twig';
}
$banner->setFilePath($banner->getFilePathMobile());
$bannerHTML = $this->container->get('twig')->render($view, ['topSiteBanner' => $banner]);
}
$softCache->set($currentBannerAmount . '-mobile', ['categoryID' => $banner->getCategoryID(), 'passThrough' => $banner->isPassThrough(), 'html' => $bannerHTML], 0);
}
};
for ($i = $currentBannerAmount + 1; $i <= $previousBannersAmount; $i++) {
$softCache->delete($i);
}
$softCache->set('amount', $currentBannerAmount, 30 * 60);
}
private function getCacheVersion() {
return (new SoftCache(self::CACHE_NAME))->get(self::CACHE_VERSION_CACHE_KEY, 0);
}
public function getMainMenuBannerCached() {
$softCache = new SoftCache(self::CACHE_NAME);
$cacheKey = self::MAIN_MENU_BANNER_CACHE_KEY;
$mainMenuBannerList = $softCache->get($cacheKey, []);
return $mainMenuBannerList;
}
public function reloadMainMenuBannerCache() {
$softCache = new SoftCache(self::CACHE_NAME);
$cacheKey = self::MAIN_MENU_BANNER_CACHE_KEY;
$mainMenuBannerList = $this->entityManager->getRepository(Banner\MainMenuBanner::class)->findBy(['active' => true], ['ID' => 'DESC']);
$twig = $this->container->get('twig');
$i = 0;
$banners = [];
foreach ($mainMenuBannerList as $banner) {
$banners[$i] = $twig->render('Slivki/banners/main_menu_banner.html.twig', ['banner' => $banner, 'index' => $i]);
$i++;
}
$softCache->set($cacheKey, $banners, 0);
}
public function getCategoryBannerCached(Category $category = null, $isMobile) {
if (!$category) {
return '';
}
$softCache = new SoftCache(Banner::CATEGORY_BANNER_CACHE_NAME);
$cachedBannerList = $softCache->get('category'.$category->getID());
if (!$cachedBannerList) {
$cachedBannerList = $this->reloadCategoryBannerCache($category);
}
if ($cachedBannerList == '') {
return '';
}
$bannerIDList = explode(',', $cachedBannerList);
return $this->getCategoryBannerCachedByID($bannerIDList[array_rand($bannerIDList)], $isMobile);
}
public function reloadCategoryBannerCache(Category $category) {
$softCache = new SoftCache(Banner::CATEGORY_BANNER_CACHE_NAME);
$bannerList = $category->getActiveBannersByType(Banner::TYPE_CATEGORY_BANNER);
$bannerIDList = [];
foreach ($bannerList as $banner) {
$bannerIDList[] = $banner->getID();
}
$imlodedBanerIDList = implode($bannerIDList, ',');
if (empty($bannerIDList)) {
$softCache->delete('category'.$category->getID());
return '';
}
$softCache->set('category'.$category->getID(), $imlodedBanerIDList, 30 * 40);
return $imlodedBanerIDList;
}
public function reloadCategoryBannerListCache() {
$bannerList = $this->bannerRepository->findBy(['typeID' => Banner::TYPE_CATEGORY_BANNER, 'active' => true]);
foreach ($bannerList as $banner) {
$this->reloadCategoryBannerCacheByID($banner->getID());
}
}
public function getCategoryBannerCachedByID($bannerID, $isMobile = false) {
$softCache = new SoftCache($isMobile ? self::MOBILE_CACHE_NAME_PREFIX . Banner::CATEGORY_BANNER_CACHE_NAME
: Banner::CATEGORY_BANNER_CACHE_NAME);
$bannerContent = $softCache->get($bannerID);
if (!$bannerContent) {
$bannerContent = $this->reloadCategoryBannerCacheByID($bannerID, $isMobile);
}
return $bannerContent;
}
public function reloadCategoryBannerCacheByID($bannerID, $isMobile = false) {
$softCache = new SoftCache(Banner::CATEGORY_BANNER_CACHE_NAME);
$mobileSoftCache = new SoftCache(self::MOBILE_CACHE_NAME_PREFIX . Banner::CATEGORY_BANNER_CACHE_NAME);
/** @var Banner $banner */
$banner = $this->bannerRepository->find($bannerID);
if (!$banner) {
return '';
}
if ($banner->getTypeID() != Banner::TYPE_CATEGORY_BANNER) {
return '';
}
if (!$banner->isActive()) {
$softCache->delete($bannerID);
}
$data['categoryBanner'] = $banner;
$twig = $this->container->get('twig');
$bannerContent = $twig->render('Slivki/banners/category_banner.html.twig', $data);
$softCache->set($bannerID, $bannerContent, 60 * 40);
$mobileBannerContent = $twig->render('Slivki/mobile/banner/banner.html.twig', ['banner' => $banner]);
$mobileSoftCache->set($bannerID, $mobileBannerContent, 60 * 40);
return $isMobile ? $mobileBannerContent : $bannerContent;
}
public function getCommentsBanners($mobileDevice = false, $cityID = City::DEFAULT_CITY_ID, $offerId = null) {
$commentsBannerList = $this->commentsBannerRepository->findActiveByCities([$cityID]);
$commentsBannerHtmlList = [];
$view = $mobileDevice ? 'Slivki/mobile/banner/banner.html.twig' : 'Slivki/banners/comments_banner.html.twig';
/** @var Banner $banner */
foreach($commentsBannerList as $banner) {
if (null !== $offerId && !empty(self::BANNER_BAN_LIST[$offerId]) && (int) $banner->getID() === self::BANNER_BAN_LIST[$offerId]) {
continue;
}
$commentsBannerHtmlList[$banner->getPositionRow()][] = $this->container->get('twig')->render($view, ['banner' => $banner]);
}
// Add offer button
ksort($commentsBannerHtmlList);
$i = 1;
foreach ($commentsBannerHtmlList as $key=>$item) {
if ($i == 2 && !isset($commentsBannerHtmlList[$key+2]) && !$mobileDevice) {
$commentsBannerHtmlList[$key+2][0] = '<div class="add-offer-comment-link"><a class="button--rose button" href="/moya_akciya" onclick="ga(\'send\', \'event\', \'create-own-offer-button--comments\', \'Click\', \'1\');">Разместить свою акцию на Slivki.by</a></div>';
}
if ($i > 2) {
break;
}
$i++;
}
return $commentsBannerHtmlList;
}
public function getCacheIndex() {
$softCache = new SoftCache(self::CACHE_NAME);
$cacheKey = self::CACHE_INDEX_KEY;
$cacheIndex = $softCache->get($cacheKey);
return $cacheIndex ? $cacheIndex : 0;
}
public function incrementCacheIndex() {
$softCache = new SoftCache(self::CACHE_NAME);
$cacheKey = self::CACHE_INDEX_KEY;
$cacheIndex = $softCache->get($cacheKey);
$cacheIndex = $cacheIndex ? $cacheIndex + 1 : 1;
$softCache->set($cacheKey, $cacheIndex, 0);
}
public function getSidebarBannerCached($cityID) {
$softCache = new SoftCache(self::CACHE_NAME);
$cacheKey = self::SIDEBAR_BANNER_CACHE_KEY . '-' . $cityID;
$cacheKeyLocked = $cacheKey . '-locked';
$sidebarBannerCached = $softCache->get($cacheKey);
if (!$sidebarBannerCached || ($sidebarBannerCached['expiredOn'] > time() && !$softCache->get($cacheKeyLocked))) {
return $this->reloadSidebarBannerCache($cityID);
}
$sidebarBannerCached['serverTimeToBannerTime'] = strtotime(date("Y-m-d 09:00:00")) - time();
return $sidebarBannerCached;
}
public function reloadSidebarBannerCache($cityID) {
$softCache = new SoftCache(self::CACHE_NAME);
$cacheKey = self::SIDEBAR_BANNER_CACHE_KEY . '-' . $cityID;
$cacheKeyLocked = $cacheKey . '-locked';
$softCache->add($cacheKeyLocked, 'locked', 20);
$sidebarBannerRepository = $this->entityManager->getRepository(SidebarBanner::class);
$bannerList = $sidebarBannerRepository->findBy(['active' => true, 'cityID' => $cityID], ['ID' => 'ASC']);
if (!$bannerList) {
$bannerList = $sidebarBannerRepository->findBy(['active' => true, 'cityID' => City::DEFAULT_CITY_ID], ['ID' => 'ASC']);
}
$sidebarBannerCached['serverTimeToBannerTime'] = strtotime(date("Y-m-d 09:00:00")) - time();
$sidebarBannerCached['html'] = $this->container->get('twig')->render('Slivki/banners/sidebar_banner.html.twig', [
'bannerList' => $bannerList,
'lastPurchasesOfferList' => []
]);
$sidebarBannerCached['expiredOn'] = time() + 60 * 5;
$softCache->set($cacheKey, $sidebarBannerCached, 0);
return $sidebarBannerCached;
}
public function getBeautyShopBannerCached() {
$softCache = new SoftCache(Banner::BEAUTY_SHOPS_CACHE_NAME);
$cachedBannerList = $softCache->get('beautyShop');
if (!$cachedBannerList) {
$cachedBannerList = $this->reloadBeautyShopBannerCache();
}
if ($cachedBannerList == '') {
return '';
}
$bannerIDList = explode(',', $cachedBannerList);
return $this->getBeautyShopBannerCachedByID($bannerIDList[array_rand($bannerIDList)]);
}
public function reloadBeautyShopBannerCache() {
$softCache = new SoftCache(Banner::CATEGORY_BANNER_CACHE_NAME);
$bannerList = $this->bannerRepository->findBy(['typeID' => Banner::TYPE_BEAUTY_SHOPS_BANNER, 'active' => true]);
$bannerIDList = [];
foreach ($bannerList as $banner) {
$bannerIDList[] = $banner->getID();
}
$imlodedBanerIDList = implode($bannerIDList, ',');
if (empty($bannerIDList)) {
$softCache->delete('beautyShop');
return '';
}
$softCache->set('beautyShop', $imlodedBanerIDList, 30 * 40);
return $imlodedBanerIDList;
}
public function reloadBeautyShopBannerListCache() {
$bannerList = $this->bannerRepository->findBy(['typeID' => Banner::TYPE_BEAUTY_SHOPS_BANNER, 'active' => true]);
foreach ($bannerList as $banner) {
$this->reloadBeautyShopBannerCacheByID($banner->getID());
}
}
public function getBeautyShopBannerCachedByID($bannerID) {
$softCache = new SoftCache(Banner::BEAUTY_SHOPS_CACHE_NAME);
$bannerContent = $softCache->get($bannerID);
if (!$bannerContent) {
$bannerContent = $this->reloadBeautyShopBannerCacheByID($bannerID);
}
return $bannerContent;
}
public function reloadBeautyShopBannerCacheByID($bannerID) {
$softCache = new SoftCache(Banner::BEAUTY_SHOPS_CACHE_NAME);
/** @var Banner $banner */
$banner = $this->bannerRepository->find($bannerID);
if (!$banner) {
return '';
}
if ($banner->getTypeID() != Banner::TYPE_BEAUTY_SHOPS_BANNER) {
return '';
}
if (!$banner->isActive()) {
$softCache->delete($bannerID);
}
$data['banner'] = $banner;
$bannerContent = $this->container->get('twig')->render('Slivki/banners/beauty_shop_banner.html.twig', $data);
$softCache->set($bannerID, $bannerContent, 60 * 40);
return $bannerContent;
}
public function getMobileAppMainPageBannerCache($cityID = City::DEFAULT_CITY_ID) {
$softCache = new SoftCache(self::CACHE_NAME);
$result = $softCache->get(self::MOBILE_APP_MAIN_PAGE_BANNER_CACHE_KEY . $cityID);
if (!$result) {
return $this->reloadMobileAppMainPageBannerCache($cityID);
}
return $result;
}
public function reloadMobileAppMainPageBannerCache(int $cityID = City::DEFAULT_CITY_ID): array
{
$softCache = new SoftCache(self::CACHE_NAME);
$result = [];
$banners = $this->mobileAppBannerRepository->findActiveByCity($cityID);
$baseURL = $this->container->getParameter('base_url');
/** @var AbstractMobileAppBanner $banner */
foreach ($banners as $banner) {
$entityID = null;
if ($banner instanceof CategoryMobileAppBanner) {
$entityID = $banner->getCategory()->getID();
$target = 'category';
$entityName = $banner->getCategory()->getName();
} elseif ($banner instanceof OfferMobileAppBanner) {
$entityID = $banner->getOffer()->getID();
$target = 'offer';
$entityName = $banner->getOffer()->getTitle();
} elseif ($banner instanceof ExternalMobileAppBanner) {
$target = 'external';
}
$result[] = [
'ID' => $banner->getID(),
'imageURL' => $baseURL . $banner->getFilePath(),
'target' => $target,
'entityID' => $entityID,
'entityName' => $entityName,
'externalUrl' => $banner->getURL(),
];
}
$softCache->set(self::MOBILE_APP_MAIN_PAGE_BANNER_CACHE_KEY . $cityID, $result, 60 * 30);
return $result;
}
}