<?php
/*
* This file is part of the RecentlyViewedProducts Plugin
*
* Copyright (C) 2023 Diezon.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Plugin\RecentlyViewedProducts\Service;
use Doctrine\ORM\EntityManagerInterface;
use Eccube\Repository\ProductRepository;
use Eccube\Util\StringUtil;
use Eccube\Entity\Customer;
use Eccube\Entity\Product;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Plugin\RecentlyViewedProducts\Entity\RecentlyViewedProduct;
use Plugin\RecentlyViewedProducts\Repository\RecentlyViewedProductRepository;
class RecentlyViewedProductService
{
const SESSION_KEY = 'plugin.recently_viewed_products.identification_key';
/**
* @var SessionInterface
*/
protected $session;
/**
* @var \Doctrine\ORM\EntityManagerInterface
*/
protected $entityManager;
/**
* @var ProductRepository
*/
protected $productRepository;
/**
* @var RecentlyViewedProductRepository
*/
protected $recentlyViewedProductRepository;
/**
* @var TokenStorageInterface
*/
protected $tokenStorage;
/**
* RecentlyViewedProductService constructor.
*/
public function __construct(
RequestStack $requestStack,
EntityManagerInterface $entityManager,
ProductRepository $productRepository,
RecentlyViewedProductRepository $recentlyViewedProductRepository,
TokenStorageInterface $tokenStorage
) {
$this->session = $requestStack->getSession();
$this->entityManager = $entityManager;
$this->productRepository = $productRepository;
$this->recentlyViewedProductRepository = $recentlyViewedProductRepository;
$this->tokenStorage = $tokenStorage;
}
/**
* @param Customer $Customer
* @return array
*/
public function getPersistedProducts($Customer = null)
{
return $this->recentlyViewedProductRepository->getRecentlyViewedProductsByCustomer($Customer ? $Customer : $this->getUser());
}
/**
* @param Customer $Customer
* @return array
*/
public function getAllPersistedProducts($Customer = null)
{
return $this->recentlyViewedProductRepository->getRecentlyViewedProductsByCustomer($Customer ? $Customer : $this->getUser(), true);
}
/**
* @return array
*/
public function getSessionProducts()
{
$identificationKey = $this->session->get(self::SESSION_KEY, null);
if (empty($identificationKey)) {
return [];
}
return $this->recentlyViewedProductRepository->getRecentlyViewedProductsByIdentificationKey($identificationKey);
}
/**
* @return array
*/
public function getAllSessionProducts()
{
$identificationKey = $this->session->get(self::SESSION_KEY, null);
if (empty($identificationKey)) {
return [];
}
return $this->recentlyViewedProductRepository->getRecentlyViewedProductsByIdentificationKey($identificationKey, true);
}
/**
* @param Customer $Customer
* @return void
*/
public function mergeFromPersistedProducts(Customer $Customer)
{
$PersistedProducts = $this->getPersistedProducts();
$SessionProducts = $this->getSessionProducts();
$productInfo = [];
foreach ($PersistedProducts as $PeristedProduct) {
$productInfo[$PeristedProduct->getProduct()->getId()] = $PeristedProduct;
}
foreach ($SessionProducts as $SessionProduct) {
if (isset($productInfo[$SessionProduct->getProduct()->getId()])) {
$PeristedProduct = $productInfo[$SessionProduct->getProduct()->getId()];
if ($SessionProduct->getViewedDate() > $PeristedProduct->getViewedDate()) {
$PeristedProduct->setViewedDate($SessionProduct->getViewedDate());
}
// 不要なレコードは削除
$this->entityManager->remove($SessionProduct);
} else {
$SessionProduct->setCustomer($Customer);
}
}
$this->entityManager->flush();
}
/**
* @return array
*/
public function getRecentlyViewedProducts()
{
if ($this->getUser()) {
return $this->getPersistedProducts();
} else {
return $this->getSessionProducts();
}
}
/**
* @param Product $Product
* @return void
*/
public function addViewedProduct($Product)
{
$Customer = $this->getUser();
if ($Customer) {
$RecentlyViewedProduct = $this->recentlyViewedProductRepository->findOneBy([
'Customer' => $Customer,
'Product' => $Product,
]);
} else {
$identificationKey = $this->getIdentificationKey();
$RecentlyViewedProduct = $this->recentlyViewedProductRepository->findOneBy([
'identification_key' => $identificationKey,
'Product' => $Product,
]);
}
if (!$RecentlyViewedProduct) {
$RecentlyViewedProduct = new RecentlyViewedProduct();
$RecentlyViewedProduct->setProduct($Product);
if ($Customer) {
$RecentlyViewedProduct->setCustomer($Customer);
} else {
$RecentlyViewedProduct->setIdentificationKey($identificationKey);
}
$this->entityManager->persist($RecentlyViewedProduct);
}
$RecentlyViewedProduct->setViewedDate(new \DateTime());
$this->entityManager->flush($RecentlyViewedProduct);
}
/**
* @return void
*/
public function clear()
{
if ($this->getUser()) {
$RecentlyViewedProducts = $this->getAllPersistedProducts();
} else {
$RecentlyViewedProducts = $this->getAllSessionProducts();
}
foreach ($RecentlyViewedProducts as $RecentlyViewedProduct) {
$this->entityManager->remove($RecentlyViewedProduct);
}
$this->entityManager->flush();
}
/**
* @return string
*/
protected function getIdentificationKey()
{
if ($this->session->has(self::SESSION_KEY)) {
return $this->session->get(self::SESSION_KEY);
}
do {
$identificationKey = StringUtil::random(32);
$RecentlyViewedProducts = $this->recentlyViewedProductRepository->findBy(['identification_key' => $identificationKey], [], 1);
} while (count($RecentlyViewedProducts) > 0);
$this->session->set(self::SESSION_KEY, $identificationKey);
return $identificationKey;
}
/**
* @return Customer|null
*/
protected function getUser()
{
if (null === $token = $this->tokenStorage->getToken()) {
return;
}
if (!is_object($user = $token->getUser())) {
// e.g. anonymous authentication
return;
}
return $user;
}
}