- <?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;
- 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\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\ParamConverter;
- 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 PurchaseFlow
-      */
-     protected $purchaseFlow;
-     /**
-      * @var CustomerFavoriteProductRepository
-      */
-     protected $customerFavoriteProductRepository;
-     /**
-      * @var CartService
-      */
-     protected $cartService;
-     /**
-      * @var ProductRepository
-      */
-     protected $productRepository;
-     /**
-      * @var BaseInfo
-      */
-     protected $BaseInfo;
-     /**
-      * @var AuthenticationUtils
-      */
-     protected $helper;
-     /**
-      * @var ProductListMaxRepository
-      */
-     protected $productListMaxRepository;
-     private $title = '';
-     /**
-      * ProductController constructor.
-      *
-      * @param PurchaseFlow $cartPurchaseFlow
-      * @param CustomerFavoriteProductRepository $customerFavoriteProductRepository
-      * @param CartService $cartService
-      * @param ProductRepository $productRepository
-      * @param BaseInfoRepository $baseInfoRepository
-      * @param AuthenticationUtils $helper
-      * @param ProductListMaxRepository $productListMaxRepository
-      */
-     public function __construct(
-         PurchaseFlow $cartPurchaseFlow,
-         CustomerFavoriteProductRepository $customerFavoriteProductRepository,
-         CartService $cartService,
-         ProductRepository $productRepository,
-         BaseInfoRepository $baseInfoRepository,
-         AuthenticationUtils $helper,
-         ProductListMaxRepository $productListMaxRepository
-     ) {
-         $this->purchaseFlow = $cartPurchaseFlow;
-         $this->customerFavoriteProductRepository = $customerFavoriteProductRepository;
-         $this->cartService = $cartService;
-         $this->productRepository = $productRepository;
-         $this->BaseInfo = $baseInfoRepository->get();
-         $this->helper = $helper;
-         $this->productListMaxRepository = $productListMaxRepository;
-     }
-     /**
-      * 商品一覧画面.
-      *
-      * @Route("/products/list", name="product_list", methods={"GET"})
-      * @Template("Product/list.twig")
-      */
-     public function index(Request $request, PaginatorInterface $paginator)
-     {
-         // 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->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']->getId() : $this->productListMaxRepository->findOneBy([], ['sort_no' => 'ASC'])->getId()
-         );
-         $ids = [];
-         foreach ($pagination as $Product) {
-             $ids[] = $Product->getId();
-         }
-         $ProductsAndClassCategories = $this->productRepository->findProductsWithSortedClassCategories($ids, 'p.id');
-         // addCart form
-         $forms = [];
-         foreach ($pagination as $Product) {
-             /* @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,
-         ];
-     }
-     /**
-      * 商品詳細画面.
-      *
-      * @Route("/products/detail/{id}", name="product_detail", methods={"GET"}, requirements={"id" = "\d+"})
-      * @Template("Product/detail.twig")
-      * @ParamConverter("Product", options={"repository_method" = "findWithSortedClassCategories"})
-      *
-      * @param Request $request
-      * @param Product $Product
-      *
-      * @return array
-      */
-     public function detail(Request $request, Product $Product)
-     {
-         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);
-         $is_favorite = false;
-         if ($this->isGranted('ROLE_USER')) {
-             $Customer = $this->getUser();
-             $is_favorite = $this->customerFavoriteProductRepository->isFavorite($Customer, $Product);
-         }
-         return [
-             'title' => $this->title,
-             'subtitle' => $Product->getName(),
-             'form' => $builder->getForm()->createView(),
-             'Product' => $Product,
-             'is_favorite' => $is_favorite,
-         ];
-     }
-     /**
-      * お気に入り追加.
-      *
-      * @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->redirectToRoute('product_detail', ['id' => $Product->getId()]);
-         } 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/add_cart/{id}", name="product_add_cart", methods={"POST"}, requirements={"id" = "\d+"})
-      */
-     public function addCart(Request $request, Product $Product)
-     {
-         // エラーメッセージの配列
-         $errorMessages = [];
-         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_CART_ADD_INITIALIZE);
-         /* @var $form \Symfony\Component\Form\FormInterface */
-         $form = $builder->getForm();
-         $form->handleRequest($request);
-         if (!$form->isValid()) {
-             dump($form->getErrors(true));
- //            throw new NotFoundHttpException();
-         }
-         $addCartData = $form->getData();
-         log_info(
-             'カート追加処理開始',
-             [
-                 'product_id' => $Product->getId(),
-                 'product_class_id' => $addCartData['product_class_id'],
-                 'quantity' => $addCartData['quantity'],
-             ]
-         );
-         // カートへ追加
-         $this->cartService->addProduct($addCartData['product_class_id'], $addCartData['quantity']);
-         // 明細の正規化
-         $Carts = $this->cartService->getCarts();
-         foreach ($Carts as $Cart) {
-             $result = $this->purchaseFlow->validate($Cart, new PurchaseContext($Cart, $this->getUser()));
-             // 復旧不可のエラーが発生した場合は追加した明細を削除.
-             if ($result->hasError()) {
-                 $this->cartService->removeProduct($addCartData['product_class_id']);
-                 foreach ($result->getErrors() as $error) {
-                     $errorMessages[] = $error->getMessage();
-                 }
-             }
-             foreach ($result->getWarning() as $warning) {
-                 $errorMessages[] = $warning->getMessage();
-             }
-         }
-         $this->cartService->save();
-         log_info(
-             'カート追加処理完了',
-             [
-                 'product_id' => $Product->getId(),
-                 'product_class_id' => $addCartData['product_class_id'],
-                 'quantity' => $addCartData['quantity'],
-             ]
-         );
-         $event = new EventArgs(
-             [
-                 'form' => $form,
-                 'Product' => $Product,
-             ],
-             $request
-         );
-         $this->eventDispatcher->dispatch($event, EccubeEvents::FRONT_PRODUCT_CART_ADD_COMPLETE);
-         if ($event->getResponse() !== null) {
-             return $event->getResponse();
-         }
-         if ($request->isXmlHttpRequest()) {
-             // ajaxでのリクエストの場合は結果をjson形式で返す。
-             // 初期化
-             $messages = [];
-             if (empty($errorMessages)) {
-                 // エラーが発生していない場合
-                 $done = true;
-                 array_push($messages, trans('front.product.add_cart_complete'));
-             } else {
-                 // エラーが発生している場合
-                 $done = false;
-                 $messages = $errorMessages;
-             }
-             return $this->json(['done' => $done, 'messages' => $messages]);
-         } else {
-             // ajax以外でのリクエストの場合はカート画面へリダイレクト
-             foreach ($errorMessages as $errorMessage) {
-                 $this->addRequestError($errorMessage);
-             }
-             return $this->redirectToRoute('cart');
-         }
-     }
-     /**
-      * ページタイトルの設定
-      *
-      * @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.product.all_products');
-         }
-     }
-     /**
-      * 閲覧可能な商品かどうかを判定
-      *
-      * @param Product $Product
-      *
-      * @return boolean 閲覧可能な場合は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;
-     }
- }
-