<?php
namespace App\Service;
use App\Entity\Location\City;
use App\Entity\Profile\Genders;
use App\Entity\Profile\Profile;
use App\Entity\Sales\PaidPlacementPrice;
use App\Entity\Sales\Profile\SidebarPlacement;
use App\Entity\Sales\SidebarPlacementType;
use App\Entity\Saloon\Saloon;
use App\Event\Profile\ProfilesShownEvent;
use App\Repository\ProfileSidebarPlacementRepository;
use App\Repository\SaloonSidebarPlacementRepository;
use App\Repository\SidebarPlacementRepository;
use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Cache\ItemInterface;
class Sidebar
{
CONST MINUTES_TO_BE_NEW = 2;
public function __construct(
private EntityManagerInterface $entityManager,
private ProfileSidebarPlacementRepository $profileSidebarPlacementRepository,
private SaloonSidebarPlacementRepository $saloonSidebarPlacementRepository,
private SidebarPlacementRepository $sidebarPlacementRepository,
private CacheItemPoolInterface $sidebarNewCheckCoolDownCache,
private EventDispatcherInterface $eventDispatcher
) {}
public function doPlaceProfileOnSidebar(Profile $profile, SidebarPlacementType $placementType, PaidPlacementPrice $placementPrice, \DateTimeImmutable $placedAt, \DateTimeImmutable $placedUntil): void
{
if(false == $placementType->isVip() && false == $placementType->isUltraVip()) {
throw new \DomainException('Must be vip or ultra vip placement');
}
if($placementType->isVip() || $placementType->isUltraVip()) {
$creationMethod = SidebarPlacementType::getCamelCaseLabel($placementType->getValue());
$sidebarPlacement = SidebarPlacement::$creationMethod($profile, $placementPrice, $placedAt, $placedUntil);
$this->entityManager->persist($sidebarPlacement);
}
}
public function deleteProfileFromSidebar(Profile $profile): void
{
$sidebarPlacement = $this->profileSidebarPlacementRepository->getPlacementByProfile($profile);
if($sidebarPlacement) {
$this->entityManager->remove($sidebarPlacement);
}
}
public function prolongProfilePlacement(Profile $profile, CarbonImmutable $nextHour): void
{
$sidebarPlacement = $this->profileSidebarPlacementRepository->getPlacementByProfile($profile);
if($sidebarPlacement) {
$sidebarPlacement->prolong($nextHour);
}
}
public function doPlaceSaloonOnSidebar(Saloon $saloon, SidebarPlacementType $placementType, PaidPlacementPrice $placementPrice, \DateTimeImmutable $placedAt, \DateTimeImmutable $placedUntil): void
{
if(false == $placementType->isVip() && false == $placementType->isUltraVip()) {
throw new \DomainException('Must be vip or ultra vip placement');
}
if($placementType->isVip() || $placementType->isUltraVip()) {
$creationMethod = SidebarPlacementType::getCamelCaseLabel($placementType->getValue());
$sidebarPlacement = \App\Entity\Sales\Saloon\SidebarPlacement::$creationMethod($saloon, $placementPrice, $placedAt, $placedUntil);
$this->entityManager->persist($sidebarPlacement);
}
}
public function deleteSaloonFromSidebar(Saloon $saloon): void
{
$sidebarPlacement = $this->saloonSidebarPlacementRepository->getPlacementBySaloon($saloon);
if($sidebarPlacement) {
$this->entityManager->remove($sidebarPlacement);
}
}
public function prolongSaloonPlacement(Saloon $saloon, CarbonImmutable $nextHour): void
{
$sidebarPlacement = $this->saloonSidebarPlacementRepository->getPlacementBySaloon($saloon);
if($sidebarPlacement) {
$sidebarPlacement->prolong($nextHour);
}
}
//////////////////////////////////
/// ROTATION
//////////////////////////////////
protected function checkOutdatedNew(City $city, int $type, array $genders = [Genders::FEMALE], array $gendersToUpdate = [Genders::FEMALE]): void
{
//максимальное кол-во показов по городу
$maxShowsByCity = $this->sidebarPlacementRepository->getMaxShowsForOldPlacementsByTypeInCity($city, $type/*, $genders*/);
$date = Carbon::now();
$date->modify(sprintf('-%s minutes', self::MINUTES_TO_BE_NEW));
$this->sidebarPlacementRepository->updateNewPlacementsByTypeOlderThanInCity($city, $type, $date, $maxShowsByCity, $gendersToUpdate);
// $new = $this->sidebarPlacementRepository->getNewPlacementsByTypeOlderThanInCity($city, $type, $date, $maxShowsByCity, $genders);
// array_map(function(\App\Entity\Sales\SidebarPlacement $placement) use ($maxShowsByCity) {
// //"новым", которые перешли по сроку в "не новые", ставим кол-во просмотров макс. по городу + просмотры самого плейсмента
// $placement->setIsNew(false);
// $placement->setShows($placement->getShows() + $maxShowsByCity);
// }, $new);
$this->entityManager->flush();
}
protected function processShowOnPlacementsByTypeExcluding(City $city, int $type, int $count, array $exclude, array $genders = [Genders::FEMALE], bool $onlyProfile = false, bool $onlyMasseur = false, bool $onlySaloon = false): array
{
$placements = $this->sidebarPlacementRepository->getPlacementsOrderedByShowsExcluding($city, $type, $exclude, $count, $genders, $onlyProfile, $onlyMasseur, $onlySaloon);
array_map(function(\App\Entity\Sales\SidebarPlacement $placement): void {
$placement->show();
}, $placements);
$this->entityManager->flush();
return $placements;
}
public function getPlacementsToShow(City $city, int $type, int $count, array $exclude, array $genders = [Genders::FEMALE], bool $onlyProfile = false, bool $onlyMasseur = false, bool $onlySaloon = false): array
{
$coolDownKey = 'cool_down_'.$city->getId().'_'.$type.'_'.implode($genders);
$this->sidebarNewCheckCoolDownCache->get($coolDownKey, function (ItemInterface $item) use ($city, $type, $genders, $coolDownKey): int {
$this->checkOutdatedNew($city, $type, $genders, $genders);
return 1;
});
$placements = $this->processShowOnPlacementsByTypeExcluding($city, $type, $count, $exclude, $genders, $onlyProfile, $onlyMasseur, $onlySaloon);
$new = []; $old = [];
foreach ($placements as $placement) {
/** @var \App\Entity\Sales\SidebarPlacement $placement */
$placement->isNew()
? $new[] = $placement
: $old[] = $placement;
}
shuffle($new);
shuffle($old);
$placements = array_merge($new, $old);
$profileIds = [];
foreach ($placements as $placement) {
if($placement instanceof SidebarPlacement)
$profileIds[] = $placement->getProfile()->getId();
}
$this->eventDispatcher->dispatch(new ProfilesShownEvent($profileIds, 'sidebar'), ProfilesShownEvent::NAME);
return $placements;
}
}