<?php
declare(strict_types=1);
namespace BitBag\OpenMarketplace\Component\ProductComparer\Provider;
use BitBag\OpenMarketplace\Component\Customer\Model\CustomerInterface;
use BitBag\OpenMarketplace\Component\ProductComparer\Entity\ComparerInterface;
use BitBag\OpenMarketplace\Component\ProductComparer\Event\MissingCookieException;
use BitBag\OpenMarketplace\Component\ProductComparer\Factory\ComparerFactoryInterface;
use BitBag\OpenMarketplace\Component\ProductComparer\Repository\ComparerRepositoryInterface;
use BitBag\OpenMarketplace\Component\Vendor\Entity\ShopUserInterface;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Sylius\Component\Core\Context\ShopperContextInterface;
use Symfony\Component\HttpFoundation\RequestStack;
final class ComparerProvider implements ComparerProviderInterface
{
public function __construct(
private ComparerFactoryInterface $comparerFactory,
private ComparerRepositoryInterface $comparerRepository,
private ShopperContextInterface $shopperContext,
private EntityManagerInterface $entityManager,
private RequestStack $requestStack
) {
}
/** @inheritDoc */
public function provide(): ComparerInterface
{
$shopUser = $this->getShopUserFromContext();
$comparer = $shopUser instanceof ShopUserInterface
? $this->getComparerForShopUser($shopUser)
: $this->getComparerForAnonymousUser()
;
$this->clearOldProducts($comparer);
return $comparer;
}
private function clearOldProducts(ComparerInterface $comparer): void
{
if (false === $this->isOlderThanOneDay($comparer)) {
return;
}
foreach ($comparer->getComparerProducts() as $comparerProduct) {
$comparer->removeComparerProduct($comparerProduct);
}
$comparer->setCreatedAt(new DateTime());
$this->entityManager->persist($comparer);
$this->entityManager->flush();
}
private function isOlderThanOneDay(ComparerInterface $comparer): bool
{
$createdAt = $comparer->getCreatedAt();
if (null === $createdAt) {
return true;
}
$now = new DateTime();
$diff = $now->diff($createdAt);
return 1 <= $diff->days;
}
private function getShopUserFromContext(): ?ShopUserInterface
{
$customer = $this->shopperContext->getCustomer();
if (!$customer instanceof CustomerInterface) {
return null;
}
$shopUser = $customer->getUser();
if (!$shopUser instanceof ShopUserInterface) {
return null;
}
return $shopUser;
}
private function getComparerForShopUser(ShopUserInterface $shopUser): ComparerInterface
{
$comparer = $this->comparerRepository->findOneByShopUser($shopUser);
if ($comparer instanceof ComparerInterface) {
return $comparer;
}
return $this->comparerFactory->createNewForShopUser($shopUser);
}
private function getComparerForAnonymousUser(): ComparerInterface
{
$session = $this->requestStack->getSession();
$comparerToken = $session->getId();
if ('' === $comparerToken) {
throw new MissingCookieException('Session ID cannot be null');
}
$comparer = $this->comparerRepository->findOneByToken($comparerToken);
if ($comparer instanceof ComparerInterface) {
return $comparer;
}
return $this->comparerFactory->createNewForToken($comparerToken);
}
}