<?php
/*
* This file is part of EC-CUBE
*
* Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
*
* http://www.ec-cube.co.jp/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Customize\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Doctrine\ORM\EntityManagerInterface;
use Eccube\Entity\Customer;
use Exception;
use Customize\Exception\DenyProductException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Eccube\Entity\Product;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* カートに商品を追加した際に発生するイベントリスナー。
*/
class EccubeProductCartAddListener implements EventSubscriberInterface
{
const ERRORS = array(
'duplicate' => 'この商品は複数回購入することができません。',
'guest' => 'この商品はログインした状態でのみ購入することが可能です。',
'product' => '対象の商品が見つかりませんでした。'
);
/**
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* @var SessionInterface
*/
private $session;
/**
* @var Security $security
*/
private $security;
public function __construct(EntityManagerInterface $entityManager, SessionInterface $session, Security $security)
{
$this->entityManager = $entityManager;
$this->session = $session;
$this->security = $security;
}
/**
* 対応するメソッドと優先度を登録する。
* 数値が高いほど優先度高。
*
* @see https://symfony.com/doc/4.4/event_dispatcher.html
*
* @return array
*/
public static function getSubscribedEvents()
{
return [
EccubeEvents::FRONT_PRODUCT_CART_ADD_INITIALIZE => [
['prohibitionOfDuplicatePurchases', 0]
]
];
}
/**
* 特定商品(プランの重複購入およびゲスト購入を禁止する。
* 基本的にはtwigで制御するため、不正POST対策のみ。
*
* @param EventArgs $event
* @return void
* @throws Exception
*/
public function prohibitionOfDuplicatePurchases(EventArgs $event)
{
try {
/** @var Request $request */
$request = $event->getRequest();
$arguments = $event->getArguments();
if (!isset($arguments['Product'])) {
return $this->redirectOrThrowError($request, self::ERRORS['product']);
}
/** @var \Eccube\Entity\Product $product */
$product = $arguments['Product'];
if ($product->getId() == env('PLAN_PRODUCT_ID', 77)) {
// ログインしていない
/** @var \Eccube\Entity\Customer $user */
$user = $this->security->getUser();
if (empty($user) || !$user instanceof Customer) {
return $this->redirectOrThrowError($request, self::ERRORS['guest'], $product);
}
/** @var \Doctrine\Common\Collections\ArrayCollection $orders */
$orders = $user->getOrders();
/** @var \Eccube\Entity\Order $order */
foreach ($orders as $order) {
if (!empty($order->getOrderStatus()) && $order->getOrderStatus()->isDisplayOrderCount()) {
/** @var \Eccube\Entity\OrderItem */
foreach ($order->getOrderItems() as $orderItem) {
if ($orderItem->isProduct()) {
$productId = $orderItem->getProduct()->getId();
if ($productId == env('PLAN_PRODUCT_ID', 77)) {
return $this->redirectOrThrowError($request, self::ERRORS['duplicate'], $product);
}
}
}
}
}
}
} catch (DenyProductException $e) {
throw $e;
} catch (NotFoundHttpException $e) {
throw $e;
} catch (Exception $e) {
throw $e;
}
}
/**
* 商品の購入を許可しない場合レスポンスまたは例外を発生させる。
* Ajax: 例外, 通常アクセス: リダイレクト
* →リダイレクトの場合ディスパッチ元の処理が続行してしまうため例外で対応。
*
* @param Request $request
* @param string $message
* @return RedirectResponse|void
* @throws DenyProductException|NotFoundHttpException
*/
public function redirectOrThrowError(Request $request, string $message, Product $product = null)
{
if (empty($product)) {
throw new NotFoundHttpException();
}
if ($request->isXmlHttpRequest()) {
throw new DenyProductException($message);
} else {
throw new NotFoundHttpException();
// global $kernel;
// $container = $kernel->getContainer();
// $redirectUrl = $container->get('router')->generate('product_detail', ['id' => $product->getId()], UrlGeneratorInterface::ABSOLUTE_PATH);
// $this->session->getFlashBag()->add('customize.error.deny_product', $message);
// return new RedirectResponse($redirectUrl);
}
}
}