src/Eccube/Controller/ProductController.php line 603

Open in your IDE?
  1. <?php
  2. namespace Eccube\Controller;
  3. use Eccube\Controller\AbstractController;
  4. use Eccube\Entity\BaseInfo;
  5. use Eccube\Entity\Master\ProductStatus;
  6. use Eccube\Entity\Product;
  7. use Eccube\Event\EccubeEvents;
  8. use Eccube\Event\EventArgs;
  9. use Eccube\Form\Type\AddCartType;
  10. use Eccube\Form\Type\SearchProductType;
  11. use Eccube\Repository\BaseInfoRepository;
  12. use Eccube\Repository\CustomerFavoriteProductRepository;
  13. use Eccube\Repository\Master\ProductListMaxRepository;
  14. use Eccube\Repository\ProductRepository;
  15. use Eccube\Repository\CategoryRepository;
  16. use Eccube\Service\CartService;
  17. use Eccube\Service\PurchaseFlow\PurchaseContext;
  18. use Eccube\Service\PurchaseFlow\PurchaseFlow;
  19. use Knp\Bundle\PaginatorBundle\Pagination\SlidingPagination;
  20. use Knp\Component\Pager\PaginatorInterface;
  21. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  22. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  23. use Symfony\Component\HttpFoundation\Request;
  24. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  25. use Symfony\Component\Routing\Annotation\Route;
  26. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  27. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  28. use Plugin\ProductPlus42\Repository\ProductDataDetailRepository;
  29. use Plugin\CustomerRank42\Repository\CustomerPriceRepository;
  30. use Plugin\PiaProductRestock\Repository\ProductRestockRepository;
  31. use Plugin\PiaProductRestock\Repository\ProductRestockCustomerRepository;
  32. class ProductController extends AbstractController
  33. {
  34.   /**
  35.    * @var PurchaseFlow
  36.    */
  37.   protected $purchaseFlow;
  38.   /**
  39.    * @var CustomerFavoriteProductRepository
  40.    */
  41.   protected $customerFavoriteProductRepository;
  42.   /**
  43.    * @var CartService
  44.    */
  45.   protected $cartService;
  46.   /**
  47.    * @var ProductRepository
  48.    */
  49.   protected $productRepository;
  50.   /**
  51.    * @var CategoryRepository
  52.    */
  53.   protected $categoryRepository;
  54.   /**
  55.    * @var BaseInfo
  56.    */
  57.   protected $BaseInfo;
  58.   /**
  59.    * @var AuthenticationUtils
  60.    */
  61.   protected $helper;
  62.   /**
  63.    * @var ProductListMaxRepository
  64.    */
  65.   protected $productListMaxRepository;
  66.   private $title '';
  67.   /**
  68.    * @var ProductDataDetailRepository
  69.    */
  70.   protected $productDataDetailRepository;
  71.   /**
  72.    * @var CustomerPriceRepository
  73.    */
  74.   protected $customerPriceRepository;
  75.   /**
  76.    * @var ProductRestockRepository
  77.    */
  78.   protected $productRestockRepository;
  79.   /**
  80.    * @var ProductRestockCustomerRepository
  81.    */
  82.   protected $productRestockCustomerRepository;
  83.   /**
  84.    * ProductController constructor.
  85.    *
  86.    * @param PurchaseFlow $cartPurchaseFlow
  87.    * @param CustomerFavoriteProductRepository $customerFavoriteProductRepository
  88.    * @param CartService $cartService
  89.    * @param ProductRepository $productRepository
  90.    * @param CategoryRepository $categoryRepository
  91.    * @param BaseInfoRepository $baseInfoRepository
  92.    * @param AuthenticationUtils $helper
  93.    * @param ProductListMaxRepository $productListMaxRepository
  94.    * @param ProductDataDetailRepository $ProductDataDetailRepository
  95.    * @param CustomerPriceRepository $customerPriceRepository
  96.    * @param ProductRestockRepository $productRestockRepository
  97.    * @param ProductRestockCustomerRepository $productRestockCustomerRepository
  98.    */
  99.   public function __construct(
  100.     PurchaseFlow                      $cartPurchaseFlow,
  101.     CustomerFavoriteProductRepository $customerFavoriteProductRepository,
  102.     CartService                       $cartService,
  103.     ProductRepository                 $productRepository,
  104.     CategoryRepository $categoryRepository,
  105.     BaseInfoRepository                $baseInfoRepository,
  106.     AuthenticationUtils               $helper,
  107.     ProductListMaxRepository          $productListMaxRepository,
  108.     ProductDataDetailRepository       $ProductDataDetailRepository,
  109.     CustomerPriceRepository $customerPriceRepository,
  110.     ProductRestockRepository $productRestockRepository,
  111.     ProductRestockCustomerRepository $productRestockCustomerRepository
  112.   )
  113.   {
  114.     $this->purchaseFlow $cartPurchaseFlow;
  115.     $this->customerFavoriteProductRepository $customerFavoriteProductRepository;
  116.     $this->cartService $cartService;
  117.     $this->productRepository $productRepository;
  118.     $this->categoryRepository $categoryRepository;
  119.     $this->BaseInfo $baseInfoRepository->get();
  120.     $this->helper $helper;
  121.     $this->productListMaxRepository $productListMaxRepository;
  122.     $this->productDataDetailRepository $ProductDataDetailRepository;
  123.     $this->customerPriceRepository $customerPriceRepository;
  124.     $this->productRestockRepository $productRestockRepository;
  125.     $this->productRestockCustomerRepository $productRestockCustomerRepository;
  126.   }
  127.   /**
  128.    * 商品一覧画面.
  129.    *
  130.    * @Route("/products/list", name="product_list", methods={"GET"})
  131.    * @Template("Product/list.twig")
  132.    */
  133.   public function index(Request $requestPaginatorInterface $paginator)
  134.   {
  135.     $this->session->set('header_footer_layout'"palace");
  136.     // Doctrine SQLFilter
  137.     if ($this->BaseInfo->isOptionNostockHidden()) {
  138.       $this->entityManager->getFilters()->enable('option_nostock_hidden');
  139.     }
  140.     // handleRequestは空のqueryの場合は無視するため
  141.     if ($request->getMethod() === 'GET') {
  142.       $request->query->set('pageno'$request->query->get('pageno'''));
  143.     }
  144.     // searchForm
  145.     /* @var $builder \Symfony\Component\Form\FormBuilderInterface */
  146.     $builder $this->formFactory->createNamedBuilder(''SearchProductType::class);
  147.     if ($request->getMethod() === 'GET') {
  148.       $builder->setMethod('GET');
  149.     }
  150.     $event = new EventArgs(
  151.       [
  152.         'builder' => $builder,
  153.       ],
  154.       $request
  155.     );
  156.     $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_PRODUCT_INDEX_INITIALIZE);
  157.     /* @var $searchForm \Symfony\Component\Form\FormInterface */
  158.     $searchForm $builder->getForm();
  159.     $searchForm->handleRequest($request);
  160.     // paginator
  161.     $searchData $searchForm->getData();
  162.     $qb $this->productRepository->getQueryBuilderBySearchData($searchData);
  163.     $event = new EventArgs(
  164.       [
  165.         'searchData' => $searchData,
  166.         'qb' => $qb,
  167.       ],
  168.       $request
  169.     );
  170.     $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_PRODUCT_INDEX_SEARCH);
  171.     $searchData $event->getArgument('searchData');
  172.     $query $qb->getQuery()
  173.       ->useResultCache(true$this->eccubeConfig['eccube_result_cache_lifetime_short']);
  174.     /** @var SlidingPagination $pagination */
  175.     $pagination $paginator->paginate(
  176.       $query,
  177.       !empty($searchData['pageno']) ? $searchData['pageno'] : 1,
  178.       !empty($searchData['disp_number']) ? $searchData['disp_number']->getId() : $this->productListMaxRepository->findOneBy([], ['sort_no' => 'ASC'])->getId()
  179.     );
  180.     $ids = [];
  181.     foreach ($pagination as $Product) {
  182.       $ids[] = $Product->getId();
  183.     }
  184.     $ProductsAndClassCategories $this->productRepository->findProductsWithSortedClassCategories($ids'p.id');
  185.     // addCart form
  186.     $forms = [];
  187.     foreach ($pagination as $Product) {
  188.       /* @var $builder \Symfony\Component\Form\FormBuilderInterface */
  189.       $builder $this->formFactory->createNamedBuilder(
  190.         '',
  191.         AddCartType::class,
  192.         null,
  193.         [
  194.           'product' => $ProductsAndClassCategories[$Product->getId()],
  195.           'allow_extra_fields' => true,
  196.         ]
  197.       );
  198.       $addCartForm $builder->getForm();
  199.       $forms[$Product->getId()] = $addCartForm->createView();
  200.     }
  201.     $Category $searchForm->get('category_id')->getData();
  202.     $category_id = empty($_GET["category_id"]) ? "" intval($_GET["category_id"]);
  203.     return [
  204.       'subtitle' => $this->getPageTitle($searchData),
  205.       'pagination' => $pagination,
  206.       'search_form' => $searchForm->createView(),
  207.       'forms' => $forms,
  208.       'Category' => $Category,
  209.         'category_id' => $category_id,
  210.     ];
  211.   }
  212.   /**
  213.    * 商品詳細画面.
  214.    *
  215.    * @Route("/products/detail/{id}", name="product_detail", methods={"GET"}, requirements={"id" = "\d+"})
  216.    * @Template("Product/detail.twig")
  217.    * @ParamConverter("Product", options={"repository_method" = "findWithSortedClassCategories"})
  218.    *
  219.    * @param Request $request
  220.    * @param Product $Product
  221.    *
  222.    * @return array
  223.    */
  224.   public function detail(Request $requestProduct $Product)
  225.   {
  226.     $this->session->set('header_footer_layout'"palace");
  227.     if (!$this->checkVisibility($Product)) {
  228.       throw new NotFoundHttpException();
  229.     }
  230.     // ============================================================
  231.     // 限定公開URLチェック(column_id: 66)
  232.     // ============================================================
  233.     $product_id $Product->getId();
  234.     $genteiValue $this->productDataDetailRepository->getObjectFromProductId($product_id"66");
  235.     if (!empty($genteiValue)) {
  236.       $d_id $request->query->get('d_id');
  237.       if (empty($d_id) || $d_id !== $genteiValue) {
  238.         // d_idパラメータがない、または不一致の場合は404
  239.         throw new NotFoundHttpException();
  240.       }
  241.     }
  242.     $builder $this->formFactory->createNamedBuilder(
  243.       '',
  244.       AddCartType::class,
  245.       null,
  246.       [
  247.         'product' => $Product,
  248.         'id_add_product_id' => false,
  249.       ]
  250.     );
  251.     $event = new EventArgs(
  252.       [
  253.         'builder' => $builder,
  254.         'Product' => $Product,
  255.       ],
  256.       $request
  257.     );
  258.     $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_PRODUCT_DETAIL_INITIALIZE);
  259.     $is_favorite false;
  260.     if ($this->isGranted('ROLE_USER')) {
  261.       $Customer $this->getUser();
  262.       $is_favorite $this->customerFavoriteProductRepository->isFavorite($Customer$Product);
  263.     }
  264.     // 商品種別を取得
  265.     $ProductClasses $Product->getProductClasses();
  266.     $product_type_id "";
  267.     foreach ($ProductClasses as $class) {
  268.       $type $class->getSaleType();
  269.       $product_type_id $type->getId();
  270.     }
  271.     // 商品の拡張項目を取得
  272.     $product_id $Product->getId();
  273.     $htEx $this->productDataDetailRepository->getHashFromProductId($product_id);
  274.     // 地金カテゴリーの確認
  275.     $jigane_flg $this->categoryRepository->hasCategory($product_id"5");
  276.     // 会員価格を表示
  277.     $member_price $this->customerPriceRepository->getPriceFromProductId($product_id);
  278.     // 再入荷通知情報を取得
  279.     $restock $this->productRestockRepository->findByProductId($product_id);
  280.     $restock_disp_flg $restock $restock->getDispFlg() : 0;
  281.     // 在庫がある場合は再入荷ボタンを非表示
  282.     $stock 0;
  283.     foreach ($Product->getProductClasses() as $productClass) {
  284.       if ($productClass->isVisible()) {
  285.         $stock += $productClass->getStock();
  286.       }
  287.     }
  288.     if ($stock 0) {
  289.       $restock_disp_flg 0;
  290.     }
  291.     // ログインユーザーの再入荷登録状況
  292.     $restock_regist_flg 2// 未登録
  293.     if ($this->isGranted('ROLE_USER') && $restock) {
  294.       $customer $this->getUser();
  295.       $isRegistered $this->productRestockCustomerRepository->isRegistered(
  296.         $restock->getId(),
  297.         $customer->getId()
  298.       );
  299.       $restock_regist_flg $isRegistered 2;
  300.     }
  301.     return [
  302.       'title' => $this->title,
  303.       'subtitle' => $Product->getName(),
  304.       'form' => $builder->getForm()->createView(),
  305.       'Product' => $Product,
  306.       'is_favorite' => $is_favorite,
  307.       'product_type_id' => $product_type_id,
  308.       'htEx' => $htEx,
  309.       'jigane_flg' => $jigane_flg,
  310.       'member_price' => $member_price,
  311.       'restock_disp_flg' => $restock_disp_flg,
  312.       'restock_regist_flg' => $restock_regist_flg,
  313.     ];
  314.   }
  315.   /**
  316.    * お気に入り追加.
  317.    *
  318.    * @Route("/products/add_favorite/{id}", name="product_add_favorite", requirements={"id" = "\d+"}, methods={"GET", "POST"})
  319.    */
  320.   public function addFavorite(Request $requestProduct $Product)
  321.   {
  322.     $this->checkVisibility($Product);
  323.     $event = new EventArgs(
  324.       [
  325.         'Product' => $Product,
  326.       ],
  327.       $request
  328.     );
  329.     $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_INITIALIZE);
  330.     if ($this->isGranted('ROLE_USER')) {
  331.       $Customer $this->getUser();
  332.       $this->customerFavoriteProductRepository->addFavorite($Customer$Product);
  333.       $this->session->getFlashBag()->set('product_detail.just_added_favorite'$Product->getId());
  334.       $event = new EventArgs(
  335.         [
  336.           'Product' => $Product,
  337.         ],
  338.         $request
  339.       );
  340.       $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE);
  341.       // パレスとプラザの戻り先を変更
  342.       $product_id $Product->getId();
  343.       $productClasses $Product->getProductClasses();
  344.       $plaza_flg false;
  345.       foreach($productClasses as $ProductClass) {
  346.         $sale_type_id $ProductClass->getSaleType()->getId();
  347.         if($sale_type_id == "2"){
  348.           $plaza_flg true;
  349.         }
  350.       }
  351.       if($plaza_flg === true){
  352.         return $this->redirectToRoute('plaza_product_detail', ['id' => $product_id]);
  353.       }else{
  354.         return $this->redirectToRoute('product_detail', ['id' => $product_id]);
  355.       }
  356.     } else {
  357.       // 非会員の場合、ログイン画面を表示
  358.       //  ログイン後の画面遷移先を設定
  359.       $this->setLoginTargetPath($this->generateUrl('product_add_favorite', ['id' => $Product->getId()], UrlGeneratorInterface::ABSOLUTE_URL));
  360.       $this->session->getFlashBag()->set('eccube.add.favorite'true);
  361.       $event = new EventArgs(
  362.         [
  363.           'Product' => $Product,
  364.         ],
  365.         $request
  366.       );
  367.       $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_PRODUCT_FAVORITE_ADD_COMPLETE);
  368.       return $this->redirectToRoute('mypage_login');
  369.     }
  370.   }
  371.   /**
  372.    * カートに追加.
  373.    *
  374.    * @Route("/products/add_cart/{id}", name="product_add_cart", methods={"POST"}, requirements={"id" = "\d+"})
  375.    */
  376.   public function addCart(Request $requestProduct $Product)
  377.   {
  378.     // エラーメッセージの配列
  379.     $errorMessages = [];
  380.     if (!$this->checkVisibility($Product)) {
  381.       throw new NotFoundHttpException();
  382.     }
  383.     $builder $this->formFactory->createNamedBuilder(
  384.       '',
  385.       AddCartType::class,
  386.       null,
  387.       [
  388.         'product' => $Product,
  389.         'id_add_product_id' => false,
  390.       ]
  391.     );
  392.     $event = new EventArgs(
  393.       [
  394.         'builder' => $builder,
  395.         'Product' => $Product,
  396.       ],
  397.       $request
  398.     );
  399.     $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_PRODUCT_CART_ADD_INITIALIZE);
  400.     /* @var $form \Symfony\Component\Form\FormInterface */
  401.     $form $builder->getForm();
  402.     $form->handleRequest($request);
  403.     if (!$form->isValid()) {
  404.       throw new NotFoundHttpException();
  405.     }
  406.     $addCartData $form->getData();
  407.     log_info(
  408.       'カート追加処理開始',
  409.       [
  410.         'product_id' => $Product->getId(),
  411.         'product_class_id' => $addCartData['product_class_id'],
  412.         'quantity' => $addCartData['quantity'],
  413.       ]
  414.     );
  415.     // オーナーチェック
  416.     if ($this->isGranted('ROLE_USER')) {
  417.       $product_id $Product->getId();
  418.       $owner_id $this->productDataDetailRepository->getObjectFromProductId($product_id"6");
  419.       $user_id $this->getUser()->getId();
  420.       if($owner_id == $user_id){
  421.         $this->addRequestError("お客様が出品中のコインは購入する事が出来ません。");
  422.         return $this->redirectToRoute('cart');
  423.       }
  424.     }
  425.     // カートへ追加
  426.     $this->cartService->addProduct($addCartData['product_class_id'], $addCartData['quantity']);
  427.     // 明細の正規化
  428.     $Carts $this->cartService->getCarts();
  429.     // 同時購入できない商品がある場合
  430.     if(count($Carts) >= 2){
  431.       $product_id $Product->getId();
  432.       foreach ($Carts as $Cart) {
  433.         foreach ($Cart->getCartItems() as $CartItem) {
  434.           $ProductClass $CartItem->getProductClass();
  435.           $NewProduct $ProductClass->getProduct();
  436.           $new_product_id $NewProduct->getId();
  437.           if($new_product_id != $product_id){
  438.             $this->cartService->removeProduct($ProductClass);
  439.           }
  440.         }
  441.       }
  442.     }
  443.     $Carts $this->cartService->getCarts();
  444.     foreach ($Carts as $Cart) {
  445.       $result $this->purchaseFlow->validate($Cart, new PurchaseContext($Cart$this->getUser()));
  446.       // 復旧不可のエラーが発生した場合は追加した明細を削除.
  447.       if ($result->hasError()) {
  448.         $this->cartService->removeProduct($addCartData['product_class_id']);
  449.         foreach ($result->getErrors() as $error) {
  450.           $errorMessages[] = $error->getMessage();
  451.         }
  452.       }
  453.       foreach ($result->getWarning() as $warning) {
  454.         $errorMessages[] = $warning->getMessage();
  455.       }
  456.     }
  457.     $this->cartService->save();
  458.     log_info(
  459.       'カート追加処理完了',
  460.       [
  461.         'product_id' => $Product->getId(),
  462.         'product_class_id' => $addCartData['product_class_id'],
  463.         'quantity' => $addCartData['quantity'],
  464.       ]
  465.     );
  466.     $event = new EventArgs(
  467.       [
  468.         'form' => $form,
  469.         'Product' => $Product,
  470.       ],
  471.       $request
  472.     );
  473.     $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_PRODUCT_CART_ADD_COMPLETE);
  474.     if ($event->getResponse() !== null) {
  475.       return $event->getResponse();
  476.     }
  477.     if ($request->isXmlHttpRequest()) {
  478.       // ajaxでのリクエストの場合は結果をjson形式で返す。
  479.       // 初期化
  480.       $messages = [];
  481.       if (empty($errorMessages)) {
  482.         // エラーが発生していない場合
  483.         $done true;
  484.         array_push($messagestrans('front.product.add_cart_complete'));
  485.       } else {
  486.         // エラーが発生している場合
  487.         $done false;
  488.         $messages $errorMessages;
  489.       }
  490.       return $this->json(['done' => $done'messages' => $messages]);
  491.     } else {
  492.       // ajax以外でのリクエストの場合はカート画面へリダイレクト
  493.       foreach ($errorMessages as $errorMessage) {
  494.         $this->addRequestError($errorMessage);
  495.       }
  496.       return $this->redirectToRoute('cart');
  497.     }
  498.   }
  499.   /**
  500.    * ページタイトルの設定
  501.    *
  502.    * @param array|null $searchData
  503.    *
  504.    * @return str
  505.    */
  506.   protected function getPageTitle($searchData)
  507.   {
  508.     if (isset($searchData['name']) && !empty($searchData['name'])) {
  509.       return trans('front.product.search_result');
  510.     } elseif (isset($searchData['category_id']) && $searchData['category_id']) {
  511.       return $searchData['category_id']->getName();
  512.     } else {
  513.       return trans('front.product.all_products');
  514.     }
  515.   }
  516.   /**
  517.    * 閲覧可能な商品かどうかを判定
  518.    *
  519.    * @param Product $Product
  520.    *
  521.    * @return boolean 閲覧可能な場合はtrue
  522.    */
  523.   protected function checkVisibility(Product $Product)
  524.   {
  525.     $is_admin $this->session->has('_security_admin');
  526.     // 管理ユーザの場合はステータスやオプションにかかわらず閲覧可能.
  527.     if (!$is_admin) {
  528.       // 削除済み商品は表示しない
  529.       if ($Product->getDelFlg() === 1) {
  530.         return false;
  531.       }
  532.       // 在庫なし商品の非表示オプションが有効な場合.
  533.       // if ($this->BaseInfo->isOptionNostockHidden()) {
  534.       //     if (!$Product->getStockFind()) {
  535.       //         return false;
  536.       //     }
  537.       // }
  538.       // 表示可能なステータス: 1(公開), 6(取り置き), 8(予約品)
  539.       $statusId $Product->getStatus()->getId();
  540.       if (!in_array($statusId, [
  541.         ProductStatus::DISPLAY_SHOW,  // 1: 公開
  542.         6,  // 取り置き(公開)
  543.         8,  // 予約品(公開)
  544.       ])) {
  545.         return false;
  546.       }
  547.     }
  548.     return true;
  549.   }
  550. }