<?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 Eccube\Controller\AbstractController;
use Eccube\Entity\BaseInfo;
use Eccube\Entity\Master\ProductStatus;
use Eccube\Entity\Product;
use Eccube\Event\EccubeEvents;
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\Repository\OrderRepository;
use Eccube\Repository\ProductRepository;
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;
class MyOrderListController extends AbstractController
{
/**
* @var PurchaseFlow
*/
protected $purchaseFlow;
/**
* @var CustomerFavoriteProductRepository
*/
protected $customerFavoriteProductRepository;
/**
* @var CartService
*/
protected $cartService;
/**
* @var ProductRepository
*/
protected $productRepository;
/**
* @var BaseInfo
*/
protected $BaseInfo;
/**
* @var ProductListMaxRepository
*/
protected $productListMaxRepository;
/**
* @var OrderRepository
*/
protected $orderRepository;
/**
* MyOrderListController constructor.
*
* @param PurchaseFlow $cartPurchaseFlow
* @param CustomerFavoriteProductRepository $customerFavoriteProductRepository
* @param CartService $cartService
* @param ProductRepository $productRepository
* @param BaseInfoRepository $baseInfoRepository
* @param ProductListMaxRepository $productListMaxRepository
* @param OrderRepository $orderRepository
*/
public function __construct(
PurchaseFlow $cartPurchaseFlow,
CustomerFavoriteProductRepository $customerFavoriteProductRepository,
CartService $cartService,
ProductRepository $productRepository,
BaseInfoRepository $baseInfoRepository,
ProductListMaxRepository $productListMaxRepository,
OrderRepository $orderRepository
) {
$this->purchaseFlow = $cartPurchaseFlow;
$this->customerFavoriteProductRepository = $customerFavoriteProductRepository;
$this->cartService = $cartService;
$this->productRepository = $productRepository;
$this->BaseInfo = $baseInfoRepository->get();
$this->productListMaxRepository = $productListMaxRepository;
$this->orderRepository = $orderRepository;
}
/**
* お気に入り商品一覧画面.
*
* @Route("/my_order_list/favorite", name="my_order_list_favorite", methods={"GET"})
* @Template("MyOrderList/favorite.twig")
*/
public function index(Request $request, PaginatorInterface $paginator)
{
if (!$this->BaseInfo->isOptionFavoriteProduct()) {
throw new NotFoundHttpException();
}
if (!$this->isGranted('ROLE_USER')) {
$this->setLoginTargetPath($this->generateUrl('my_order_list_favorite', [], UrlGeneratorInterface::ABSOLUTE_URL));
return $this->redirectToRoute('mypage_login');
}
$Customer = $this->getUser();
// Doctrine SQLFilter
if ($this->BaseInfo->isOptionNostockHidden()) {
$this->entityManager->getFilters()->enable('option_nostock_hidden');
}
// 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('', 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();
$qb = $this->customerFavoriteProductRepository->getQueryBuilderByCustomerWithSearchData($Customer, $searchData);
$event = new EventArgs(
[
'searchData' => $searchData,
'qb' => $qb,
'Customer' => $Customer,
],
$request
);
$this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_MYPAGE_MYPAGE_FAVORITE_SEARCH);
$searchData = $event->getArgument('searchData');
$query = $qb->getQuery();
/** @var SlidingPagination $pagination */
$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(),
['wrap-queries' => true]
);
$ids = [];
foreach ($pagination as $FavoriteProduct) {
$ids[] = $FavoriteProduct->getProduct()->getId();
}
$ProductsAndClassCategories = $this->productRepository->findProductsWithSortedClassCategories($ids, 'p.id');
// 注文回数を計算
$orderCounts = [];
// 前回注文情報を取得
$lastOrders = [];
if (!empty($ids)) {
$qb = $this->entityManager->createQueryBuilder();
$qb->select('p.id as product_id, COUNT(DISTINCT oi.id) as order_count')
->from('Eccube\Entity\OrderItem', 'oi')
->innerJoin('oi.Order', 'o')
->innerJoin('oi.OrderItemType', 'oit')
->innerJoin('oi.Product', 'p')
->where('p.id IN (:product_ids)')
->andWhere('o.Customer = :customer')
->andWhere('o.order_date IS NOT NULL')
->andWhere('o.OrderStatus IN (:orderStatuses)')
->andWhere('oit.id = :productItemType')
->setParameter('product_ids', $ids)
->setParameter('customer', $Customer)
->setParameter('productItemType', \Eccube\Entity\Master\OrderItemType::PRODUCT)
->setParameter('orderStatuses', [
\Eccube\Entity\Master\OrderStatus::NEW,
\Eccube\Entity\Master\OrderStatus::PAID,
\Eccube\Entity\Master\OrderStatus::IN_PROGRESS,
\Eccube\Entity\Master\OrderStatus::DELIVERED,
])
->groupBy('p.id');
$results = $qb->getQuery()->getResult();
foreach ($results as $result) {
$orderCounts[$result['product_id']] = (int)$result['order_count'];
}
// 前回注文情報を取得(各商品の最新の注文)
$qb = $this->entityManager->createQueryBuilder();
$qb->select('p.id as product_id, o.order_date as order_date, oi.quantity as quantity, pc.id as product_class_id, st.name as unit_name, cc1.name as class_category_name1, cc2.name as class_category_name2')
->from('Eccube\Entity\OrderItem', 'oi')
->innerJoin('oi.Order', 'o')
->innerJoin('oi.OrderItemType', 'oit')
->innerJoin('oi.Product', 'p')
->leftJoin('oi.ProductClass', 'pc')
->leftJoin('pc.SaleType', 'st')
->leftJoin('pc.ClassCategory1', 'cc1')
->leftJoin('pc.ClassCategory2', 'cc2')
->where('p.id IN (:product_ids)')
->andWhere('o.Customer = :customer')
->andWhere('o.order_date IS NOT NULL')
->andWhere('o.OrderStatus IN (:orderStatuses)')
->andWhere('oit.id = :productItemType')
->setParameter('product_ids', $ids)
->setParameter('customer', $Customer)
->setParameter('productItemType', \Eccube\Entity\Master\OrderItemType::PRODUCT)
->setParameter('orderStatuses', [
\Eccube\Entity\Master\OrderStatus::NEW,
\Eccube\Entity\Master\OrderStatus::PAID,
\Eccube\Entity\Master\OrderStatus::IN_PROGRESS,
\Eccube\Entity\Master\OrderStatus::DELIVERED,
])
->orderBy('o.order_date', 'DESC');
$lastOrderResults = $qb->getQuery()->getResult();
// 各商品について最新の注文を取得
foreach ($lastOrderResults as $result) {
$productId = $result['product_id'];
if (!isset($lastOrders[$productId])) {
$lastOrders[$productId] = [
'date' => $result['order_date'],
'quantity' => $result['quantity'],
'product_class_id' => $result['product_class_id'],
'unit_name' => $result['unit_name'] ?: '',
'class_category_name1' => $result['class_category_name1'] ?: '1',
'class_category_name2' => $result['class_category_name2'] ?: '1',
];
}
}
}
// addCart form
$forms = [];
foreach ($pagination as $FavoriteProduct) {
$Product = $FavoriteProduct->getProduct();
/* @var $builder \Symfony\Component\Form\FormBuilderInterface */
$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,
'order_counts' => $orderCounts,
'last_orders' => $lastOrders,
];
}
/**
* 注文履歴一覧画面.
*
* @Route("/my_order_list/history", name="my_order_list_history", methods={"GET"})
* @Template("MyOrderList/history.twig")
*/
public function history(Request $request, PaginatorInterface $paginator)
{
if (!$this->isGranted('ROLE_USER')) {
$this->setLoginTargetPath($this->generateUrl('my_order_list_history', [], UrlGeneratorInterface::ABSOLUTE_URL));
return $this->redirectToRoute('mypage_login');
}
$Customer = $this->getUser();
// 購入処理中/決済処理中ステータスの受注を非表示にする
$this->entityManager->getFilters()->enable('incomplete_order_status_hidden');
// SearchProductType で GET パラメータ(stock, price_range, pageno)を取得
if ($request->getMethod() === 'GET') {
$request->query->set('pageno', $request->query->get('pageno', ''));
}
$builder = $this->formFactory->createNamedBuilder('', SearchProductType::class)->setMethod('GET');
$searchForm = $builder->getForm();
$searchForm->handleRequest($request);
$searchData = $searchForm->getData();
$qb = $this->orderRepository->getQueryBuilderByCustomerWithSearchData($Customer, $searchData);
$hasStock = isset($searchData['stock']) && $searchData['stock'];
$hasPriceRange = isset($searchData['price_range']) && !empty($searchData['price_range']) && is_array($searchData['price_range']);
$pageno = max(1, (int) (!empty($searchData['pageno']) ? $searchData['pageno'] : $request->get('pageno', 1)));
$pagination = $paginator->paginate(
$qb,
$pageno,
$this->eccubeConfig['eccube_search_pmax']
);
// 注文×商品ごとに1フォームを用意(同一フォームの二重レンダーを防ぐ)。絞り込み時は条件を満たす OrderItem のみ追加
$orderItemFormsByOrder = [];
$orders = $pagination->getItems();
$productIds = [];
foreach ($orders as $Order) {
foreach ($Order->getProductOrderItems() as $OrderItem) {
$Product = $OrderItem->getProduct();
if (!$Product) {
continue;
}
if ($hasStock || $hasPriceRange) {
if (!$this->orderRepository->productMatchesHistoryFilters($Product, $searchData)) {
continue;
}
}
$productIds[] = $Product->getId();
}
}
$productIds = array_unique($productIds);
$ProductsAndClassCategories = !empty($productIds)
? $this->productRepository->findProductsWithSortedClassCategories($productIds, 'p.id')
: [];
foreach ($orders as $Order) {
$orderItemFormsByOrder[$Order->getId()] = [];
foreach ($Order->getProductOrderItems() as $OrderItem) {
$Product = $OrderItem->getProduct();
if (!$Product || !isset($ProductsAndClassCategories[$Product->getId()])) {
continue;
}
if ($hasStock || $hasPriceRange) {
if (!$this->orderRepository->productMatchesHistoryFilters($Product, $searchData)) {
continue;
}
}
$builder = $this->formFactory->createNamedBuilder(
'',
AddCartType::class,
null,
[
'product' => $ProductsAndClassCategories[$Product->getId()],
'allow_extra_fields' => true,
]
);
$addCartForm = $builder->getForm();
$addCartForm->get('quantity')->setData($OrderItem->getQuantity());
$orderItemFormsByOrder[$Order->getId()][] = [
'orderItem' => $OrderItem,
'form' => $addCartForm->createView(),
];
}
}
return [
'pagination' => $pagination,
'orderItemFormsByOrder' => $orderItemFormsByOrder,
];
}
/**
* ページタイトルの設定
*
* @param array|null $searchData
*
* @return str
*/
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.mypage.nav__favorite');
}
}
}