<?php
namespace App\Service;
use App\Entity\Profile\Profile;
use App\Entity\Sales\Profile\PlacementCharge;
use App\Entity\Sales\Profile\TopPlacement;
use App\Event\Profile\ProfilesShownEvent;
use App\Event\Profile\ProfileWasPlacedOnTop;
use App\Repository\PaidPlacementPriceRepository;
use App\Repository\ProfileTopPlacementRepository;
use Carbon\CarbonImmutable;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class ProfileTopBoard
{
private ?ObjectManager $entityManager;
public function __construct(
ManagerRegistry $managerRegistry,
private ProfileChargesCalculator $profileChargesCalculator,
private PaidPlacementPriceRepository $paidPlacementPriceRepository,
private AccountFinances $accountFinances,
private ProfileTopPlacementRepository $profileTopPlacementRepository,
private EventDispatcherInterface $eventDispatcher,
private CurrentCityResolver $cityResolver,
private ProfileAdBoard $profileAdBoard
)
{
$this->entityManager = $managerRegistry->getManagerForClass(TopPlacement::class);
}
public function doPlaceOnTop(Profile $profile, \DateTimeImmutable $placedAt, \DateTimeImmutable $placedUntil): void
{
$city = $profile->getCity();
$overlaps = $this->profileTopPlacementRepository->getPlacementsByPeriod($city, $placedAt, $placedUntil);
if(count($overlaps))
throw new \LogicException('Некоторые из выбранных промежутков уже заняты.', 1);
$timezone = $placedAt->getTimezone();
$now = new \DateTime('now', $timezone);
if($placedAt->format("Y-m-d H") == $now->format("Y-m-d H"))
throw new \LogicException('Нельзя разместить на текущий час', 2);
$placementPrice = $this->paidPlacementPriceRepository->getProfileTopPlacementPrice($profile);
$charges = $this->profileChargesCalculator->calculateTopPlacementCharges($profile, $placedAt, $placedUntil);
$placement = new TopPlacement($city, $profile, $placementPrice, $placedAt, $placedUntil);
$placementCharge = new PlacementCharge($profile, $charges, CarbonImmutable::now(), $placementPrice, $placedAt, $placedUntil);
$this->entityManager->transactional(function (EntityManagerInterface $em) use ($city, $placement, $placementCharge, $profile): void {
$this->accountFinances->processCharge($placementCharge);
$em->persist($placement);
$profile->addTopPlacement($placement);
$this->eventDispatcher->dispatch(new ProfileWasPlacedOnTop($profile, $placement), ProfileWasPlacedOnTop::NAME);
});
}
public function currentTopPlacement(bool $increaseShows): ?Profile
{
$city = $this->cityResolver->resolveCurrentCity();
$currentTime = CarbonImmutable::now();
$profile = $this->profileTopPlacementRepository->getCurrentlyPlaced($city, $currentTime);
if($profile) {
$this->profileAdBoard->deleteProfileHiding($profile);
if($increaseShows) {
$this->eventDispatcher->dispatch(new ProfilesShownEvent([$profile->getId()], 'top'), ProfilesShownEvent::NAME);
}
}
return $profile;
}
}