<?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\Controller;
use Customize\Event\EccubeEvents;
use Customize\Repository\BitHistoryRepository;
use Customize\Repository\PreviewTenderRepository;
use Customize\Repository\ProductRepository;
use Customize\Repository\ProductAccessRepository;
use Customize\Repository\ProductMemoRepository;
use Customize\Repository\OrderRepository;
use Eccube\Controller\AbstractController;
//use Eccube\Entity\BaseInfo;
use Eccube\Entity\Master\ProductStatus;
use Eccube\Entity\Product;
use Eccube\Event\EventArgs;
//use Eccube\Form\Type\AddCartType;
//use Eccube\Form\Type\SearchProductType;
//use Eccube\Repository\BaseInfoRepository;
use Eccube\Repository\CustomerFavoriteProductRepository;
use Eccube\Repository\Master\ProductListMaxRepository;
//use Eccube\Service\CartService;
//use Eccube\Service\PurchaseFlow\PurchaseContext;
//use Eccube\Service\PurchaseFlow\PurchaseFlow;
//use Knp\Bundle\PaginatorBundle\Pagination\SlidingPagination;
//use Knp\Component\Pager\PaginatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class ProductController extends AbstractController
{
/**
* @var BitHistoryRepository
*/
protected $bitHistoryRepository;
/**
* @var CustomerFavoriteProductRepository
*/
protected $customerFavoriteProductRepository;
/**
* @var PreviewTenderRepository
*/
protected $previewTenderRepository;
/**
* @var ProductRepository
*/
protected $productRepository;
/**
* @var ProductAccessRepository
*/
protected $productAccessRepository;
/**
* @var ProductMemoRepository
*/
protected $productMemoRepository;
/**
* @var AuthenticationUtils
*/
protected $helper;
/**
* @var ProductListMaxRepository
*/
protected $productListMaxRepository;
/**
* @var OrderRepository
*/
protected $orderRepository;
private $title = '';
/**
* ProductController constructor.
*
* @param ProductAccessRepository $ProductAccessRepository
*/
public function __construct(
CustomerFavoriteProductRepository $customerFavoriteProductRepository,
PreviewTenderRepository $previewTenderRepository,
ProductRepository $productRepository,
ProductAccessRepository $productAccessRepository,
ProductMemoRepository $productMemoRepository,
AuthenticationUtils $helper,
ProductListMaxRepository $productListMaxRepository,
BitHistoryRepository $bitHistoryRepository,
OrderRepository $orderRepository,
) {
$this->customerFavoriteProductRepository = $customerFavoriteProductRepository;
$this->previewTenderRepository = $previewTenderRepository;
$this->productRepository = $productRepository;
$this->productAccessRepository = $productAccessRepository;
$this->productMemoRepository = $productMemoRepository;
$this->helper = $helper;
$this->productListMaxRepository = $productListMaxRepository;
$this->bitHistoryRepository = $bitHistoryRepository;
$this->orderRepository = $orderRepository;
}
/**
* 商品一覧画面.
*
* @Route("/products/list", name="product_list", methods={"GET"})
*
* @Template("Product/list.twig")
*/
/* public function index(Request $request, PaginatorInterface $paginator)
{
if ($this->BaseInfo->isOptionNostockHidden()) {
$this->entityManager->getFilters()->enable('option_nostock_hidden');
}
if ($request->getMethod() === 'GET') {
$request->query->set('pageno', $request->query->get('pageno', ''));
}
$builder = $this->formFactory->createNamedBuilder('', SearchProductType::class);
if ($request->getMethod() === 'GET') {
$builder->setMethod('GET');
}
$event = new EventArgs(
[
'builder' => $builder,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_INDEX_INITIALIZE);
$searchForm = $builder->getForm();
$searchForm->handleRequest($request);
$searchData = $searchForm->getData();
$qb = $this->productRepository->getQueryBuilderBySearchData($searchData);
$event = new EventArgs(
[
'searchData' => $searchData,
'qb' => $qb,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_INDEX_SEARCH);
$searchData = $event->getArgument('searchData');
$query = $qb->getQuery()
->useResultCache(true, $this->eccubeConfig['eccube_result_cache_lifetime_short']);
$pagination = $paginator->paginate(
$query,
!empty($searchData['pageno']) ? $searchData['pageno'] : 1,
!empty($searchData['disp_number']) ? $searchData['disp_number']->getId() : $this->productListMaxRepository->findOneBy([], ['sort_no' => 'ASC'])->getId()
);
$ids = [];
foreach ($pagination as $Product) {
$ids[] = $Product->getId();
}
$ProductsAndClassCategories = $this->productRepository->findProductsWithSortedClassCategories($ids, 'p.id');
$forms = [];
foreach ($pagination as $Product) {
$builder = $this->formFactory->createNamedBuilder(
'',
AddCartType::class,
null,
[
'product' => $ProductsAndClassCategories[$Product->getId()],
'allow_extra_fields' => true,
]
);
$addCartForm = $builder->getForm();
$forms[$Product->getId()] = $addCartForm->createView();
}
$Category = $searchForm->get('category_id')->getData();
return [
'subtitle' => $this->getPageTitle($searchData),
'pagination' => $pagination,
'search_form' => $searchForm->createView(),
'forms' => $forms,
'Category' => $Category,
];
} */
/**
* 商品詳細画面.
*
* @Route("/products/detail/{id}", name="product_detail", methods={"GET"}, requirements={"id" = "\d+"})
*
* @Template("Product/detail.twig")
*
* @return array
*/
public function detail(Request $request, Product $Product)
{
if ($this->isGranted('ROLE_USER')) {
if (!$this->checkVisibility($Product)) {
throw new NotFoundHttpException();
}
/* $builder = $this->formFactory->createNamedBuilder(
'',
AddCartType::class,
null,
[
'product' => $Product,
'id_add_product_id' => false,
]
); */
$event = new EventArgs(
[
//'builder' => $builder,
'Product' => $Product,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_DETAIL_INITIALIZE);
$Auction = $Product->getAuction();
$Customer = $this->getUser();
if ($Auction->isBefore() && !$Customer->getIsAdmin()) {
throw new NotFoundHttpException();
}
// 下見期間かどうか
$is_preview = $Auction->isPreview();
// 競り後かどうか
$is_closed = $Auction->isClosed();
// 入札社数
if ($is_closed) {
$biddingCompaniesCount = $this->bitHistoryRepository->countBiddingCompanies($Product->getId());
} else {
$biddingCompaniesCount = $this->productRepository->countBiddingCompanies($Product->getId());
}
$is_favorite = $this->customerFavoriteProductRepository->isFavorite($Customer, $Product);
$this->productAccessRepository->addAccess($Product, $Customer);
$prevProduct = $this->productRepository->findPrevProduct($Auction->getId(), $Product->getAuctionNo());
$nextProduct = $this->productRepository->findNextProduct($Auction->getId(), $Product->getAuctionNo());
$isUnpaid = !empty($this->orderRepository->getNotPaidOrder($Customer)) ? true : false;
$randomBytes = random_bytes(32);
$token = hash('sha256', $randomBytes);
$hashedToken = hash('sha256', $token);
$Customer->setToken($hashedToken);
$this->entityManager->persist($Customer);
$this->entityManager->flush();
return [
'title' => $this->title,
'subtitle' => $Product->getName(),
//'form' => $builder->getForm()->createView(),
'Product' => $Product,
'Customer' => $Customer,
'biddingCompaniesCount' => $biddingCompaniesCount,
'is_preview' => $is_preview,
'is_closed' => $is_closed,
'is_favorite' => $is_favorite,
'prevProduct' => $prevProduct,
'nextProduct' => $nextProduct,
'auctionId' => $Auction->getId(),
'isUnpaid' => $isUnpaid,
'token' => $token,
'maxAutoBidLimit' => $this->previewTenderRepository->findMaxAutoBidLimitByProductId($Product->getId(), $Customer->getId()) ?? 0,
];
} else {
// 非会員の場合、ログイン画面を表示
// ログイン後の画面遷移先を設定
$this->setLoginTargetPath($this->generateUrl('product_detail', ['id' => $Product->getId()], UrlGeneratorInterface::ABSOLUTE_URL));
return $this->redirectToRoute('mypage_login');
}
}
/**
* 商品詳細(共有)画面.
*
* @Route("/products/sharing_detail/{id}", name="sharing_product_detail", methods={"GET"}, requirements={"id" = "\d+"})
*
* @Template("Product/sharing_detail.twig")
*
* @return array
*/
public function sharingDetail(Request $request, Product $Product)
{
if ($this->isGranted('ROLE_USER')) {
if (!$this->checkVisibility($Product)) {
throw new NotFoundHttpException();
}
$event = new EventArgs(
[
'Product' => $Product,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_DETAIL_INITIALIZE);
$Auction = $Product->getAuction();
$Customer = $this->getUser();
if ($Auction->isBefore() && !$Customer->getIsAdmin()) {
throw new NotFoundHttpException();
}
// 下見期間かどうか
$is_preview = $Auction->isPreview();
// 競り後かどうか
$is_closed = $Auction->isClosed();
// 入札社数
if ($is_closed) {
$biddingCompaniesCount = $this->bitHistoryRepository->countBiddingCompanies($Product->getId());
} else {
$biddingCompaniesCount = $this->productRepository->countBiddingCompanies($Product->getId());
}
$is_favorite = $this->customerFavoriteProductRepository->isFavorite($Customer, $Product);
$this->productAccessRepository->addAccess($Product, $Customer);
$prevProduct = $this->productRepository->findPrevProduct($Auction->getId(), $Product->getAuctionNo());
$nextProduct = $this->productRepository->findNextProduct($Auction->getId(), $Product->getAuctionNo());
$isUnpaid = !empty($this->orderRepository->getNotPaidOrder($Customer)) ? true : false;
$randomBytes = random_bytes(32);
$token = hash('sha256', $randomBytes);
$hashedToken = hash('sha256', $token);
$Customer->setToken($hashedToken);
$this->entityManager->persist($Customer);
$this->entityManager->flush();
return [
'title' => $this->title,
'subtitle' => $Product->getName(),
'Product' => $Product,
'Customer' => $Customer,
'biddingCompaniesCount' => $biddingCompaniesCount,
'is_preview' => $is_preview,
'is_closed' => $is_closed,
'is_favorite' => $is_favorite,
'prevProduct' => $prevProduct,
'nextProduct' => $nextProduct,
'auctionId' => $Auction->getId(),
'isUnpaid' => $isUnpaid,
'token' => $token,
];
} else {
// 非会員の場合、ログイン画面を表示
return $this->redirectToRoute('mypage_login');
}
}
/**
* お気に入り追加.
*
* @Route("/products/add_favorite/{id}", name="product_add_favorite", requirements={"id" = "\d+"}, methods={"GET", "POST"})
*/
public function addFavorite(Request $request, Product $Product)
{
$this->checkVisibility($Product);
$event = new EventArgs(
[
'Product' => $Product,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_INITIALIZE);
if ($this->isGranted('ROLE_USER')) {
$Customer = $this->getUser();
$this->customerFavoriteProductRepository->addFavorite($Customer, $Product);
$this->session->getFlashBag()->set('product_detail.just_added_favorite', $Product->getId());
$event = new EventArgs(
[
'Product' => $Product,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE);
return $this->redirect($_SERVER['HTTP_REFERER']);
} else {
// 非会員の場合、ログイン画面を表示
// ログイン後の画面遷移先を設定
$this->setLoginTargetPath($this->generateUrl('product_add_favorite', ['id' => $Product->getId()], UrlGeneratorInterface::ABSOLUTE_URL));
$this->session->getFlashBag()->set('eccube.add.favorite', true);
$event = new EventArgs(
[
'Product' => $Product,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE);
return $this->redirectToRoute('mypage_login');
}
}
/**
* お気に入り削除.
*
* @Route("/products/remove_favorite/{id}", name="product_remove_favorite", requirements={"id" = "\d+"}, methods={"GET", "POST"})
*/
public function removeFavorite(Request $request, Product $Product)
{
if ($this->isGranted('ROLE_USER')) {
$Customer = $this->getUser();
$CustomerFavoriteProduct = $this->customerFavoriteProductRepository->findOneBy(['Customer' => $Customer, 'Product' => $Product]);
if ($CustomerFavoriteProduct) {
$this->customerFavoriteProductRepository->delete($CustomerFavoriteProduct);
} else {
throw new BadRequestHttpException();
}
$event = new EventArgs(
[
'Customer' => $Customer,
'CustomerFavoriteProduct' => $CustomerFavoriteProduct,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_FAVORITE_REMOVE_COMPLETE);
return $this->redirect($_SERVER['HTTP_REFERER']);
} else {
// 非会員の場合、ログイン画面を表示
return $this->redirectToRoute('mypage_login');
}
}
/**
* 商品一覧からのお気に入り操作.
*
* @Route("/products/favorite_from_list/{id}", name="product_favorite_from_list", requirements={"id" = "\d+"}, methods={"GET", "POST"})
*/
public function favoriteFromList(Request $request, Product $Product)
{
$this->checkVisibility($Product);
$event = new EventArgs(
[
'Product' => $Product,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_INITIALIZE);
if ($this->isGranted('ROLE_USER')) {
$Customer = $this->getUser();
$CustomerFavoriteProduct = $this->customerFavoriteProductRepository->findOneBy(['Customer' => $Customer, 'Product' => $Product]);
if ($CustomerFavoriteProduct) {
$this->customerFavoriteProductRepository->delete($CustomerFavoriteProduct);
$status = 'not-favorite';
} else {
$this->customerFavoriteProductRepository->addFavorite($Customer, $Product);
$status = 'favorite';
}
$event = new EventArgs(
[
'Product' => $Product,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE);
return $this->json([
'done' => true,
'product_id' => $Product->getId(),
'status' => $status
]);
} else {
// 非会員の場合、ログイン画面を表示
return $this->redirectToRoute('mypage_login');
}
}
/**
* 商品一覧からのメモ登録.
*
* @Route("/products/register_memo_from_list/", name="product_memo_from_list", methods={"POST"})
*/
public function registerMemoFromList(Request $request)
{
if ($this->isGranted('ROLE_USER')) {
$product_id = intval($request->request->get('product_id'));
$customer_id = intval($request->request->get('customer_id'));
$memo = $request->request->get('memo');
$params = [
'Product' => $product_id,
'Customer' => $customer_id,
];
$this->productMemoRepository->register($params, $memo);
return $this->json([
'done' => true,
'product_id' => $product_id,
'memo' => $memo
]);
} else {
// 非会員の場合、ログイン画面を表示
return $this->redirectToRoute('mypage_login');
}
}
/**
* 事前入札画面からのメモ登録.
*
* @Route("/products/register_memo/{id}", name="product_memo", requirements={"id" = "\d+"}, methods={"POST"})
*/
public function registerMemo(Request $request, Product $Product)
{
if ($this->isGranted('ROLE_USER')) {
$product_id = $Product->getId();
$customer_id = $this->getUser()->getId();
$memo = $request->request->get('memo');
$params = [
'Product' => $product_id,
'Customer' => $customer_id,
];
$this->productMemoRepository->register($params, $memo);
return $this->redirect($_SERVER['HTTP_REFERER']);
} else {
// 非会員の場合、ログイン画面を表示
return $this->redirectToRoute('mypage_login');
}
}
/**
* 商品一覧からの事前入札.
*
* @Route("/products/preview_tender_from_list/", name="preview_tender_from_list", methods={"POST"})
*/
public function previewTenderFromList(Request $request)
{
if ($this->isGranted('ROLE_USER')) {
$product_id = intval($request->request->get('preview_tender_product_id'));
$tender_price = intval($request->request->get('tender_price'));
$auto_bid_limit = $request->request->get('auto_bid_limit');
$autoBidLimit = $auto_bid_limit === null || $auto_bid_limit === '' ? null : intval($auto_bid_limit);
$Customer = $this->getUser();
$Product = $this->productRepository->find($product_id);
$Auction = $Product->getAuction();
// 下見期間かどうか
$is_preview = $Auction->isPreview();
if (!$is_preview) {
return $this->json(['done' => false]);
}
$result = $this->previewTenderRepository->registerWithAutoBid($Product, $Customer, $tender_price, $autoBidLimit);
if (!$result['success']) {
return $this->json([
'done' => false,
'message' => $result['message'] ?? null,
'current_price' => $result['current_price'] ?? null,
]);
}
return $this->json([
'done' => true,
'product_id' => $product_id,
'tender_price' => number_format($result['winning_price']),
'winning_price' => $result['winning_price'],
'winner_customer_id' => $result['winner_customer_id'],
]);
} else {
// 非会員の場合、ログイン画面を表示
return $this->redirectToRoute('mypage_login');
}
}
/**
* 事前入札画面からの事前入札.
*
* @Route("/products/preview_tender/{id}", name="preview_tender", requirements={"id" = "\d+"}, methods={"POST"})
*/
public function previewTender(Request $request, Product $Product)
{
if ($this->isGranted('ROLE_USER')) {
$product_id = $Product->getId();
$tender_price = intval($request->request->get('tender_price'));
$auto_bid_limit = $request->request->get('auto_bid_limit');
$autoBidLimit = $auto_bid_limit === null || $auto_bid_limit === '' ? null : intval($auto_bid_limit);
$Customer = $this->getUser();
$Product = $this->productRepository->find($product_id);
$Auction = $Product->getAuction();
// 下見期間かどうか
$is_preview = $Auction->isPreview();
if (!$is_preview) {
return $this->json(['done' => false]);
}
$result = $this->previewTenderRepository->registerWithAutoBid($Product, $Customer, $tender_price, $autoBidLimit);
if (!$result['success']) {
return $this->json(['done' => false, 'message' => $result['message'] ?? null]);
}
return $this->json(['done' => true]);
} else {
// 非会員の場合、ログイン画面を表示
return $this->redirectToRoute('mypage_login');
}
}
/**
* ページタイトルの設定
*
* @param array|null $searchData
* @return string
*/
protected function getPageTitle($searchData)
{
if (isset($searchData['name']) && !empty($searchData['name'])) {
return trans('front.product.search_result');
} elseif (isset($searchData['category_id']) && $searchData['category_id']) {
return $searchData['category_id']->getName();
} else {
return trans('front.product.all_products');
}
}
/**
* 閲覧可能な商品かどうかを判定
*
* @return bool 閲覧可能な場合はtrue
*/
protected function checkVisibility(Product $Product)
{
$is_admin = $this->session->has('_security_admin');
// 管理ユーザの場合はステータスやオプションにかかわらず閲覧可能.
if (!$is_admin) {
// 在庫なし商品の非表示オプションが有効な場合.
// if ($this->BaseInfo->isOptionNostockHidden()) {
// if (!$Product->getStockFind()) {
// return false;
// }
// }
// 公開ステータスでない商品は表示しない.
if ($Product->getStatus()->getId() !== ProductStatus::DISPLAY_SHOW) {
return false;
}
}
return true;
}
/**
* オークション再開時の商品番号を取得
*
* @Route("/auctions/get_restart_product", name="get_restart_product", methods={"GET", "POST"})
*/
public function getRestartProduct(Request $request) {
$productId = $request->request->get('product_id');
$productNumber = $this->productRepository->find($productId)->formatProductNumber();
return $this->json([
'product_number' => $productNumber,
]);
}
}