app/Customize/Controller/ProductController.php line 170

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