<?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\Entity\Auction;
use Customize\Entity\Master\AuctionStatus;
use Customize\Event\EccubeEvents;
use Customize\Form\Type\SearchAuctionType;
use Customize\Form\Type\SearchProductType;
use Customize\Repository\AuctionRepository;
use Customize\Repository\BitHistoryRepository;
use Customize\Repository\CustomerFavoriteAuctionRepository;
use Customize\Repository\CustomerFavoriteProductRepository;
use Customize\Repository\ProductRepository;
use Customize\Repository\OrderRepository;
use Eccube\Controller\AbstractController;
use Eccube\Event\EventArgs;
use Eccube\Repository\Master\ProductListMaxRepository;
use Knp\Bundle\PaginatorBundle\Pagination\SlidingPagination;
use Knp\Component\Pager\PaginatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class AuctionController extends AbstractController
{
/**
* @var AuctionRepository
*/
protected $auctionRepository;
/**
* @var BitHistoryRepository
*/
protected $bitHistoryRepository;
/**
* @var CustomerFavoriteAuctionRepository
*/
protected $customerFavoriteAuctionRepository;
/**
* @var CustomerFavoriteProductRepository
*/
protected $customerFavoriteProductRepository;
/**
* @var ProductRepository
*/
protected $productRepository;
/**
* @var ProductListMaxRepository
*/
protected $productListMaxRepository;
/**
* @var OrderRepository
*/
protected $orderRepository;
private $title = '';
/**
* AuctionController constructor.
*/
public function __construct(
AuctionRepository $auctionRepository,
BitHistoryRepository $bitHistoryRepository,
CustomerFavoriteAuctionRepository $customerFavoriteAuctionRepository,
CustomerFavoriteProductRepository $customerFavoriteProductRepository,
ProductRepository $productRepository,
ProductListMaxRepository $productListMaxRepository,
OrderRepository $orderRepository,
) {
$this->auctionRepository = $auctionRepository;
$this->bitHistoryRepository = $bitHistoryRepository;
$this->customerFavoriteAuctionRepository = $customerFavoriteAuctionRepository;
$this->customerFavoriteProductRepository = $customerFavoriteProductRepository;
$this->productRepository = $productRepository;
$this->productListMaxRepository = $productListMaxRepository;
$this->orderRepository = $orderRepository;
}
/**
* オークション一覧画面.
*
* @Route("/auctions/list", name="auction_list", methods={"GET"})
*
* @Template("Auction/list.twig")
*/
public function index(Request $request, PaginatorInterface $paginator)
{
if ($this->isGranted('ROLE_USER')) {
// handleRequestは空のqueryの場合は無視するため
if ($request->getMethod() === 'GET') {
$request->query->set('pageno', $request->query->get('pageno', ''));
}
// searchForm
/* @var $builder \Symfony\Component\Form\FormBuilderInterface */
$builder = $this->formFactory->createNamedBuilder('', SearchAuctionType::class);
if ($request->getMethod() === 'GET') {
$builder->setMethod('GET');
}
$event = new EventArgs(
[
'builder' => $builder,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_AUCTION_INDEX_INITIALIZE);
/* @var $searchForm \Symfony\Component\Form\FormInterface */
$searchForm = $builder->getForm();
$searchForm->handleRequest($request);
// paginator
$searchData = $searchForm->getData();
$qb = $this->auctionRepository->getQueryBuilderBySearchData($searchData);
$event = new EventArgs(
[
'searchData' => $searchData,
'qb' => $qb,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_AUCTION_INDEX_SEARCH);
$searchData = $event->getArgument('searchData');
$query = $qb->getQuery()
->useResultCache(true, $this->eccubeConfig['eccube_result_cache_lifetime_short']);
/** @var SlidingPagination $pagination */
$pagination = $paginator->paginate(
$query,
! empty($searchData['pageno']) ? $searchData['pageno'] : 1,
! empty($searchData['disp_number']) ? $searchData['disp_number'] : 20
);
$Customer = $this->getUser();
return [
'subtitle' => 'オークション一覧',
'pagination' => $pagination,
'search_form' => $searchForm->createView(),
'Customer' => $Customer,
];
} else {
// 非会員の場合、ログイン画面を表示
return $this->redirectToRoute('mypage_login');
}
}
/**
* オークション詳細画面.
*
* @Route("/auctions/detail/{id}", name="auction_detail", methods={"GET"}, requirements={"id" = "\d+"})
*
* @Template("Auction/detail.twig")
*
* @return array
*/
public function detail(Request $request, Auction $Auction, PaginatorInterface $paginator)
{
if ($this->isGranted('ROLE_USER')) {
$Customer = $this->getUser();
if (! $this->checkVisibility($Auction)) {
throw new NotFoundHttpException();
}
if ($Auction->isBefore() && !$Customer->getIsAdmin()) {
throw new NotFoundHttpException();
}
// handleRequestは空のqueryの場合は無視するため
if ($request->getMethod() === 'GET') {
$request->query->set('pageno', $request->query->get('pageno', ''));
$request->query->set('orderby', $request->query->get('orderby', 3));
}
// searchForm
/* @var $builder \Symfony\Component\Form\FormBuilderInterface */
$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);
/* @var $searchForm \Symfony\Component\Form\FormInterface */
$searchForm = $builder->getForm();
$searchForm->handleRequest($request);
// paginator
$searchData = $searchForm->getData();
$searchData['auction_id'] = $Auction->getId();
$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']);
/** @var SlidingPagination $pagination */
$pagination = $paginator->paginate(
$query,
! empty($searchData['pageno']) ? $searchData['pageno'] : 1,
! empty($searchData['disp_number']) ? $searchData['disp_number'] : 20
);
// 下見期間かどうか
$is_preview = $Auction->isPreview();
// 競り後かどうか
$is_closed = $Auction->isClosed();
// 訂正リストの有無
$has_correction_list = ! empty($Auction->getCorrectionListProducts());
$Products = $this->productRepository->getTotalProductsForAuction($Auction->getId());
$biddingCompaniesCounts = [];
$productIds = array_map(function ($Product) {
return $Product->getId();
}, $Products);
if ($is_closed) {
$biddingCompaniesResults = $this->bitHistoryRepository->countBiddingCompaniesForProducts($productIds);
} else {
$biddingCompaniesResults = $this->productRepository->countBiddingCompaniesForProducts($productIds);
}
foreach ($biddingCompaniesResults as $result) {
$biddingCompaniesCounts[$result['productId']] = $result['count'];
}
foreach ($pagination as $Product) {
// もし結果が存在しない場合は 0 をセット
$biddingCompaniesCounts[$Product->getId()] = $biddingCompaniesCounts[$Product->getId()] ?? 0;
}
$isUnpaid = !empty($this->orderRepository->getNotPaidOrder($Customer)) ? true : false;
return [
'title' => $this->title,
'subtitle' => $Auction->getName(),
'Auction' => $Auction,
'auctionId' => $Auction->getId(),
'pagination' => $pagination,
'search_form' => $searchForm->createView(),
'Customer' => $Customer,
'is_preview' => $is_preview,
'is_closed' => $is_closed,
'has_correction_list' => $has_correction_list,
'biddingCompaniesCounts' => $biddingCompaniesCounts,
'isUnpaid' => $isUnpaid
];
} else {
// 非会員の場合、ログイン画面を表示
// ログイン後の画面遷移先を設定
$this->setLoginTargetPath($this->generateUrl('auction_detail', ['id' => $Auction->getId()], UrlGeneratorInterface::ABSOLUTE_URL));
return $this->redirectToRoute('mypage_login');
}
}
/**
* 競り中画面.
*
* @Route("/starting_auctions/detail/{id}", name="starting_auction_detail", methods={"GET"}, requirements={"id" = "\d+"})
*
* @Template("Product/starting_detail.twig")
*
* @return array
*/
public function startingDetail(Request $request, Auction $Auction)
{
if ($this->isGranted('ROLE_USER')) {
if (! $this->checkVisibility($Auction)) {
throw new NotFoundHttpException();
}
$Customer = $this->getUser();
$Products = $this->productRepository->getProductsSortedByAuctionNo($Auction->getId());
$ProductsCount = count($this->productRepository->getTotalProductsForAuction($Auction->getId()));
$firstProductId = !empty($Products) ? $Products[0]['id'] : 0;
$nextProductImages = [];
$auctionNos = array_map(function ($Product) {
return $Product->getAuctionNo();
}, $Products);
if (!empty($auctionNos)) {
$minAuctionNo = min($auctionNos);
$nextProducts = $this->productRepository->findNextProducts($Auction->getId(), $minAuctionNo);
foreach ($Products as $Product) {
$filteredProducts = array_filter($nextProducts, function($nextProduct) use ($Product) {
return $nextProduct->getAuctionNo() > $Product->getAuctionNo();
});
// 2件だけ取得
$nextProductImages[$Product->getId()] = array_slice($filteredProducts, 0, 2);
}
};
$productIds = array_map(function ($Product) {
return $Product->getId();
}, $Products);
$biddingCompaniesCounts = [];
$biddingCompaniesResults = $this->productRepository->countBiddingCompaniesForProducts($productIds);
foreach ($biddingCompaniesResults as $result) {
$biddingCompaniesCounts[$result['productId']] = $result['count'];
}
$isFavorites = [];
$favorites = $this->customerFavoriteProductRepository->getFavoritesForCustomer($Customer, $productIds);
foreach ($Products as $Product) {
$isFavorites[$Product->getId()] = in_array($Product->getId(), $favorites);
}
$startPrices = [];
$startPricesResults = $this->productRepository->getStartPrices($productIds);
foreach ($startPricesResults as $result) {
$startPrices[$result['productId']] = number_format($result['startPrice']);
}
$limitPrices = [];
$settingPersents = [];
$canBids = [];
$isOwns = [];
foreach ($Products as $Product) {
$limitPrices[$Product->getId()] = $Product->getLimitPrice();
$settingPersents[$Product->getId()] = $Product->getSettingPersent();
$canBids[$Product->getId()] = $Product->getTenderPrice($Customer) != 0 && $Product->getNowPrice() == $Product->getTenderPrice($Customer) ? false : true;
$isOwns[$Product->getId()] = $Product->getCustomer() == $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();
$socketHostUrl = getenv('SOCKET_HOST_URL');
$isUnpaid = !empty($this->orderRepository->getNotPaidOrder($Customer)) ? true : false;
// 競り後かどうか
$is_closed = $Auction->isClosed();
return [
'title' => $this->title,
'Auction' => $Auction,
'Products' => $Products,
'limitPrices' => json_encode($limitPrices),
'settingPersents' => json_encode($settingPersents),
'nextProductImages' => $nextProductImages,
'token' => $token,
'Customer' => $Customer,
'isFavorites' => $isFavorites,
'biddingCompaniesCounts' => $biddingCompaniesCounts,
'canBids' => json_encode($canBids),
'isOwns' => json_encode($isOwns),
'startPrices' => json_encode($startPrices),
'socketHostUrl' => $socketHostUrl,
'ProductsCount' => $ProductsCount,
'isUnpaid' => $isUnpaid,
'is_closed' => $is_closed,
'firstProductId' => $firstProductId
];
} else {
// 非会員の場合、ログイン画面を表示
return $this->redirectToRoute('mypage_login');
}
}
/**
* お気に入り追加.
*
* @Route("/auctions/add_favorite/{id}", name="auction_add_favorite", requirements={"id" = "\d+"}, methods={"GET", "POST"})
*/
public function addFavorite(Request $request, Auction $Auction)
{
$this->checkVisibility($Auction);
$event = new EventArgs(
[
'Auction' => $Auction,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_AUCTION_FAVORITE_ADD_INITIALIZE);
if ($this->isGranted('ROLE_USER')) {
$Customer = $this->getUser();
$this->customerFavoriteAuctionRepository->addFavorite($Customer, $Auction);
$this->session->getFlashBag()->set('auction_detail.just_added_favorite', $Auction->getId());
$event = new EventArgs(
[
'Auction' => $Auction,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_AUCTION_FAVORITE_ADD_COMPLETE);
return $this->redirect($_SERVER['HTTP_REFERER']);
} else {
// 非会員の場合、ログイン画面を表示
// ログイン後の画面遷移先を設定
$this->setLoginTargetPath($_SERVER['HTTP_REFERER']);
$this->session->getFlashBag()->set('eccube.add.favorite', true);
$event = new EventArgs(
[
'Auction' => $Auction,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_AUCTION_FAVORITE_ADD_COMPLETE);
return $this->redirectToRoute('mypage_login');
}
}
/**
* お気に入り削除.
*
* @Route("/auctions/remove_favorite/{id}", name="auction_remove_favorite", requirements={"id" = "\d+"}, methods={"GET", "POST"})
*/
public function removeFavorite(Request $request, Auction $Auction)
{
if ($this->isGranted('ROLE_USER')) {
$Customer = $this->getUser();
$CustomerFavoriteAuction = $this->customerFavoriteAuctionRepository->findOneBy(['Customer' => $Customer, 'Auction' => $Auction]);
if ($CustomerFavoriteAuction) {
$this->customerFavoriteAuctionRepository->delete($CustomerFavoriteAuction);
} else {
throw new BadRequestHttpException();
}
$event = new EventArgs(
[
'Customer' => $Customer,
'CustomerFavoriteAuction' => $CustomerFavoriteAuction,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_AUCTION_FAVORITE_REMOVE_COMPLETE);
return $this->redirect($_SERVER['HTTP_REFERER']);
} else {
// 非会員の場合、ログイン画面を表示
return $this->redirectToRoute('mypage_login');
}
}
/**
* オークションのstart_date/end_dateを登録
*
* @Route("/auctions/register_date/{id}", name="register_date", requirements={"id" = "\d+"}, methods={"GET", "POST"})
*/
public function registerDate(Request $request, Auction $Auction) {
if ($request->request->get('type') == 'start') {
$Auction->setStartDate(new \DateTime());
} else {
$Auction->setEndDate(new \DateTime());
}
$this->entityManager->flush();
return $this->json(['done' => true]);
}
/**
* 開催中のオークションを取得
*
* @Route("/auctions/start_auction_list", name="start_auction_list", methods={"GET", "POST"})
*/
public function startAuctionList(Request $request) {
$startAuction = $this->auctionRepository->getStartAuction();
return $this->json(json_encode($startAuction));
}
protected function getPageTitle($searchData)
{
if (isset($searchData['name']) && ! empty($searchData['name'])) {
return trans('front.auction.search_result');
} elseif (isset($searchData['category_id']) && $searchData['category_id']) {
return $searchData['category_id']->getName();
} else {
return trans('front.auction.all_auctions');
}
}
/**
* 閲覧可能なオークションかどうかを判定
*
*
* @return bool 閲覧可能な場合はtrue
*/
protected function checkVisibility(Auction $Auction)
{
$is_admin = $this->session->has('_security_admin');
// 管理ユーザの場合はステータスやオプションにかかわらず閲覧可能.
if (! $is_admin) {
// 公開ステータスでない商品は表示しない.
if ($Auction->getStatus()->getId() !== AuctionStatus::DISPLAY_SHOW) {
return false;
}
}
return true;
}
}