<?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 Eccube\Controller\Mypage; 
 
use Eccube\Controller\AbstractController; 
use Eccube\Entity\BaseInfo; 
use Eccube\Entity\Customer; 
use Eccube\Entity\Order; 
use Eccube\Entity\Product; 
use Eccube\Event\EccubeEvents; 
use Eccube\Event\EventArgs; 
use Eccube\Exception\CartException; 
use Eccube\Form\Type\Front\CustomerLoginType; 
use Eccube\Repository\BaseInfoRepository; 
use Eccube\Repository\CustomerFavoriteProductRepository; 
use Eccube\Repository\OrderRepository; 
use Eccube\Repository\ProductRepository; 
use Eccube\Service\CartService; 
use Eccube\Service\PurchaseFlow\PurchaseContext; 
use Eccube\Service\PurchaseFlow\PurchaseFlow; 
use Knp\Component\Pager\PaginatorInterface; 
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; 
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\Security\Http\Authentication\AuthenticationUtils; 
 
class MypageController extends AbstractController 
{ 
    /** 
     * @var ProductRepository 
     */ 
    protected $productRepository; 
 
    /** 
     * @var CustomerFavoriteProductRepository 
     */ 
    protected $customerFavoriteProductRepository; 
 
    /** 
     * @var BaseInfo 
     */ 
    protected $BaseInfo; 
 
    /** 
     * @var CartService 
     */ 
    protected $cartService; 
 
    /** 
     * @var OrderRepository 
     */ 
    protected $orderRepository; 
 
    /** 
     * @var PurchaseFlow 
     */ 
    protected $purchaseFlow; 
 
    /** 
     * MypageController constructor. 
     * 
     * @param OrderRepository $orderRepository 
     * @param CustomerFavoriteProductRepository $customerFavoriteProductRepository 
     * @param CartService $cartService 
     * @param BaseInfoRepository $baseInfoRepository 
     * @param PurchaseFlow $purchaseFlow 
     */ 
    public function __construct( 
        OrderRepository $orderRepository, 
        CustomerFavoriteProductRepository $customerFavoriteProductRepository, 
        CartService $cartService, 
        BaseInfoRepository $baseInfoRepository, 
        PurchaseFlow $purchaseFlow 
    ) { 
        $this->orderRepository = $orderRepository; 
        $this->customerFavoriteProductRepository = $customerFavoriteProductRepository; 
        $this->BaseInfo = $baseInfoRepository->get(); 
        $this->cartService = $cartService; 
        $this->purchaseFlow = $purchaseFlow; 
    } 
 
    /** 
     * ログイン画面. 
     * 
     * @Route("/mypage/login", name="mypage_login", methods={"GET", "POST"}) 
     * @Template("Mypage/login.twig") 
     */ 
    public function login(Request $request, AuthenticationUtils $utils) 
    { 
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) { 
            log_info('認証済のためログイン処理をスキップ'); 
 
            return $this->redirectToRoute('mypage'); 
        } 
 
        /* @var $form \Symfony\Component\Form\FormInterface */ 
        $builder = $this->formFactory 
            ->createNamedBuilder('', CustomerLoginType::class); 
 
        $builder->get('login_memory')->setData((bool) $request->getSession()->get('_security.login_memory')); 
 
        if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
            $Customer = $this->getUser(); 
            if ($Customer instanceof Customer) { 
                $builder->get('login_email') 
                    ->setData($Customer->getEmail()); 
            } 
        } 
 
        $event = new EventArgs( 
            [ 
                'builder' => $builder, 
            ], 
            $request 
        ); 
        $this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_MYPAGE_MYPAGE_LOGIN_INITIALIZE); 
 
        $form = $builder->getForm(); 
 
        return [ 
            'error' => $utils->getLastAuthenticationError(), 
            'form' => $form->createView(), 
        ]; 
    } 
 
    /** 
     * マイページ. 
     * 
     * @Route("/mypage/", name="mypage", methods={"GET"}) 
     * @Template("Mypage/index.twig") 
     */ 
    public function index(Request $request, PaginatorInterface $paginator) 
    { 
        $Customer = $this->getUser(); 
 
        // 購入処理中/決済処理中ステータスの受注を非表示にする. 
        $this->entityManager 
            ->getFilters() 
            ->enable('incomplete_order_status_hidden'); 
 
        // paginator 
        $qb = $this->orderRepository->getQueryBuilderByCustomer($Customer); 
 
        $event = new EventArgs( 
            [ 
                'qb' => $qb, 
                'Customer' => $Customer, 
            ], 
            $request 
        ); 
        $this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_MYPAGE_MYPAGE_INDEX_SEARCH); 
 
        $pagination = $paginator->paginate( 
            $qb, 
            $request->get('pageno', 1), 
            $this->eccubeConfig['eccube_search_pmax'] 
        ); 
 
        return [ 
            'pagination' => $pagination, 
        ]; 
    } 
 
    /** 
     * 購入履歴詳細を表示する. 
     * 
     * @Route("/mypage/history/{order_no}", name="mypage_history", methods={"GET"}) 
     * @Template("Mypage/history.twig") 
     */ 
    public function history(Request $request, $order_no) 
    { 
        $this->entityManager->getFilters() 
            ->enable('incomplete_order_status_hidden'); 
        $Order = $this->orderRepository->findOneBy( 
            [ 
                'order_no' => $order_no, 
                'Customer' => $this->getUser(), 
            ] 
        ); 
 
        $event = new EventArgs( 
            [ 
                'Order' => $Order, 
            ], 
            $request 
        ); 
        $this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_MYPAGE_MYPAGE_HISTORY_INITIALIZE); 
 
        /** @var Order $Order */ 
        $Order = $event->getArgument('Order'); 
 
        if (!$Order) { 
            throw new NotFoundHttpException(); 
        } 
 
        $stockOrder = true; 
        foreach ($Order->getOrderItems() as $orderItem) { 
            if ($orderItem->isProduct() && $orderItem->getQuantity() < 0) { 
                $stockOrder = false; 
                break; 
            } 
        } 
 
        return [ 
            'Order' => $Order, 
            'stockOrder' => $stockOrder, 
        ]; 
    } 
 
    /** 
     * 再購入を行う. 
     * 
     * @Route("/mypage/order/{order_no}", name="mypage_order", methods={"PUT"}) 
     */ 
    public function order(Request $request, $order_no) 
    { 
        $this->isTokenValid(); 
 
        log_info('再注文開始', [$order_no]); 
 
        $Customer = $this->getUser(); 
 
        /* @var $Order \Eccube\Entity\Order */ 
        $Order = $this->orderRepository->findOneBy( 
            [ 
                'order_no' => $order_no, 
                'Customer' => $Customer, 
            ] 
        ); 
 
        $event = new EventArgs( 
            [ 
                'Order' => $Order, 
                'Customer' => $Customer, 
            ], 
            $request 
        ); 
        $this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_MYPAGE_MYPAGE_ORDER_INITIALIZE); 
 
        if (!$Order) { 
            log_info('対象の注文が見つかりません', [$order_no]); 
            throw new NotFoundHttpException(); 
        } 
 
        // エラーメッセージの配列 
        $errorMessages = []; 
 
        foreach ($Order->getOrderItems() as $OrderItem) { 
            try { 
                if ($OrderItem->getProduct() && $OrderItem->getProductClass()) { 
                    $this->cartService->addProduct($OrderItem->getProductClass(), $OrderItem->getQuantity()); 
 
                    // 明細の正規化 
                    $Carts = $this->cartService->getCarts(); 
                    foreach ($Carts as $Cart) { 
                        $result = $this->purchaseFlow->validate($Cart, new PurchaseContext($Cart, $this->getUser())); 
                        // 復旧不可のエラーが発生した場合は追加した明細を削除. 
                        if ($result->hasError()) { 
                            $this->cartService->removeProduct($OrderItem->getProductClass()); 
                            foreach ($result->getErrors() as $error) { 
                                $errorMessages[] = $error->getMessage(); 
                            } 
                        } 
                        foreach ($result->getWarning() as $warning) { 
                            $errorMessages[] = $warning->getMessage(); 
                        } 
                    } 
 
                    $this->cartService->save(); 
                } 
            } catch (CartException $e) { 
                log_info($e->getMessage(), [$order_no]); 
                $this->addRequestError($e->getMessage()); 
            } 
        } 
 
        foreach ($errorMessages as $errorMessage) { 
            $this->addRequestError($errorMessage); 
        } 
 
        $event = new EventArgs( 
            [ 
                'Order' => $Order, 
                'Customer' => $Customer, 
            ], 
            $request 
        ); 
        $this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_MYPAGE_MYPAGE_ORDER_COMPLETE); 
 
        if ($event->getResponse() !== null) { 
            return $event->getResponse(); 
        } 
 
        log_info('再注文完了', [$order_no]); 
 
        return $this->redirect($this->generateUrl('cart')); 
    } 
 
    /** 
     * お気に入り商品を表示する. 
     * 
     * @Route("/mypage/favorite", name="mypage_favorite", methods={"GET"}) 
     * @Template("Mypage/favorite.twig") 
     */ 
    public function favorite(Request $request, PaginatorInterface $paginator) 
    { 
        if (!$this->BaseInfo->isOptionFavoriteProduct()) { 
            throw new NotFoundHttpException(); 
        } 
        $Customer = $this->getUser(); 
 
        // paginator 
        $qb = $this->customerFavoriteProductRepository->getQueryBuilderByCustomer($Customer); 
 
        $event = new EventArgs( 
            [ 
                'qb' => $qb, 
                'Customer' => $Customer, 
            ], 
            $request 
        ); 
        $this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_MYPAGE_MYPAGE_FAVORITE_SEARCH); 
 
        $pagination = $paginator->paginate( 
            $qb, 
            $request->get('pageno', 1), 
            $this->eccubeConfig['eccube_search_pmax'], 
            ['wrap-queries' => true] 
        ); 
 
        return [ 
            'pagination' => $pagination, 
        ]; 
    } 
 
    /** 
     * お気に入り商品を削除する. 
     * 
     * @Route("/mypage/favorite/{id}/delete", name="mypage_favorite_delete", methods={"DELETE"}, requirements={"id" = "\d+"}) 
     */ 
    public function delete(Request $request, Product $Product) 
    { 
        $this->isTokenValid(); 
 
        $Customer = $this->getUser(); 
 
        log_info('お気に入り商品削除開始', [$Customer->getId(), $Product->getId()]); 
 
        $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_MYPAGE_MYPAGE_DELETE_COMPLETE); 
 
        log_info('お気に入り商品削除完了', [$Customer->getId(), $CustomerFavoriteProduct->getId()]); 
 
        return $this->redirect($this->generateUrl('mypage_favorite')); 
    } 
}